xref: /OK3568_Linux_fs/kernel/drivers/edac/edac_device_sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * file for managing the edac_device subsystem of devices for EDAC
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) 2007 SoftwareBitMaker
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This file may be distributed under the terms of the
7*4882a593Smuzhiyun  * GNU General Public License.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Written Doug Thompson <norsk5@xmission.com>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/ctype.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/edac.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "edac_device.h"
19*4882a593Smuzhiyun #include "edac_module.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define EDAC_DEVICE_SYMLINK	"device"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
24*4882a593Smuzhiyun #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * Set of edac_device_ctl_info attribute store/show functions
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* 'log_ue' */
edac_device_ctl_log_ue_show(struct edac_device_ctl_info * ctl_info,char * data)32*4882a593Smuzhiyun static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
33*4882a593Smuzhiyun 					*ctl_info, char *data)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	return sprintf(data, "%u\n", ctl_info->log_ue);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
edac_device_ctl_log_ue_store(struct edac_device_ctl_info * ctl_info,const char * data,size_t count)38*4882a593Smuzhiyun static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
39*4882a593Smuzhiyun 					*ctl_info, const char *data,
40*4882a593Smuzhiyun 					size_t count)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	/* if parameter is zero, turn off flag, if non-zero turn on flag */
43*4882a593Smuzhiyun 	ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	return count;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* 'log_ce' */
edac_device_ctl_log_ce_show(struct edac_device_ctl_info * ctl_info,char * data)49*4882a593Smuzhiyun static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
50*4882a593Smuzhiyun 					*ctl_info, char *data)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	return sprintf(data, "%u\n", ctl_info->log_ce);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
edac_device_ctl_log_ce_store(struct edac_device_ctl_info * ctl_info,const char * data,size_t count)55*4882a593Smuzhiyun static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
56*4882a593Smuzhiyun 					*ctl_info, const char *data,
57*4882a593Smuzhiyun 					size_t count)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	/* if parameter is zero, turn off flag, if non-zero turn on flag */
60*4882a593Smuzhiyun 	ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return count;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* 'panic_on_ue' */
edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info * ctl_info,char * data)66*4882a593Smuzhiyun static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
67*4882a593Smuzhiyun 						*ctl_info, char *data)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	return sprintf(data, "%u\n", ctl_info->panic_on_ue);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info * ctl_info,const char * data,size_t count)72*4882a593Smuzhiyun static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
73*4882a593Smuzhiyun 						 *ctl_info, const char *data,
74*4882a593Smuzhiyun 						 size_t count)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	/* if parameter is zero, turn off flag, if non-zero turn on flag */
77*4882a593Smuzhiyun 	ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	return count;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun /* 'poll_msec' show and store functions*/
edac_device_ctl_poll_msec_show(struct edac_device_ctl_info * ctl_info,char * data)83*4882a593Smuzhiyun static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
84*4882a593Smuzhiyun 					*ctl_info, char *data)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	return sprintf(data, "%u\n", ctl_info->poll_msec);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
edac_device_ctl_poll_msec_store(struct edac_device_ctl_info * ctl_info,const char * data,size_t count)89*4882a593Smuzhiyun static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
90*4882a593Smuzhiyun 					*ctl_info, const char *data,
91*4882a593Smuzhiyun 					size_t count)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	unsigned long value;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/* get the value and enforce that it is non-zero, must be at least
96*4882a593Smuzhiyun 	 * one millisecond for the delay period, between scans
97*4882a593Smuzhiyun 	 * Then cancel last outstanding delay for the work request
98*4882a593Smuzhiyun 	 * and set a new one.
99*4882a593Smuzhiyun 	 */
100*4882a593Smuzhiyun 	value = simple_strtoul(data, NULL, 0);
101*4882a593Smuzhiyun 	edac_device_reset_delay_period(ctl_info, value);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return count;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* edac_device_ctl_info specific attribute structure */
107*4882a593Smuzhiyun struct ctl_info_attribute {
108*4882a593Smuzhiyun 	struct attribute attr;
109*4882a593Smuzhiyun 	ssize_t(*show) (struct edac_device_ctl_info *, char *);
110*4882a593Smuzhiyun 	ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
114*4882a593Smuzhiyun #define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun /* Function to 'show' fields from the edac_dev 'ctl_info' structure */
edac_dev_ctl_info_show(struct kobject * kobj,struct attribute * attr,char * buffer)117*4882a593Smuzhiyun static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
118*4882a593Smuzhiyun 				struct attribute *attr, char *buffer)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
121*4882a593Smuzhiyun 	struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (ctl_info_attr->show)
124*4882a593Smuzhiyun 		return ctl_info_attr->show(edac_dev, buffer);
125*4882a593Smuzhiyun 	return -EIO;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /* Function to 'store' fields into the edac_dev 'ctl_info' structure */
edac_dev_ctl_info_store(struct kobject * kobj,struct attribute * attr,const char * buffer,size_t count)129*4882a593Smuzhiyun static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
130*4882a593Smuzhiyun 				struct attribute *attr,
131*4882a593Smuzhiyun 				const char *buffer, size_t count)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
134*4882a593Smuzhiyun 	struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (ctl_info_attr->store)
137*4882a593Smuzhiyun 		return ctl_info_attr->store(edac_dev, buffer, count);
138*4882a593Smuzhiyun 	return -EIO;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun /* edac_dev file operations for an 'ctl_info' */
142*4882a593Smuzhiyun static const struct sysfs_ops device_ctl_info_ops = {
143*4882a593Smuzhiyun 	.show = edac_dev_ctl_info_show,
144*4882a593Smuzhiyun 	.store = edac_dev_ctl_info_store
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun #define CTL_INFO_ATTR(_name,_mode,_show,_store)        \
148*4882a593Smuzhiyun static struct ctl_info_attribute attr_ctl_info_##_name = {      \
149*4882a593Smuzhiyun 	.attr = {.name = __stringify(_name), .mode = _mode },   \
150*4882a593Smuzhiyun 	.show   = _show,                                        \
151*4882a593Smuzhiyun 	.store  = _store,                                       \
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun /* Declare the various ctl_info attributes here and their respective ops */
155*4882a593Smuzhiyun CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
156*4882a593Smuzhiyun 	edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
157*4882a593Smuzhiyun CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
158*4882a593Smuzhiyun 	edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
159*4882a593Smuzhiyun CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
160*4882a593Smuzhiyun 	edac_device_ctl_panic_on_ue_show,
161*4882a593Smuzhiyun 	edac_device_ctl_panic_on_ue_store);
162*4882a593Smuzhiyun CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
163*4882a593Smuzhiyun 	edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /* Base Attributes of the EDAC_DEVICE ECC object */
166*4882a593Smuzhiyun static struct ctl_info_attribute *device_ctrl_attr[] = {
167*4882a593Smuzhiyun 	&attr_ctl_info_panic_on_ue,
168*4882a593Smuzhiyun 	&attr_ctl_info_log_ue,
169*4882a593Smuzhiyun 	&attr_ctl_info_log_ce,
170*4882a593Smuzhiyun 	&attr_ctl_info_poll_msec,
171*4882a593Smuzhiyun 	NULL,
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /*
175*4882a593Smuzhiyun  * edac_device_ctrl_master_release
176*4882a593Smuzhiyun  *
177*4882a593Smuzhiyun  *	called when the reference count for the 'main' kobj
178*4882a593Smuzhiyun  *	for a edac_device control struct reaches zero
179*4882a593Smuzhiyun  *
180*4882a593Smuzhiyun  *	Reference count model:
181*4882a593Smuzhiyun  *		One 'main' kobject for each control structure allocated.
182*4882a593Smuzhiyun  *		That main kobj is initially set to one AND
183*4882a593Smuzhiyun  *		the reference count for the EDAC 'core' module is
184*4882a593Smuzhiyun  *		bumped by one, thus added 'keep in memory' dependency.
185*4882a593Smuzhiyun  *
186*4882a593Smuzhiyun  *		Each new internal kobj (in instances and blocks) then
187*4882a593Smuzhiyun  *		bumps the 'main' kobject.
188*4882a593Smuzhiyun  *
189*4882a593Smuzhiyun  *		When they are released their release functions decrement
190*4882a593Smuzhiyun  *		the 'main' kobj.
191*4882a593Smuzhiyun  *
192*4882a593Smuzhiyun  *		When the main kobj reaches zero (0) then THIS function
193*4882a593Smuzhiyun  *		is called which then decrements the EDAC 'core' module.
194*4882a593Smuzhiyun  *		When the module reference count reaches zero then the
195*4882a593Smuzhiyun  *		module no longer has dependency on keeping the release
196*4882a593Smuzhiyun  *		function code in memory and module can be unloaded.
197*4882a593Smuzhiyun  *
198*4882a593Smuzhiyun  *		This will support several control objects as well, each
199*4882a593Smuzhiyun  *		with its own 'main' kobj.
200*4882a593Smuzhiyun  */
edac_device_ctrl_master_release(struct kobject * kobj)201*4882a593Smuzhiyun static void edac_device_ctrl_master_release(struct kobject *kobj)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	edac_dbg(4, "control index=%d\n", edac_dev->dev_idx);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	/* decrement the EDAC CORE module ref count */
208*4882a593Smuzhiyun 	module_put(edac_dev->owner);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* free the control struct containing the 'main' kobj
211*4882a593Smuzhiyun 	 * passed in to this routine
212*4882a593Smuzhiyun 	 */
213*4882a593Smuzhiyun 	kfree(edac_dev);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /* ktype for the main (master) kobject */
217*4882a593Smuzhiyun static struct kobj_type ktype_device_ctrl = {
218*4882a593Smuzhiyun 	.release = edac_device_ctrl_master_release,
219*4882a593Smuzhiyun 	.sysfs_ops = &device_ctl_info_ops,
220*4882a593Smuzhiyun 	.default_attrs = (struct attribute **)device_ctrl_attr,
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun  * edac_device_register_sysfs_main_kobj
225*4882a593Smuzhiyun  *
226*4882a593Smuzhiyun  *	perform the high level setup for the new edac_device instance
227*4882a593Smuzhiyun  *
228*4882a593Smuzhiyun  * Return:  0 SUCCESS
229*4882a593Smuzhiyun  *         !0 FAILURE
230*4882a593Smuzhiyun  */
edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info * edac_dev)231*4882a593Smuzhiyun int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct bus_type *edac_subsys;
234*4882a593Smuzhiyun 	int err;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	edac_dbg(1, "\n");
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/* get the /sys/devices/system/edac reference */
239*4882a593Smuzhiyun 	edac_subsys = edac_get_sysfs_subsys();
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* Point to the 'edac_subsys' this instance 'reports' to */
242*4882a593Smuzhiyun 	edac_dev->edac_subsys = edac_subsys;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	/* Init the devices's kobject */
245*4882a593Smuzhiyun 	memset(&edac_dev->kobj, 0, sizeof(struct kobject));
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* Record which module 'owns' this control structure
248*4882a593Smuzhiyun 	 * and bump the ref count of the module
249*4882a593Smuzhiyun 	 */
250*4882a593Smuzhiyun 	edac_dev->owner = THIS_MODULE;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (!try_module_get(edac_dev->owner)) {
253*4882a593Smuzhiyun 		err = -ENODEV;
254*4882a593Smuzhiyun 		goto err_out;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* register */
258*4882a593Smuzhiyun 	err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
259*4882a593Smuzhiyun 				   &edac_subsys->dev_root->kobj,
260*4882a593Smuzhiyun 				   "%s", edac_dev->name);
261*4882a593Smuzhiyun 	if (err) {
262*4882a593Smuzhiyun 		edac_dbg(1, "Failed to register '.../edac/%s'\n",
263*4882a593Smuzhiyun 			 edac_dev->name);
264*4882a593Smuzhiyun 		goto err_kobj_reg;
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 	kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* At this point, to 'free' the control struct,
269*4882a593Smuzhiyun 	 * edac_device_unregister_sysfs_main_kobj() must be used
270*4882a593Smuzhiyun 	 */
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	edac_dbg(4, "Registered '.../edac/%s' kobject\n", edac_dev->name);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return 0;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	/* Error exit stack */
277*4882a593Smuzhiyun err_kobj_reg:
278*4882a593Smuzhiyun 	kobject_put(&edac_dev->kobj);
279*4882a593Smuzhiyun 	module_put(edac_dev->owner);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun err_out:
282*4882a593Smuzhiyun 	return err;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /*
286*4882a593Smuzhiyun  * edac_device_unregister_sysfs_main_kobj:
287*4882a593Smuzhiyun  *	the '..../edac/<name>' kobject
288*4882a593Smuzhiyun  */
edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info * dev)289*4882a593Smuzhiyun void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	edac_dbg(0, "\n");
292*4882a593Smuzhiyun 	edac_dbg(4, "name of kobject is: %s\n", kobject_name(&dev->kobj));
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/*
295*4882a593Smuzhiyun 	 * Unregister the edac device's kobject and
296*4882a593Smuzhiyun 	 * allow for reference count to reach 0 at which point
297*4882a593Smuzhiyun 	 * the callback will be called to:
298*4882a593Smuzhiyun 	 *   a) module_put() this module
299*4882a593Smuzhiyun 	 *   b) 'kfree' the memory
300*4882a593Smuzhiyun 	 */
301*4882a593Smuzhiyun 	kobject_put(&dev->kobj);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun /* edac_dev -> instance information */
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun  * Set of low-level instance attribute show functions
308*4882a593Smuzhiyun  */
instance_ue_count_show(struct edac_device_instance * instance,char * data)309*4882a593Smuzhiyun static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
310*4882a593Smuzhiyun 				char *data)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	return sprintf(data, "%u\n", instance->counters.ue_count);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
instance_ce_count_show(struct edac_device_instance * instance,char * data)315*4882a593Smuzhiyun static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
316*4882a593Smuzhiyun 				char *data)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	return sprintf(data, "%u\n", instance->counters.ce_count);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun #define to_instance(k) container_of(k, struct edac_device_instance, kobj)
322*4882a593Smuzhiyun #define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun /* DEVICE instance kobject release() function */
edac_device_ctrl_instance_release(struct kobject * kobj)325*4882a593Smuzhiyun static void edac_device_ctrl_instance_release(struct kobject *kobj)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	struct edac_device_instance *instance;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	edac_dbg(1, "\n");
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* map from this kobj to the main control struct
332*4882a593Smuzhiyun 	 * and then dec the main kobj count
333*4882a593Smuzhiyun 	 */
334*4882a593Smuzhiyun 	instance = to_instance(kobj);
335*4882a593Smuzhiyun 	kobject_put(&instance->ctl->kobj);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun /* instance specific attribute structure */
339*4882a593Smuzhiyun struct instance_attribute {
340*4882a593Smuzhiyun 	struct attribute attr;
341*4882a593Smuzhiyun 	ssize_t(*show) (struct edac_device_instance *, char *);
342*4882a593Smuzhiyun 	ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
343*4882a593Smuzhiyun };
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun /* Function to 'show' fields from the edac_dev 'instance' structure */
edac_dev_instance_show(struct kobject * kobj,struct attribute * attr,char * buffer)346*4882a593Smuzhiyun static ssize_t edac_dev_instance_show(struct kobject *kobj,
347*4882a593Smuzhiyun 				struct attribute *attr, char *buffer)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	struct edac_device_instance *instance = to_instance(kobj);
350*4882a593Smuzhiyun 	struct instance_attribute *instance_attr = to_instance_attr(attr);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	if (instance_attr->show)
353*4882a593Smuzhiyun 		return instance_attr->show(instance, buffer);
354*4882a593Smuzhiyun 	return -EIO;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun /* Function to 'store' fields into the edac_dev 'instance' structure */
edac_dev_instance_store(struct kobject * kobj,struct attribute * attr,const char * buffer,size_t count)358*4882a593Smuzhiyun static ssize_t edac_dev_instance_store(struct kobject *kobj,
359*4882a593Smuzhiyun 				struct attribute *attr,
360*4882a593Smuzhiyun 				const char *buffer, size_t count)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	struct edac_device_instance *instance = to_instance(kobj);
363*4882a593Smuzhiyun 	struct instance_attribute *instance_attr = to_instance_attr(attr);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	if (instance_attr->store)
366*4882a593Smuzhiyun 		return instance_attr->store(instance, buffer, count);
367*4882a593Smuzhiyun 	return -EIO;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun /* edac_dev file operations for an 'instance' */
371*4882a593Smuzhiyun static const struct sysfs_ops device_instance_ops = {
372*4882a593Smuzhiyun 	.show = edac_dev_instance_show,
373*4882a593Smuzhiyun 	.store = edac_dev_instance_store
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun #define INSTANCE_ATTR(_name,_mode,_show,_store)        \
377*4882a593Smuzhiyun static struct instance_attribute attr_instance_##_name = {      \
378*4882a593Smuzhiyun 	.attr = {.name = __stringify(_name), .mode = _mode },   \
379*4882a593Smuzhiyun 	.show   = _show,                                        \
380*4882a593Smuzhiyun 	.store  = _store,                                       \
381*4882a593Smuzhiyun };
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /*
384*4882a593Smuzhiyun  * Define attributes visible for the edac_device instance object
385*4882a593Smuzhiyun  *	Each contains a pointer to a show and an optional set
386*4882a593Smuzhiyun  *	function pointer that does the low level output/input
387*4882a593Smuzhiyun  */
388*4882a593Smuzhiyun INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
389*4882a593Smuzhiyun INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun /* list of edac_dev 'instance' attributes */
392*4882a593Smuzhiyun static struct instance_attribute *device_instance_attr[] = {
393*4882a593Smuzhiyun 	&attr_instance_ce_count,
394*4882a593Smuzhiyun 	&attr_instance_ue_count,
395*4882a593Smuzhiyun 	NULL,
396*4882a593Smuzhiyun };
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun /* The 'ktype' for each edac_dev 'instance' */
399*4882a593Smuzhiyun static struct kobj_type ktype_instance_ctrl = {
400*4882a593Smuzhiyun 	.release = edac_device_ctrl_instance_release,
401*4882a593Smuzhiyun 	.sysfs_ops = &device_instance_ops,
402*4882a593Smuzhiyun 	.default_attrs = (struct attribute **)device_instance_attr,
403*4882a593Smuzhiyun };
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun /* edac_dev -> instance -> block information */
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun #define to_block(k) container_of(k, struct edac_device_block, kobj)
408*4882a593Smuzhiyun #define to_block_attr(a) \
409*4882a593Smuzhiyun 	container_of(a, struct edac_dev_sysfs_block_attribute, attr)
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun /*
412*4882a593Smuzhiyun  * Set of low-level block attribute show functions
413*4882a593Smuzhiyun  */
block_ue_count_show(struct kobject * kobj,struct attribute * attr,char * data)414*4882a593Smuzhiyun static ssize_t block_ue_count_show(struct kobject *kobj,
415*4882a593Smuzhiyun 					struct attribute *attr, char *data)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct edac_device_block *block = to_block(kobj);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	return sprintf(data, "%u\n", block->counters.ue_count);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
block_ce_count_show(struct kobject * kobj,struct attribute * attr,char * data)422*4882a593Smuzhiyun static ssize_t block_ce_count_show(struct kobject *kobj,
423*4882a593Smuzhiyun 					struct attribute *attr, char *data)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	struct edac_device_block *block = to_block(kobj);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	return sprintf(data, "%u\n", block->counters.ce_count);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun /* DEVICE block kobject release() function */
edac_device_ctrl_block_release(struct kobject * kobj)431*4882a593Smuzhiyun static void edac_device_ctrl_block_release(struct kobject *kobj)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	struct edac_device_block *block;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	edac_dbg(1, "\n");
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	/* get the container of the kobj */
438*4882a593Smuzhiyun 	block = to_block(kobj);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/* map from 'block kobj' to 'block->instance->controller->main_kobj'
441*4882a593Smuzhiyun 	 * now 'release' the block kobject
442*4882a593Smuzhiyun 	 */
443*4882a593Smuzhiyun 	kobject_put(&block->instance->ctl->kobj);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun /* Function to 'show' fields from the edac_dev 'block' structure */
edac_dev_block_show(struct kobject * kobj,struct attribute * attr,char * buffer)448*4882a593Smuzhiyun static ssize_t edac_dev_block_show(struct kobject *kobj,
449*4882a593Smuzhiyun 				struct attribute *attr, char *buffer)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	struct edac_dev_sysfs_block_attribute *block_attr =
452*4882a593Smuzhiyun 						to_block_attr(attr);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (block_attr->show)
455*4882a593Smuzhiyun 		return block_attr->show(kobj, attr, buffer);
456*4882a593Smuzhiyun 	return -EIO;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun /* Function to 'store' fields into the edac_dev 'block' structure */
edac_dev_block_store(struct kobject * kobj,struct attribute * attr,const char * buffer,size_t count)460*4882a593Smuzhiyun static ssize_t edac_dev_block_store(struct kobject *kobj,
461*4882a593Smuzhiyun 				struct attribute *attr,
462*4882a593Smuzhiyun 				const char *buffer, size_t count)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun 	struct edac_dev_sysfs_block_attribute *block_attr;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	block_attr = to_block_attr(attr);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (block_attr->store)
469*4882a593Smuzhiyun 		return block_attr->store(kobj, attr, buffer, count);
470*4882a593Smuzhiyun 	return -EIO;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun /* edac_dev file operations for a 'block' */
474*4882a593Smuzhiyun static const struct sysfs_ops device_block_ops = {
475*4882a593Smuzhiyun 	.show = edac_dev_block_show,
476*4882a593Smuzhiyun 	.store = edac_dev_block_store
477*4882a593Smuzhiyun };
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun #define BLOCK_ATTR(_name,_mode,_show,_store)        \
480*4882a593Smuzhiyun static struct edac_dev_sysfs_block_attribute attr_block_##_name = {	\
481*4882a593Smuzhiyun 	.attr = {.name = __stringify(_name), .mode = _mode },   \
482*4882a593Smuzhiyun 	.show   = _show,                                        \
483*4882a593Smuzhiyun 	.store  = _store,                                       \
484*4882a593Smuzhiyun };
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
487*4882a593Smuzhiyun BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun /* list of edac_dev 'block' attributes */
490*4882a593Smuzhiyun static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
491*4882a593Smuzhiyun 	&attr_block_ce_count,
492*4882a593Smuzhiyun 	&attr_block_ue_count,
493*4882a593Smuzhiyun 	NULL,
494*4882a593Smuzhiyun };
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun /* The 'ktype' for each edac_dev 'block' */
497*4882a593Smuzhiyun static struct kobj_type ktype_block_ctrl = {
498*4882a593Smuzhiyun 	.release = edac_device_ctrl_block_release,
499*4882a593Smuzhiyun 	.sysfs_ops = &device_block_ops,
500*4882a593Smuzhiyun 	.default_attrs = (struct attribute **)device_block_attr,
501*4882a593Smuzhiyun };
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun /* block ctor/dtor  code */
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun /*
506*4882a593Smuzhiyun  * edac_device_create_block
507*4882a593Smuzhiyun  */
edac_device_create_block(struct edac_device_ctl_info * edac_dev,struct edac_device_instance * instance,struct edac_device_block * block)508*4882a593Smuzhiyun static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
509*4882a593Smuzhiyun 				struct edac_device_instance *instance,
510*4882a593Smuzhiyun 				struct edac_device_block *block)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	int i;
513*4882a593Smuzhiyun 	int err;
514*4882a593Smuzhiyun 	struct edac_dev_sysfs_block_attribute *sysfs_attrib;
515*4882a593Smuzhiyun 	struct kobject *main_kobj;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	edac_dbg(4, "Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
518*4882a593Smuzhiyun 		 instance->name, instance, block->name, block);
519*4882a593Smuzhiyun 	edac_dbg(4, "block kobj=%p  block kobj->parent=%p\n",
520*4882a593Smuzhiyun 		 &block->kobj, &block->kobj.parent);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	/* init this block's kobject */
523*4882a593Smuzhiyun 	memset(&block->kobj, 0, sizeof(struct kobject));
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	/* bump the main kobject's reference count for this controller
526*4882a593Smuzhiyun 	 * and this instance is dependent on the main
527*4882a593Smuzhiyun 	 */
528*4882a593Smuzhiyun 	main_kobj = kobject_get(&edac_dev->kobj);
529*4882a593Smuzhiyun 	if (!main_kobj) {
530*4882a593Smuzhiyun 		err = -ENODEV;
531*4882a593Smuzhiyun 		goto err_out;
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	/* Add this block's kobject */
535*4882a593Smuzhiyun 	err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
536*4882a593Smuzhiyun 				   &instance->kobj,
537*4882a593Smuzhiyun 				   "%s", block->name);
538*4882a593Smuzhiyun 	if (err) {
539*4882a593Smuzhiyun 		edac_dbg(1, "Failed to register instance '%s'\n", block->name);
540*4882a593Smuzhiyun 		kobject_put(main_kobj);
541*4882a593Smuzhiyun 		err = -ENODEV;
542*4882a593Smuzhiyun 		goto err_out;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/* If there are driver level block attributes, then added them
546*4882a593Smuzhiyun 	 * to the block kobject
547*4882a593Smuzhiyun 	 */
548*4882a593Smuzhiyun 	sysfs_attrib = block->block_attributes;
549*4882a593Smuzhiyun 	if (sysfs_attrib && block->nr_attribs) {
550*4882a593Smuzhiyun 		for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 			edac_dbg(4, "creating block attrib='%s' attrib->%p to kobj=%p\n",
553*4882a593Smuzhiyun 				 sysfs_attrib->attr.name,
554*4882a593Smuzhiyun 				 sysfs_attrib, &block->kobj);
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 			/* Create each block_attribute file */
557*4882a593Smuzhiyun 			err = sysfs_create_file(&block->kobj,
558*4882a593Smuzhiyun 				&sysfs_attrib->attr);
559*4882a593Smuzhiyun 			if (err)
560*4882a593Smuzhiyun 				goto err_on_attrib;
561*4882a593Smuzhiyun 		}
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 	kobject_uevent(&block->kobj, KOBJ_ADD);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	return 0;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Error unwind stack */
568*4882a593Smuzhiyun err_on_attrib:
569*4882a593Smuzhiyun 	kobject_put(&block->kobj);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun err_out:
572*4882a593Smuzhiyun 	return err;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun  * edac_device_delete_block(edac_dev,block);
577*4882a593Smuzhiyun  */
edac_device_delete_block(struct edac_device_ctl_info * edac_dev,struct edac_device_block * block)578*4882a593Smuzhiyun static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
579*4882a593Smuzhiyun 				struct edac_device_block *block)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	struct edac_dev_sysfs_block_attribute *sysfs_attrib;
582*4882a593Smuzhiyun 	int i;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	/* if this block has 'attributes' then we need to iterate over the list
585*4882a593Smuzhiyun 	 * and 'remove' the attributes on this block
586*4882a593Smuzhiyun 	 */
587*4882a593Smuzhiyun 	sysfs_attrib = block->block_attributes;
588*4882a593Smuzhiyun 	if (sysfs_attrib && block->nr_attribs) {
589*4882a593Smuzhiyun 		for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 			/* remove each block_attrib file */
592*4882a593Smuzhiyun 			sysfs_remove_file(&block->kobj,
593*4882a593Smuzhiyun 				(struct attribute *) sysfs_attrib);
594*4882a593Smuzhiyun 		}
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* unregister this block's kobject, SEE:
598*4882a593Smuzhiyun 	 *	edac_device_ctrl_block_release() callback operation
599*4882a593Smuzhiyun 	 */
600*4882a593Smuzhiyun 	kobject_put(&block->kobj);
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun /* instance ctor/dtor code */
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun /*
606*4882a593Smuzhiyun  * edac_device_create_instance
607*4882a593Smuzhiyun  *	create just one instance of an edac_device 'instance'
608*4882a593Smuzhiyun  */
edac_device_create_instance(struct edac_device_ctl_info * edac_dev,int idx)609*4882a593Smuzhiyun static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
610*4882a593Smuzhiyun 				int idx)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	int i, j;
613*4882a593Smuzhiyun 	int err;
614*4882a593Smuzhiyun 	struct edac_device_instance *instance;
615*4882a593Smuzhiyun 	struct kobject *main_kobj;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	instance = &edac_dev->instances[idx];
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	/* Init the instance's kobject */
620*4882a593Smuzhiyun 	memset(&instance->kobj, 0, sizeof(struct kobject));
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	instance->ctl = edac_dev;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	/* bump the main kobject's reference count for this controller
625*4882a593Smuzhiyun 	 * and this instance is dependent on the main
626*4882a593Smuzhiyun 	 */
627*4882a593Smuzhiyun 	main_kobj = kobject_get(&edac_dev->kobj);
628*4882a593Smuzhiyun 	if (!main_kobj) {
629*4882a593Smuzhiyun 		err = -ENODEV;
630*4882a593Smuzhiyun 		goto err_out;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	/* Formally register this instance's kobject under the edac_device */
634*4882a593Smuzhiyun 	err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
635*4882a593Smuzhiyun 				   &edac_dev->kobj, "%s", instance->name);
636*4882a593Smuzhiyun 	if (err != 0) {
637*4882a593Smuzhiyun 		edac_dbg(2, "Failed to register instance '%s'\n",
638*4882a593Smuzhiyun 			 instance->name);
639*4882a593Smuzhiyun 		kobject_put(main_kobj);
640*4882a593Smuzhiyun 		goto err_out;
641*4882a593Smuzhiyun 	}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	edac_dbg(4, "now register '%d' blocks for instance %d\n",
644*4882a593Smuzhiyun 		 instance->nr_blocks, idx);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	/* register all blocks of this instance */
647*4882a593Smuzhiyun 	for (i = 0; i < instance->nr_blocks; i++) {
648*4882a593Smuzhiyun 		err = edac_device_create_block(edac_dev, instance,
649*4882a593Smuzhiyun 						&instance->blocks[i]);
650*4882a593Smuzhiyun 		if (err) {
651*4882a593Smuzhiyun 			/* If any fail, remove all previous ones */
652*4882a593Smuzhiyun 			for (j = 0; j < i; j++)
653*4882a593Smuzhiyun 				edac_device_delete_block(edac_dev,
654*4882a593Smuzhiyun 							&instance->blocks[j]);
655*4882a593Smuzhiyun 			goto err_release_instance_kobj;
656*4882a593Smuzhiyun 		}
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 	kobject_uevent(&instance->kobj, KOBJ_ADD);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	edac_dbg(4, "Registered instance %d '%s' kobject\n",
661*4882a593Smuzhiyun 		 idx, instance->name);
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	return 0;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	/* error unwind stack */
666*4882a593Smuzhiyun err_release_instance_kobj:
667*4882a593Smuzhiyun 	kobject_put(&instance->kobj);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun err_out:
670*4882a593Smuzhiyun 	return err;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun /*
674*4882a593Smuzhiyun  * edac_device_remove_instance
675*4882a593Smuzhiyun  *	remove an edac_device instance
676*4882a593Smuzhiyun  */
edac_device_delete_instance(struct edac_device_ctl_info * edac_dev,int idx)677*4882a593Smuzhiyun static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
678*4882a593Smuzhiyun 					int idx)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	struct edac_device_instance *instance;
681*4882a593Smuzhiyun 	int i;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	instance = &edac_dev->instances[idx];
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	/* unregister all blocks in this instance */
686*4882a593Smuzhiyun 	for (i = 0; i < instance->nr_blocks; i++)
687*4882a593Smuzhiyun 		edac_device_delete_block(edac_dev, &instance->blocks[i]);
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	/* unregister this instance's kobject, SEE:
690*4882a593Smuzhiyun 	 *	edac_device_ctrl_instance_release() for callback operation
691*4882a593Smuzhiyun 	 */
692*4882a593Smuzhiyun 	kobject_put(&instance->kobj);
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun /*
696*4882a593Smuzhiyun  * edac_device_create_instances
697*4882a593Smuzhiyun  *	create the first level of 'instances' for this device
698*4882a593Smuzhiyun  *	(ie  'cache' might have 'cache0', 'cache1', 'cache2', etc
699*4882a593Smuzhiyun  */
edac_device_create_instances(struct edac_device_ctl_info * edac_dev)700*4882a593Smuzhiyun static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	int i, j;
703*4882a593Smuzhiyun 	int err;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	edac_dbg(0, "\n");
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/* iterate over creation of the instances */
708*4882a593Smuzhiyun 	for (i = 0; i < edac_dev->nr_instances; i++) {
709*4882a593Smuzhiyun 		err = edac_device_create_instance(edac_dev, i);
710*4882a593Smuzhiyun 		if (err) {
711*4882a593Smuzhiyun 			/* unwind previous instances on error */
712*4882a593Smuzhiyun 			for (j = 0; j < i; j++)
713*4882a593Smuzhiyun 				edac_device_delete_instance(edac_dev, j);
714*4882a593Smuzhiyun 			return err;
715*4882a593Smuzhiyun 		}
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	return 0;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun /*
722*4882a593Smuzhiyun  * edac_device_delete_instances(edac_dev);
723*4882a593Smuzhiyun  *	unregister all the kobjects of the instances
724*4882a593Smuzhiyun  */
edac_device_delete_instances(struct edac_device_ctl_info * edac_dev)725*4882a593Smuzhiyun static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	int i;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	/* iterate over creation of the instances */
730*4882a593Smuzhiyun 	for (i = 0; i < edac_dev->nr_instances; i++)
731*4882a593Smuzhiyun 		edac_device_delete_instance(edac_dev, i);
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun /* edac_dev sysfs ctor/dtor  code */
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun /*
737*4882a593Smuzhiyun  * edac_device_add_main_sysfs_attributes
738*4882a593Smuzhiyun  *	add some attributes to this instance's main kobject
739*4882a593Smuzhiyun  */
edac_device_add_main_sysfs_attributes(struct edac_device_ctl_info * edac_dev)740*4882a593Smuzhiyun static int edac_device_add_main_sysfs_attributes(
741*4882a593Smuzhiyun 			struct edac_device_ctl_info *edac_dev)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun 	struct edac_dev_sysfs_attribute *sysfs_attrib;
744*4882a593Smuzhiyun 	int err = 0;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	sysfs_attrib = edac_dev->sysfs_attributes;
747*4882a593Smuzhiyun 	if (sysfs_attrib) {
748*4882a593Smuzhiyun 		/* iterate over the array and create an attribute for each
749*4882a593Smuzhiyun 		 * entry in the list
750*4882a593Smuzhiyun 		 */
751*4882a593Smuzhiyun 		while (sysfs_attrib->attr.name != NULL) {
752*4882a593Smuzhiyun 			err = sysfs_create_file(&edac_dev->kobj,
753*4882a593Smuzhiyun 				(struct attribute*) sysfs_attrib);
754*4882a593Smuzhiyun 			if (err)
755*4882a593Smuzhiyun 				goto err_out;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 			sysfs_attrib++;
758*4882a593Smuzhiyun 		}
759*4882a593Smuzhiyun 	}
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun err_out:
762*4882a593Smuzhiyun 	return err;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun /*
766*4882a593Smuzhiyun  * edac_device_remove_main_sysfs_attributes
767*4882a593Smuzhiyun  *	remove any attributes to this instance's main kobject
768*4882a593Smuzhiyun  */
edac_device_remove_main_sysfs_attributes(struct edac_device_ctl_info * edac_dev)769*4882a593Smuzhiyun static void edac_device_remove_main_sysfs_attributes(
770*4882a593Smuzhiyun 			struct edac_device_ctl_info *edac_dev)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	struct edac_dev_sysfs_attribute *sysfs_attrib;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	/* if there are main attributes, defined, remove them. First,
775*4882a593Smuzhiyun 	 * point to the start of the array and iterate over it
776*4882a593Smuzhiyun 	 * removing each attribute listed from this device's instance's kobject
777*4882a593Smuzhiyun 	 */
778*4882a593Smuzhiyun 	sysfs_attrib = edac_dev->sysfs_attributes;
779*4882a593Smuzhiyun 	if (sysfs_attrib) {
780*4882a593Smuzhiyun 		while (sysfs_attrib->attr.name != NULL) {
781*4882a593Smuzhiyun 			sysfs_remove_file(&edac_dev->kobj,
782*4882a593Smuzhiyun 					(struct attribute *) sysfs_attrib);
783*4882a593Smuzhiyun 			sysfs_attrib++;
784*4882a593Smuzhiyun 		}
785*4882a593Smuzhiyun 	}
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun /*
789*4882a593Smuzhiyun  * edac_device_create_sysfs() Constructor
790*4882a593Smuzhiyun  *
791*4882a593Smuzhiyun  * accept a created edac_device control structure
792*4882a593Smuzhiyun  * and 'export' it to sysfs. The 'main' kobj should already have been
793*4882a593Smuzhiyun  * created. 'instance' and 'block' kobjects should be registered
794*4882a593Smuzhiyun  * along with any 'block' attributes from the low driver. In addition,
795*4882a593Smuzhiyun  * the main attributes (if any) are connected to the main kobject of
796*4882a593Smuzhiyun  * the control structure.
797*4882a593Smuzhiyun  *
798*4882a593Smuzhiyun  * Return:
799*4882a593Smuzhiyun  *	0	Success
800*4882a593Smuzhiyun  *	!0	Failure
801*4882a593Smuzhiyun  */
edac_device_create_sysfs(struct edac_device_ctl_info * edac_dev)802*4882a593Smuzhiyun int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
803*4882a593Smuzhiyun {
804*4882a593Smuzhiyun 	int err;
805*4882a593Smuzhiyun 	struct kobject *edac_kobj = &edac_dev->kobj;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	edac_dbg(0, "idx=%d\n", edac_dev->dev_idx);
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	/*  go create any main attributes callers wants */
810*4882a593Smuzhiyun 	err = edac_device_add_main_sysfs_attributes(edac_dev);
811*4882a593Smuzhiyun 	if (err) {
812*4882a593Smuzhiyun 		edac_dbg(0, "failed to add sysfs attribs\n");
813*4882a593Smuzhiyun 		goto err_out;
814*4882a593Smuzhiyun 	}
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	/* create a symlink from the edac device
817*4882a593Smuzhiyun 	 * to the platform 'device' being used for this
818*4882a593Smuzhiyun 	 */
819*4882a593Smuzhiyun 	err = sysfs_create_link(edac_kobj,
820*4882a593Smuzhiyun 				&edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
821*4882a593Smuzhiyun 	if (err) {
822*4882a593Smuzhiyun 		edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
823*4882a593Smuzhiyun 		goto err_remove_main_attribs;
824*4882a593Smuzhiyun 	}
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	/* Create the first level instance directories
827*4882a593Smuzhiyun 	 * In turn, the nested blocks beneath the instances will
828*4882a593Smuzhiyun 	 * be registered as well
829*4882a593Smuzhiyun 	 */
830*4882a593Smuzhiyun 	err = edac_device_create_instances(edac_dev);
831*4882a593Smuzhiyun 	if (err) {
832*4882a593Smuzhiyun 		edac_dbg(0, "edac_device_create_instances() returned err= %d\n",
833*4882a593Smuzhiyun 			 err);
834*4882a593Smuzhiyun 		goto err_remove_link;
835*4882a593Smuzhiyun 	}
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	edac_dbg(4, "create-instances done, idx=%d\n", edac_dev->dev_idx);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	return 0;
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	/* Error unwind stack */
843*4882a593Smuzhiyun err_remove_link:
844*4882a593Smuzhiyun 	/* remove the sym link */
845*4882a593Smuzhiyun 	sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun err_remove_main_attribs:
848*4882a593Smuzhiyun 	edac_device_remove_main_sysfs_attributes(edac_dev);
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun err_out:
851*4882a593Smuzhiyun 	return err;
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun /*
855*4882a593Smuzhiyun  * edac_device_remove_sysfs() destructor
856*4882a593Smuzhiyun  *
857*4882a593Smuzhiyun  * given an edac_device struct, tear down the kobject resources
858*4882a593Smuzhiyun  */
edac_device_remove_sysfs(struct edac_device_ctl_info * edac_dev)859*4882a593Smuzhiyun void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun 	edac_dbg(0, "\n");
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	/* remove any main attributes for this device */
864*4882a593Smuzhiyun 	edac_device_remove_main_sysfs_attributes(edac_dev);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	/* remove the device sym link */
867*4882a593Smuzhiyun 	sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	/* walk the instance/block kobject tree, deconstructing it */
870*4882a593Smuzhiyun 	edac_device_delete_instances(edac_dev);
871*4882a593Smuzhiyun }
872