diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/edac_core.h | 4 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 36 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 568 | ||||
-rw-r--r-- | drivers/edac/edac_module.c | 32 | ||||
-rw-r--r-- | drivers/edac/edac_module.h | 8 |
5 files changed, 399 insertions, 249 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 2c399c52193e..bd7f00cf2443 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h | |||
@@ -317,9 +317,8 @@ struct csrow_info { | |||
317 | struct mem_ctl_info *mci; /* the parent */ | 317 | struct mem_ctl_info *mci; /* the parent */ |
318 | 318 | ||
319 | struct kobject kobj; /* sysfs kobject for this csrow */ | 319 | struct kobject kobj; /* sysfs kobject for this csrow */ |
320 | struct completion kobj_complete; | ||
321 | 320 | ||
322 | /* FIXME the number of CHANNELs might need to become dynamic */ | 321 | /* channel information for this csrow */ |
323 | u32 nr_channels; | 322 | u32 nr_channels; |
324 | struct channel_info *channels; | 323 | struct channel_info *channels; |
325 | }; | 324 | }; |
@@ -403,7 +402,6 @@ struct mem_ctl_info { | |||
403 | 402 | ||
404 | /* edac sysfs device control */ | 403 | /* edac sysfs device control */ |
405 | struct kobject edac_mci_kobj; | 404 | struct kobject edac_mci_kobj; |
406 | struct completion kobj_complete; | ||
407 | 405 | ||
408 | /* Additional top controller level attributes, but specified | 406 | /* Additional top controller level attributes, but specified |
409 | * by the low level driver. | 407 | * by the low level driver. |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 6e4c94e9654a..2d53cb38868a 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -137,6 +137,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
137 | void *pvt; | 137 | void *pvt; |
138 | unsigned size; | 138 | unsigned size; |
139 | int row, chn; | 139 | int row, chn; |
140 | int err; | ||
140 | 141 | ||
141 | /* Figure out the offsets of the various items from the start of an mc | 142 | /* Figure out the offsets of the various items from the start of an mc |
142 | * structure. We want the alignment of each item to be at least as | 143 | * structure. We want the alignment of each item to be at least as |
@@ -149,7 +150,8 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
149 | pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); | 150 | pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); |
150 | size = ((unsigned long)pvt) + sz_pvt; | 151 | size = ((unsigned long)pvt) + sz_pvt; |
151 | 152 | ||
152 | if ((mci = kmalloc(size, GFP_KERNEL)) == NULL) | 153 | mci = kzalloc(size, GFP_KERNEL); |
154 | if (mci == NULL) | ||
153 | return NULL; | 155 | return NULL; |
154 | 156 | ||
155 | /* Adjust pointers so they point within the memory we just allocated | 157 | /* Adjust pointers so they point within the memory we just allocated |
@@ -182,20 +184,34 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
182 | 184 | ||
183 | mci->op_state = OP_ALLOC; | 185 | mci->op_state = OP_ALLOC; |
184 | 186 | ||
187 | /* | ||
188 | * Initialize the 'root' kobj for the edac_mc controller | ||
189 | */ | ||
190 | err = edac_mc_register_sysfs_main_kobj(mci); | ||
191 | if (err) { | ||
192 | kfree(mci); | ||
193 | return NULL; | ||
194 | } | ||
195 | |||
196 | /* at this point, the root kobj is valid, and in order to | ||
197 | * 'free' the object, then the function: | ||
198 | * edac_mc_unregister_sysfs_main_kobj() must be called | ||
199 | * which will perform kobj unregistration and the actual free | ||
200 | * will occur during the kobject callback operation | ||
201 | */ | ||
185 | return mci; | 202 | return mci; |
186 | } | 203 | } |
187 | |||
188 | EXPORT_SYMBOL_GPL(edac_mc_alloc); | 204 | EXPORT_SYMBOL_GPL(edac_mc_alloc); |
189 | 205 | ||
190 | /** | 206 | /** |
191 | * edac_mc_free: Free a previously allocated 'mci' structure | 207 | * edac_mc_free |
208 | * 'Free' a previously allocated 'mci' structure | ||
192 | * @mci: pointer to a struct mem_ctl_info structure | 209 | * @mci: pointer to a struct mem_ctl_info structure |
193 | */ | 210 | */ |
194 | void edac_mc_free(struct mem_ctl_info *mci) | 211 | void edac_mc_free(struct mem_ctl_info *mci) |
195 | { | 212 | { |
196 | kfree(mci); | 213 | edac_mc_unregister_sysfs_main_kobj(mci); |
197 | } | 214 | } |
198 | |||
199 | EXPORT_SYMBOL_GPL(edac_mc_free); | 215 | EXPORT_SYMBOL_GPL(edac_mc_free); |
200 | 216 | ||
201 | static struct mem_ctl_info *find_mci_by_dev(struct device *dev) | 217 | static struct mem_ctl_info *find_mci_by_dev(struct device *dev) |
@@ -391,7 +407,6 @@ struct mem_ctl_info *edac_mc_find(int idx) | |||
391 | 407 | ||
392 | return NULL; | 408 | return NULL; |
393 | } | 409 | } |
394 | |||
395 | EXPORT_SYMBOL(edac_mc_find); | 410 | EXPORT_SYMBOL(edac_mc_find); |
396 | 411 | ||
397 | /** | 412 | /** |
@@ -465,7 +480,6 @@ fail0: | |||
465 | mutex_unlock(&mem_ctls_mutex); | 480 | mutex_unlock(&mem_ctls_mutex); |
466 | return 1; | 481 | return 1; |
467 | } | 482 | } |
468 | |||
469 | EXPORT_SYMBOL_GPL(edac_mc_add_mc); | 483 | EXPORT_SYMBOL_GPL(edac_mc_add_mc); |
470 | 484 | ||
471 | /** | 485 | /** |
@@ -501,7 +515,6 @@ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) | |||
501 | mci->mod_name, mci->ctl_name, dev_name(mci)); | 515 | mci->mod_name, mci->ctl_name, dev_name(mci)); |
502 | return mci; | 516 | return mci; |
503 | } | 517 | } |
504 | |||
505 | EXPORT_SYMBOL_GPL(edac_mc_del_mc); | 518 | EXPORT_SYMBOL_GPL(edac_mc_del_mc); |
506 | 519 | ||
507 | static void edac_mc_scrub_block(unsigned long page, unsigned long offset, | 520 | static void edac_mc_scrub_block(unsigned long page, unsigned long offset, |
@@ -571,7 +584,6 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) | |||
571 | 584 | ||
572 | return row; | 585 | return row; |
573 | } | 586 | } |
574 | |||
575 | EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); | 587 | EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); |
576 | 588 | ||
577 | /* FIXME - setable log (warning/emerg) levels */ | 589 | /* FIXME - setable log (warning/emerg) levels */ |
@@ -636,7 +648,6 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci, | |||
636 | mci->csrows[row].grain); | 648 | mci->csrows[row].grain); |
637 | } | 649 | } |
638 | } | 650 | } |
639 | |||
640 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce); | 651 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce); |
641 | 652 | ||
642 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) | 653 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) |
@@ -648,7 +659,6 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) | |||
648 | mci->ce_noinfo_count++; | 659 | mci->ce_noinfo_count++; |
649 | mci->ce_count++; | 660 | mci->ce_count++; |
650 | } | 661 | } |
651 | |||
652 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); | 662 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); |
653 | 663 | ||
654 | void edac_mc_handle_ue(struct mem_ctl_info *mci, | 664 | void edac_mc_handle_ue(struct mem_ctl_info *mci, |
@@ -702,7 +712,6 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci, | |||
702 | mci->ue_count++; | 712 | mci->ue_count++; |
703 | mci->csrows[row].ue_count++; | 713 | mci->csrows[row].ue_count++; |
704 | } | 714 | } |
705 | |||
706 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue); | 715 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue); |
707 | 716 | ||
708 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | 717 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) |
@@ -716,7 +725,6 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | |||
716 | mci->ue_noinfo_count++; | 725 | mci->ue_noinfo_count++; |
717 | mci->ue_count++; | 726 | mci->ue_count++; |
718 | } | 727 | } |
719 | |||
720 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); | 728 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); |
721 | 729 | ||
722 | /************************************************************* | 730 | /************************************************************* |
@@ -784,7 +792,6 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | |||
784 | "labels \"%s\": %s\n", csrow, channela, | 792 | "labels \"%s\": %s\n", csrow, channela, |
785 | channelb, labels, msg); | 793 | channelb, labels, msg); |
786 | } | 794 | } |
787 | |||
788 | EXPORT_SYMBOL(edac_mc_handle_fbd_ue); | 795 | EXPORT_SYMBOL(edac_mc_handle_fbd_ue); |
789 | 796 | ||
790 | /************************************************************* | 797 | /************************************************************* |
@@ -824,7 +831,6 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | |||
824 | mci->csrows[csrow].ce_count++; | 831 | mci->csrows[csrow].ce_count++; |
825 | mci->csrows[csrow].channels[channel].ce_count++; | 832 | mci->csrows[csrow].channels[channel].ce_count++; |
826 | } | 833 | } |
827 | |||
828 | EXPORT_SYMBOL(edac_mc_handle_fbd_ce); | 834 | EXPORT_SYMBOL(edac_mc_handle_fbd_ce); |
829 | 835 | ||
830 | /* | 836 | /* |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 0843eaa10ec9..cd090b0677a7 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -10,10 +10,12 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
13 | #include <linux/bug.h> | ||
13 | 14 | ||
14 | #include "edac_core.h" | 15 | #include "edac_core.h" |
15 | #include "edac_module.h" | 16 | #include "edac_module.h" |
16 | 17 | ||
18 | |||
17 | /* MC EDAC Controls, setable by module parameter, and sysfs */ | 19 | /* MC EDAC Controls, setable by module parameter, and sysfs */ |
18 | static int edac_mc_log_ue = 1; | 20 | static int edac_mc_log_ue = 1; |
19 | static int edac_mc_log_ce = 1; | 21 | static int edac_mc_log_ce = 1; |
@@ -98,15 +100,7 @@ static const char *edac_caps[] = { | |||
98 | [EDAC_S16ECD16ED] = "S16ECD16ED" | 100 | [EDAC_S16ECD16ED] = "S16ECD16ED" |
99 | }; | 101 | }; |
100 | 102 | ||
101 | /* sysfs object: | ||
102 | * /sys/devices/system/edac/mc | ||
103 | */ | ||
104 | static struct kobject edac_memctrl_kobj; | ||
105 | 103 | ||
106 | /* We use these to wait for the reference counts on edac_memctrl_kobj and | ||
107 | * edac_pci_kobj to reach 0. | ||
108 | */ | ||
109 | static struct completion edac_memctrl_kobj_complete; | ||
110 | 104 | ||
111 | /* | 105 | /* |
112 | * /sys/devices/system/edac/mc; | 106 | * /sys/devices/system/edac/mc; |
@@ -128,153 +122,6 @@ static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) | |||
128 | return count; | 122 | return count; |
129 | } | 123 | } |
130 | 124 | ||
131 | struct memctrl_dev_attribute { | ||
132 | struct attribute attr; | ||
133 | void *value; | ||
134 | ssize_t(*show) (void *, char *); | ||
135 | ssize_t(*store) (void *, const char *, size_t); | ||
136 | }; | ||
137 | |||
138 | /* Set of show/store abstract level functions for memory control object */ | ||
139 | static ssize_t memctrl_dev_show(struct kobject *kobj, | ||
140 | struct attribute *attr, char *buffer) | ||
141 | { | ||
142 | struct memctrl_dev_attribute *memctrl_dev; | ||
143 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
144 | |||
145 | if (memctrl_dev->show) | ||
146 | return memctrl_dev->show(memctrl_dev->value, buffer); | ||
147 | |||
148 | return -EIO; | ||
149 | } | ||
150 | |||
151 | static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, | ||
152 | const char *buffer, size_t count) | ||
153 | { | ||
154 | struct memctrl_dev_attribute *memctrl_dev; | ||
155 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
156 | |||
157 | if (memctrl_dev->store) | ||
158 | return memctrl_dev->store(memctrl_dev->value, buffer, count); | ||
159 | |||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | static struct sysfs_ops memctrlfs_ops = { | ||
164 | .show = memctrl_dev_show, | ||
165 | .store = memctrl_dev_store | ||
166 | }; | ||
167 | |||
168 | #define MEMCTRL_ATTR(_name,_mode,_show,_store) \ | ||
169 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
170 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
171 | .value = &_name, \ | ||
172 | .show = _show, \ | ||
173 | .store = _store, \ | ||
174 | }; | ||
175 | |||
176 | #define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \ | ||
177 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
178 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
179 | .value = _data, \ | ||
180 | .show = _show, \ | ||
181 | .store = _store, \ | ||
182 | }; | ||
183 | |||
184 | /* csrow<id> control files */ | ||
185 | MEMCTRL_ATTR(edac_mc_panic_on_ue, | ||
186 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
187 | |||
188 | MEMCTRL_ATTR(edac_mc_log_ue, | ||
189 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
190 | |||
191 | MEMCTRL_ATTR(edac_mc_log_ce, | ||
192 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
193 | |||
194 | MEMCTRL_ATTR(edac_mc_poll_msec, | ||
195 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
196 | |||
197 | /* Base Attributes of the memory ECC object */ | ||
198 | static struct memctrl_dev_attribute *memctrl_attr[] = { | ||
199 | &attr_edac_mc_panic_on_ue, | ||
200 | &attr_edac_mc_log_ue, | ||
201 | &attr_edac_mc_log_ce, | ||
202 | &attr_edac_mc_poll_msec, | ||
203 | NULL, | ||
204 | }; | ||
205 | |||
206 | /* Main MC kobject release() function */ | ||
207 | static void edac_memctrl_master_release(struct kobject *kobj) | ||
208 | { | ||
209 | debugf1("%s()\n", __func__); | ||
210 | complete(&edac_memctrl_kobj_complete); | ||
211 | } | ||
212 | |||
213 | static struct kobj_type ktype_memctrl = { | ||
214 | .release = edac_memctrl_master_release, | ||
215 | .sysfs_ops = &memctrlfs_ops, | ||
216 | .default_attrs = (struct attribute **)memctrl_attr, | ||
217 | }; | ||
218 | |||
219 | /* Initialize the main sysfs entries for edac: | ||
220 | * /sys/devices/system/edac | ||
221 | * | ||
222 | * and children | ||
223 | * | ||
224 | * Return: 0 SUCCESS | ||
225 | * !0 FAILURE | ||
226 | */ | ||
227 | int edac_sysfs_memctrl_setup(void) | ||
228 | { | ||
229 | int err = 0; | ||
230 | struct sysdev_class *edac_class; | ||
231 | |||
232 | debugf1("%s()\n", __func__); | ||
233 | |||
234 | /* get the /sys/devices/system/edac class reference */ | ||
235 | edac_class = edac_get_edac_class(); | ||
236 | if (edac_class == NULL) { | ||
237 | debugf1("%s() no edac_class error=%d\n", __func__, err); | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | /* Init the MC's kobject */ | ||
242 | memset(&edac_memctrl_kobj, 0, sizeof(edac_memctrl_kobj)); | ||
243 | edac_memctrl_kobj.parent = &edac_class->kset.kobj; | ||
244 | edac_memctrl_kobj.ktype = &ktype_memctrl; | ||
245 | |||
246 | /* generate sysfs "..../edac/mc" */ | ||
247 | err = kobject_set_name(&edac_memctrl_kobj, "mc"); | ||
248 | if (err) { | ||
249 | debugf1("%s() Failed to set name '.../edac/mc'\n", __func__); | ||
250 | return err; | ||
251 | } | ||
252 | |||
253 | /* FIXME: maybe new sysdev_create_subdir() */ | ||
254 | err = kobject_register(&edac_memctrl_kobj); | ||
255 | if (err) { | ||
256 | debugf1("%s() Failed to register '.../edac/mc'\n", __func__); | ||
257 | return err; | ||
258 | } | ||
259 | |||
260 | debugf1("%s() Registered '.../edac/mc' kobject\n", __func__); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * MC teardown: | ||
266 | * the '..../edac/mc' kobject followed by '..../edac' itself | ||
267 | */ | ||
268 | void edac_sysfs_memctrl_teardown(void) | ||
269 | { | ||
270 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
271 | |||
272 | /* Unregister the MC's kobject and wait for reference count to reach 0. | ||
273 | */ | ||
274 | init_completion(&edac_memctrl_kobj_complete); | ||
275 | kobject_unregister(&edac_memctrl_kobj); | ||
276 | wait_for_completion(&edac_memctrl_kobj_complete); | ||
277 | } | ||
278 | 125 | ||
279 | /* EDAC sysfs CSROW data structures and methods | 126 | /* EDAC sysfs CSROW data structures and methods |
280 | */ | 127 | */ |
@@ -486,10 +333,15 @@ static int edac_create_channel_files(struct kobject *kobj, int chan) | |||
486 | /* No memory to release for this kobj */ | 333 | /* No memory to release for this kobj */ |
487 | static void edac_csrow_instance_release(struct kobject *kobj) | 334 | static void edac_csrow_instance_release(struct kobject *kobj) |
488 | { | 335 | { |
336 | struct mem_ctl_info *mci; | ||
489 | struct csrow_info *cs; | 337 | struct csrow_info *cs; |
490 | 338 | ||
339 | debugf1("%s()\n", __func__); | ||
340 | |||
491 | cs = container_of(kobj, struct csrow_info, kobj); | 341 | cs = container_of(kobj, struct csrow_info, kobj); |
492 | complete(&cs->kobj_complete); | 342 | mci = cs->mci; |
343 | |||
344 | kobject_put(&mci->edac_mci_kobj); | ||
493 | } | 345 | } |
494 | 346 | ||
495 | /* the kobj_type instance for a CSROW */ | 347 | /* the kobj_type instance for a CSROW */ |
@@ -500,38 +352,61 @@ static struct kobj_type ktype_csrow = { | |||
500 | }; | 352 | }; |
501 | 353 | ||
502 | /* Create a CSROW object under specifed edac_mc_device */ | 354 | /* Create a CSROW object under specifed edac_mc_device */ |
503 | static int edac_create_csrow_object(struct kobject *edac_mci_kobj, | 355 | static int edac_create_csrow_object(struct mem_ctl_info *mci, |
504 | struct csrow_info *csrow, int index) | 356 | struct csrow_info *csrow, int index) |
505 | { | 357 | { |
506 | int err = 0; | 358 | struct kobject *kobj_mci = &mci->edac_mci_kobj; |
359 | struct kobject *kobj; | ||
507 | int chan; | 360 | int chan; |
508 | 361 | int err; | |
509 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); | ||
510 | 362 | ||
511 | /* generate ..../edac/mc/mc<id>/csrow<index> */ | 363 | /* generate ..../edac/mc/mc<id>/csrow<index> */ |
512 | 364 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); | |
513 | csrow->kobj.parent = edac_mci_kobj; | 365 | csrow->mci = mci; /* include container up link */ |
366 | csrow->kobj.parent = kobj_mci; | ||
514 | csrow->kobj.ktype = &ktype_csrow; | 367 | csrow->kobj.ktype = &ktype_csrow; |
515 | 368 | ||
516 | /* name this instance of csrow<id> */ | 369 | /* name this instance of csrow<id> */ |
517 | err = kobject_set_name(&csrow->kobj, "csrow%d", index); | 370 | err = kobject_set_name(&csrow->kobj, "csrow%d", index); |
518 | if (err) | 371 | if (err) |
519 | goto error_exit; | 372 | goto err_out; |
373 | |||
374 | /* bump the mci instance's kobject's ref count */ | ||
375 | kobj = kobject_get(&mci->edac_mci_kobj); | ||
376 | if (!kobj) { | ||
377 | err = -ENODEV; | ||
378 | goto err_out; | ||
379 | } | ||
520 | 380 | ||
521 | /* Instanstiate the csrow object */ | 381 | /* Instanstiate the csrow object */ |
522 | err = kobject_register(&csrow->kobj); | 382 | err = kobject_register(&csrow->kobj); |
523 | if (!err) { | 383 | if (err) |
524 | /* Create the dyanmic attribute files on this csrow, | 384 | goto err_release_top_kobj; |
525 | * namely, the DIMM labels and the channel ce_count | 385 | |
526 | */ | 386 | /* At this point, to release a csrow kobj, one must |
527 | for (chan = 0; chan < csrow->nr_channels; chan++) { | 387 | * call the kobject_unregister and allow that tear down |
528 | err = edac_create_channel_files(&csrow->kobj, chan); | 388 | * to work the releasing |
529 | if (err) | 389 | */ |
530 | break; | 390 | |
391 | /* Create the dyanmic attribute files on this csrow, | ||
392 | * namely, the DIMM labels and the channel ce_count | ||
393 | */ | ||
394 | for (chan = 0; chan < csrow->nr_channels; chan++) { | ||
395 | err = edac_create_channel_files(&csrow->kobj, chan); | ||
396 | if (err) { | ||
397 | /* special case the unregister here */ | ||
398 | kobject_unregister(&csrow->kobj); | ||
399 | goto err_out; | ||
531 | } | 400 | } |
532 | } | 401 | } |
533 | 402 | ||
534 | error_exit: | 403 | return 0; |
404 | |||
405 | /* error unwind stack */ | ||
406 | err_release_top_kobj: | ||
407 | kobject_put(&mci->edac_mci_kobj); | ||
408 | |||
409 | err_out: | ||
535 | return err; | 410 | return err; |
536 | } | 411 | } |
537 | 412 | ||
@@ -688,6 +563,7 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, | |||
688 | return -EIO; | 563 | return -EIO; |
689 | } | 564 | } |
690 | 565 | ||
566 | /* Intermediate show/store table */ | ||
691 | static struct sysfs_ops mci_ops = { | 567 | static struct sysfs_ops mci_ops = { |
692 | .show = mcidev_show, | 568 | .show = mcidev_show, |
693 | .store = mcidev_store | 569 | .store = mcidev_store |
@@ -729,32 +605,213 @@ static struct mcidev_sysfs_attribute *mci_attr[] = { | |||
729 | NULL | 605 | NULL |
730 | }; | 606 | }; |
731 | 607 | ||
608 | |||
732 | /* | 609 | /* |
733 | * Release of a MC controlling instance | 610 | * Release of a MC controlling instance |
611 | * | ||
612 | * each MC control instance has the following resources upon entry: | ||
613 | * a) a ref count on the top memctl kobj | ||
614 | * b) a ref count on this module | ||
615 | * | ||
616 | * this function must decrement those ref counts and then | ||
617 | * issue a free on the instance's memory | ||
734 | */ | 618 | */ |
735 | static void edac_mci_instance_release(struct kobject *kobj) | 619 | static void edac_mci_control_release(struct kobject *kobj) |
736 | { | 620 | { |
737 | struct mem_ctl_info *mci; | 621 | struct mem_ctl_info *mci; |
738 | 622 | ||
739 | mci = to_mci(kobj); | 623 | mci = to_mci(kobj); |
740 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | 624 | |
741 | complete(&mci->kobj_complete); | 625 | debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx); |
626 | |||
627 | /* decrement the module ref count */ | ||
628 | module_put(mci->owner); | ||
629 | |||
630 | /* free the mci instance memory here */ | ||
631 | kfree(mci); | ||
742 | } | 632 | } |
743 | 633 | ||
744 | static struct kobj_type ktype_mci = { | 634 | static struct kobj_type ktype_mci = { |
745 | .release = edac_mci_instance_release, | 635 | .release = edac_mci_control_release, |
746 | .sysfs_ops = &mci_ops, | 636 | .sysfs_ops = &mci_ops, |
747 | .default_attrs = (struct attribute **)mci_attr, | 637 | .default_attrs = (struct attribute **)mci_attr, |
748 | }; | 638 | }; |
749 | 639 | ||
640 | /* show/store, tables, etc for the MC kset */ | ||
641 | |||
642 | |||
643 | struct memctrl_dev_attribute { | ||
644 | struct attribute attr; | ||
645 | void *value; | ||
646 | ssize_t(*show) (void *, char *); | ||
647 | ssize_t(*store) (void *, const char *, size_t); | ||
648 | }; | ||
649 | |||
650 | /* Set of show/store abstract level functions for memory control object */ | ||
651 | static ssize_t memctrl_dev_show(struct kobject *kobj, | ||
652 | struct attribute *attr, char *buffer) | ||
653 | { | ||
654 | struct memctrl_dev_attribute *memctrl_dev; | ||
655 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
656 | |||
657 | if (memctrl_dev->show) | ||
658 | return memctrl_dev->show(memctrl_dev->value, buffer); | ||
659 | |||
660 | return -EIO; | ||
661 | } | ||
662 | |||
663 | static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, | ||
664 | const char *buffer, size_t count) | ||
665 | { | ||
666 | struct memctrl_dev_attribute *memctrl_dev; | ||
667 | memctrl_dev = (struct memctrl_dev_attribute *)attr; | ||
668 | |||
669 | if (memctrl_dev->store) | ||
670 | return memctrl_dev->store(memctrl_dev->value, buffer, count); | ||
671 | |||
672 | return -EIO; | ||
673 | } | ||
674 | |||
675 | static struct sysfs_ops memctrlfs_ops = { | ||
676 | .show = memctrl_dev_show, | ||
677 | .store = memctrl_dev_store | ||
678 | }; | ||
679 | |||
680 | #define MEMCTRL_ATTR(_name, _mode, _show, _store) \ | ||
681 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
682 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
683 | .value = &_name, \ | ||
684 | .show = _show, \ | ||
685 | .store = _store, \ | ||
686 | }; | ||
687 | |||
688 | #define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store) \ | ||
689 | static struct memctrl_dev_attribute attr_##_name = { \ | ||
690 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
691 | .value = _data, \ | ||
692 | .show = _show, \ | ||
693 | .store = _store, \ | ||
694 | }; | ||
695 | |||
696 | /* csrow<id> control files */ | ||
697 | MEMCTRL_ATTR(edac_mc_panic_on_ue, | ||
698 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
699 | |||
700 | MEMCTRL_ATTR(edac_mc_log_ue, | ||
701 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
702 | |||
703 | MEMCTRL_ATTR(edac_mc_log_ce, | ||
704 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
705 | |||
706 | MEMCTRL_ATTR(edac_mc_poll_msec, | ||
707 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | ||
708 | |||
709 | /* Base Attributes of the memory ECC object */ | ||
710 | static struct memctrl_dev_attribute *memctrl_attr[] = { | ||
711 | &attr_edac_mc_panic_on_ue, | ||
712 | &attr_edac_mc_log_ue, | ||
713 | &attr_edac_mc_log_ce, | ||
714 | &attr_edac_mc_poll_msec, | ||
715 | NULL, | ||
716 | }; | ||
717 | |||
718 | |||
719 | /* the ktype for the mc_kset internal kobj */ | ||
720 | static struct kobj_type ktype_mc_set_attribs = { | ||
721 | .sysfs_ops = &memctrlfs_ops, | ||
722 | .default_attrs = (struct attribute **)memctrl_attr, | ||
723 | }; | ||
724 | |||
725 | /* EDAC memory controller sysfs kset: | ||
726 | * /sys/devices/system/edac/mc | ||
727 | */ | ||
728 | static struct kset mc_kset = { | ||
729 | .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs }, | ||
730 | .ktype = &ktype_mci, | ||
731 | }; | ||
732 | |||
733 | |||
734 | /* | ||
735 | * edac_mc_register_sysfs_main_kobj | ||
736 | * | ||
737 | * setups and registers the main kobject for each mci | ||
738 | */ | ||
739 | int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) | ||
740 | { | ||
741 | struct kobject *kobj_mci; | ||
742 | int err; | ||
743 | |||
744 | debugf1("%s()\n", __func__); | ||
745 | |||
746 | kobj_mci = &mci->edac_mci_kobj; | ||
747 | |||
748 | /* Init the mci's kobject */ | ||
749 | memset(kobj_mci, 0, sizeof(*kobj_mci)); | ||
750 | |||
751 | /* this instance become part of the mc_kset */ | ||
752 | kobj_mci->kset = &mc_kset; | ||
753 | |||
754 | /* set the name of the mc<id> object */ | ||
755 | err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx); | ||
756 | if (err) | ||
757 | goto fail_out; | ||
758 | |||
759 | /* Record which module 'owns' this control structure | ||
760 | * and bump the ref count of the module | ||
761 | */ | ||
762 | mci->owner = THIS_MODULE; | ||
763 | |||
764 | /* bump ref count on this module */ | ||
765 | if (!try_module_get(mci->owner)) { | ||
766 | err = -ENODEV; | ||
767 | goto fail_out; | ||
768 | } | ||
769 | |||
770 | /* register the mc<id> kobject to the mc_kset */ | ||
771 | err = kobject_register(kobj_mci); | ||
772 | if (err) { | ||
773 | debugf1("%s()Failed to register '.../edac/mc%d'\n", | ||
774 | __func__, mci->mc_idx); | ||
775 | goto kobj_reg_fail; | ||
776 | } | ||
777 | |||
778 | /* At this point, to 'free' the control struct, | ||
779 | * edac_mc_unregister_sysfs_main_kobj() must be used | ||
780 | */ | ||
781 | |||
782 | debugf1("%s() Registered '.../edac/mc%d' kobject\n", | ||
783 | __func__, mci->mc_idx); | ||
784 | |||
785 | return 0; | ||
786 | |||
787 | /* Error exit stack */ | ||
788 | |||
789 | kobj_reg_fail: | ||
790 | module_put(mci->owner); | ||
791 | |||
792 | fail_out: | ||
793 | return err; | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * edac_mc_register_sysfs_main_kobj | ||
798 | * | ||
799 | * tears down and the main mci kobject from the mc_kset | ||
800 | */ | ||
801 | void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) | ||
802 | { | ||
803 | /* delete the kobj from the mc_kset */ | ||
804 | kobject_unregister(&mci->edac_mci_kobj); | ||
805 | } | ||
806 | |||
750 | #define EDAC_DEVICE_SYMLINK "device" | 807 | #define EDAC_DEVICE_SYMLINK "device" |
751 | 808 | ||
752 | /* | 809 | /* |
753 | * edac_create_driver_attributes | 810 | * edac_create_mci_instance_attributes |
754 | * create MC driver specific attributes at the topmost level | 811 | * create MC driver specific attributes at the topmost level |
755 | * directory of this mci instance. | 812 | * directory of this mci instance. |
756 | */ | 813 | */ |
757 | static int edac_create_driver_attributes(struct mem_ctl_info *mci) | 814 | static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci) |
758 | { | 815 | { |
759 | int err; | 816 | int err; |
760 | struct mcidev_sysfs_attribute *sysfs_attrib; | 817 | struct mcidev_sysfs_attribute *sysfs_attrib; |
@@ -764,7 +821,7 @@ static int edac_create_driver_attributes(struct mem_ctl_info *mci) | |||
764 | */ | 821 | */ |
765 | sysfs_attrib = mci->mc_driver_sysfs_attributes; | 822 | sysfs_attrib = mci->mc_driver_sysfs_attributes; |
766 | 823 | ||
767 | while (sysfs_attrib->attr.name != NULL) { | 824 | while (sysfs_attrib && sysfs_attrib->attr.name) { |
768 | err = sysfs_create_file(&mci->edac_mci_kobj, | 825 | err = sysfs_create_file(&mci->edac_mci_kobj, |
769 | (struct attribute*) sysfs_attrib); | 826 | (struct attribute*) sysfs_attrib); |
770 | if (err) { | 827 | if (err) { |
@@ -778,6 +835,29 @@ static int edac_create_driver_attributes(struct mem_ctl_info *mci) | |||
778 | } | 835 | } |
779 | 836 | ||
780 | /* | 837 | /* |
838 | * edac_remove_mci_instance_attributes | ||
839 | * remove MC driver specific attributes at the topmost level | ||
840 | * directory of this mci instance. | ||
841 | */ | ||
842 | static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci) | ||
843 | { | ||
844 | struct mcidev_sysfs_attribute *sysfs_attrib; | ||
845 | |||
846 | /* point to the start of the array and iterate over it | ||
847 | * adding each attribute listed to this mci instance's kobject | ||
848 | */ | ||
849 | sysfs_attrib = mci->mc_driver_sysfs_attributes; | ||
850 | |||
851 | /* loop if there are attributes and until we hit a NULL entry */ | ||
852 | while (sysfs_attrib && sysfs_attrib->attr.name) { | ||
853 | sysfs_remove_file(&mci->edac_mci_kobj, | ||
854 | (struct attribute *) sysfs_attrib); | ||
855 | sysfs_attrib++; | ||
856 | } | ||
857 | } | ||
858 | |||
859 | |||
860 | /* | ||
781 | * Create a new Memory Controller kobject instance, | 861 | * Create a new Memory Controller kobject instance, |
782 | * mc<id> under the 'mc' directory | 862 | * mc<id> under the 'mc' directory |
783 | * | 863 | * |
@@ -790,51 +870,43 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
790 | int i; | 870 | int i; |
791 | int err; | 871 | int err; |
792 | struct csrow_info *csrow; | 872 | struct csrow_info *csrow; |
793 | struct kobject *edac_mci_kobj = &mci->edac_mci_kobj; | 873 | struct kobject *kobj_mci = &mci->edac_mci_kobj; |
794 | 874 | ||
795 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | 875 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); |
796 | memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); | ||
797 | |||
798 | /* set the name of the mc<id> object */ | ||
799 | err = kobject_set_name(edac_mci_kobj, "mc%d", mci->mc_idx); | ||
800 | if (err) | ||
801 | return err; | ||
802 | |||
803 | /* link to our parent the '..../edac/mc' object */ | ||
804 | edac_mci_kobj->parent = &edac_memctrl_kobj; | ||
805 | edac_mci_kobj->ktype = &ktype_mci; | ||
806 | |||
807 | /* register the mc<id> kobject */ | ||
808 | err = kobject_register(edac_mci_kobj); | ||
809 | if (err) | ||
810 | return err; | ||
811 | 876 | ||
812 | /* create a symlink for the device */ | 877 | /* create a symlink for the device */ |
813 | err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj, | 878 | err = sysfs_create_link(kobj_mci, &mci->dev->kobj, |
814 | EDAC_DEVICE_SYMLINK); | 879 | EDAC_DEVICE_SYMLINK); |
815 | if (err) | 880 | if (err) { |
881 | debugf1("%s() failure to create symlink\n", __func__); | ||
816 | goto fail0; | 882 | goto fail0; |
883 | } | ||
817 | 884 | ||
818 | /* If the low level driver desires some attributes, | 885 | /* If the low level driver desires some attributes, |
819 | * then create them now for the driver. | 886 | * then create them now for the driver. |
820 | */ | 887 | */ |
821 | if (mci->mc_driver_sysfs_attributes) { | 888 | if (mci->mc_driver_sysfs_attributes) { |
822 | err = edac_create_driver_attributes(mci); | 889 | err = edac_create_mci_instance_attributes(mci); |
823 | if (err) | 890 | if (err) { |
891 | debugf1("%s() failure to create mci attributes\n", | ||
892 | __func__); | ||
824 | goto fail0; | 893 | goto fail0; |
894 | } | ||
825 | } | 895 | } |
826 | 896 | ||
827 | /* Make directories for each CSROW object | 897 | /* Make directories for each CSROW object under the mc<id> kobject |
828 | * under the mc<id> kobject | ||
829 | */ | 898 | */ |
830 | for (i = 0; i < mci->nr_csrows; i++) { | 899 | for (i = 0; i < mci->nr_csrows; i++) { |
831 | csrow = &mci->csrows[i]; | 900 | csrow = &mci->csrows[i]; |
832 | 901 | ||
833 | /* Only expose populated CSROWs */ | 902 | /* Only expose populated CSROWs */ |
834 | if (csrow->nr_pages > 0) { | 903 | if (csrow->nr_pages > 0) { |
835 | err = edac_create_csrow_object(edac_mci_kobj, csrow, i); | 904 | err = edac_create_csrow_object(mci, csrow, i); |
836 | if (err) | 905 | if (err) { |
906 | debugf1("%s() failure: create csrow %d obj\n", | ||
907 | __func__, i); | ||
837 | goto fail1; | 908 | goto fail1; |
909 | } | ||
838 | } | 910 | } |
839 | } | 911 | } |
840 | 912 | ||
@@ -844,16 +916,17 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
844 | fail1: | 916 | fail1: |
845 | for (i--; i >= 0; i--) { | 917 | for (i--; i >= 0; i--) { |
846 | if (csrow->nr_pages > 0) { | 918 | if (csrow->nr_pages > 0) { |
847 | init_completion(&csrow->kobj_complete); | ||
848 | kobject_unregister(&mci->csrows[i].kobj); | 919 | kobject_unregister(&mci->csrows[i].kobj); |
849 | wait_for_completion(&csrow->kobj_complete); | ||
850 | } | 920 | } |
851 | } | 921 | } |
852 | 922 | ||
923 | /* remove the mci instance's attributes, if any */ | ||
924 | edac_remove_mci_instance_attributes(mci); | ||
925 | |||
926 | /* remove the symlink */ | ||
927 | sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK); | ||
928 | |||
853 | fail0: | 929 | fail0: |
854 | init_completion(&mci->kobj_complete); | ||
855 | kobject_unregister(edac_mci_kobj); | ||
856 | wait_for_completion(&mci->kobj_complete); | ||
857 | return err; | 930 | return err; |
858 | } | 931 | } |
859 | 932 | ||
@@ -869,14 +942,83 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
869 | /* remove all csrow kobjects */ | 942 | /* remove all csrow kobjects */ |
870 | for (i = 0; i < mci->nr_csrows; i++) { | 943 | for (i = 0; i < mci->nr_csrows; i++) { |
871 | if (mci->csrows[i].nr_pages > 0) { | 944 | if (mci->csrows[i].nr_pages > 0) { |
872 | init_completion(&mci->csrows[i].kobj_complete); | 945 | debugf0("%s() unreg csrow-%d\n", __func__, i); |
873 | kobject_unregister(&mci->csrows[i].kobj); | 946 | kobject_unregister(&mci->csrows[i].kobj); |
874 | wait_for_completion(&mci->csrows[i].kobj_complete); | ||
875 | } | 947 | } |
876 | } | 948 | } |
877 | 949 | ||
950 | debugf0("%s() remove_link\n", __func__); | ||
951 | |||
952 | /* remove the symlink */ | ||
878 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | 953 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); |
879 | init_completion(&mci->kobj_complete); | 954 | |
955 | debugf0("%s() remove_mci_instance\n", __func__); | ||
956 | |||
957 | /* remove this mci instance's attribtes */ | ||
958 | edac_remove_mci_instance_attributes(mci); | ||
959 | |||
960 | debugf0("%s() unregister this mci kobj\n", __func__); | ||
961 | |||
962 | /* unregister this instance's kobject */ | ||
880 | kobject_unregister(&mci->edac_mci_kobj); | 963 | kobject_unregister(&mci->edac_mci_kobj); |
881 | wait_for_completion(&mci->kobj_complete); | ||
882 | } | 964 | } |
965 | |||
966 | |||
967 | |||
968 | |||
969 | /* | ||
970 | * edac_setup_sysfs_mc_kset(void) | ||
971 | * | ||
972 | * Initialize the mc_kset for the 'mc' entry | ||
973 | * This requires creating the top 'mc' directory with a kset | ||
974 | * and its controls/attributes. | ||
975 | * | ||
976 | * To this 'mc' kset, instance 'mci' will be grouped as children. | ||
977 | * | ||
978 | * Return: 0 SUCCESS | ||
979 | * !0 FAILURE error code | ||
980 | */ | ||
981 | int edac_sysfs_setup_mc_kset(void) | ||
982 | { | ||
983 | int err = 0; | ||
984 | struct sysdev_class *edac_class; | ||
985 | |||
986 | debugf1("%s()\n", __func__); | ||
987 | |||
988 | /* get the /sys/devices/system/edac class reference */ | ||
989 | edac_class = edac_get_edac_class(); | ||
990 | if (edac_class == NULL) { | ||
991 | debugf1("%s() no edac_class error=%d\n", __func__, err); | ||
992 | goto fail_out; | ||
993 | } | ||
994 | |||
995 | /* Init the MC's kobject */ | ||
996 | mc_kset.kobj.parent = &edac_class->kset.kobj; | ||
997 | |||
998 | /* register the mc_kset */ | ||
999 | err = kset_register(&mc_kset); | ||
1000 | if (err) { | ||
1001 | debugf1("%s() Failed to register '.../edac/mc'\n", __func__); | ||
1002 | goto fail_out; | ||
1003 | } | ||
1004 | |||
1005 | debugf1("%s() Registered '.../edac/mc' kobject\n", __func__); | ||
1006 | |||
1007 | return 0; | ||
1008 | |||
1009 | |||
1010 | /* error unwind stack */ | ||
1011 | fail_out: | ||
1012 | return err; | ||
1013 | } | ||
1014 | |||
1015 | /* | ||
1016 | * edac_sysfs_teardown_mc_kset | ||
1017 | * | ||
1018 | * deconstruct the mc_ket for memory controllers | ||
1019 | */ | ||
1020 | void edac_sysfs_teardown_mc_kset(void) | ||
1021 | { | ||
1022 | kset_unregister(&mc_kset); | ||
1023 | } | ||
1024 | |||
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 07bd16564780..fc32bbb9405e 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c | |||
@@ -14,11 +14,11 @@ | |||
14 | #include "edac_core.h" | 14 | #include "edac_core.h" |
15 | #include "edac_module.h" | 15 | #include "edac_module.h" |
16 | 16 | ||
17 | #define EDAC_MC_VERSION "Ver: 2.0.4 " __DATE__ | 17 | #define EDAC_MC_VERSION "Ver: 2.0.5 " __DATE__ |
18 | 18 | ||
19 | #ifdef CONFIG_EDAC_DEBUG | 19 | #ifdef CONFIG_EDAC_DEBUG |
20 | /* Values of 0 to 4 will generate output */ | 20 | /* Values of 0 to 4 will generate output */ |
21 | int edac_debug_level = 1; | 21 | int edac_debug_level = 2; |
22 | EXPORT_SYMBOL_GPL(edac_debug_level); | 22 | EXPORT_SYMBOL_GPL(edac_debug_level); |
23 | #endif | 23 | #endif |
24 | 24 | ||
@@ -153,7 +153,7 @@ static int __init edac_init(void) | |||
153 | edac_pci_clear_parity_errors(); | 153 | edac_pci_clear_parity_errors(); |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * perform the registration of the /sys/devices/system/edac object | 156 | * perform the registration of the /sys/devices/system/edac class object |
157 | */ | 157 | */ |
158 | if (edac_register_sysfs_edac_name()) { | 158 | if (edac_register_sysfs_edac_name()) { |
159 | edac_printk(KERN_ERR, EDAC_MC, | 159 | edac_printk(KERN_ERR, EDAC_MC, |
@@ -162,29 +162,29 @@ static int __init edac_init(void) | |||
162 | goto error; | 162 | goto error; |
163 | } | 163 | } |
164 | 164 | ||
165 | /* Create the MC sysfs entries, must be first | 165 | /* |
166 | * now set up the mc_kset under the edac class object | ||
166 | */ | 167 | */ |
167 | if (edac_sysfs_memctrl_setup()) { | 168 | err = edac_sysfs_setup_mc_kset(); |
168 | edac_printk(KERN_ERR, EDAC_MC, | 169 | if (err) |
169 | "Error initializing sysfs code\n"); | 170 | goto sysfs_setup_fail; |
170 | err = -ENODEV; | ||
171 | goto error_sysfs; | ||
172 | } | ||
173 | 171 | ||
174 | /* Setup/Initialize the edac_device system */ | 172 | /* Setup/Initialize the workq for this core */ |
175 | err = edac_workqueue_setup(); | 173 | err = edac_workqueue_setup(); |
176 | if (err) { | 174 | if (err) { |
177 | edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n"); | 175 | edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n"); |
178 | goto error_mem; | 176 | goto workq_fail; |
179 | } | 177 | } |
180 | 178 | ||
181 | return 0; | 179 | return 0; |
182 | 180 | ||
183 | /* Error teardown stack */ | 181 | /* Error teardown stack */ |
184 | error_mem: | 182 | workq_fail: |
185 | edac_sysfs_memctrl_teardown(); | 183 | edac_sysfs_teardown_mc_kset(); |
186 | error_sysfs: | 184 | |
185 | sysfs_setup_fail: | ||
187 | edac_unregister_sysfs_edac_name(); | 186 | edac_unregister_sysfs_edac_name(); |
187 | |||
188 | error: | 188 | error: |
189 | return err; | 189 | return err; |
190 | } | 190 | } |
@@ -199,7 +199,7 @@ static void __exit edac_exit(void) | |||
199 | 199 | ||
200 | /* tear down the various subsystems */ | 200 | /* tear down the various subsystems */ |
201 | edac_workqueue_teardown(); | 201 | edac_workqueue_teardown(); |
202 | edac_sysfs_memctrl_teardown(); | 202 | edac_sysfs_teardown_mc_kset(); |
203 | edac_unregister_sysfs_edac_name(); | 203 | edac_unregister_sysfs_edac_name(); |
204 | } | 204 | } |
205 | 205 | ||
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 37a08aa87d3e..6368cc658fc6 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
@@ -18,11 +18,15 @@ | |||
18 | * INTERNAL EDAC MODULE: | 18 | * INTERNAL EDAC MODULE: |
19 | * EDAC memory controller sysfs create/remove functions | 19 | * EDAC memory controller sysfs create/remove functions |
20 | * and setup/teardown functions | 20 | * and setup/teardown functions |
21 | * | ||
22 | * edac_mc objects | ||
21 | */ | 23 | */ |
24 | extern int edac_sysfs_setup_mc_kset(void); | ||
25 | extern void edac_sysfs_teardown_mc_kset(void); | ||
26 | extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci); | ||
27 | extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci); | ||
22 | extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); | 28 | extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); |
23 | extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); | 29 | extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); |
24 | extern int edac_sysfs_memctrl_setup(void); | ||
25 | extern void edac_sysfs_memctrl_teardown(void); | ||
26 | extern void edac_check_mc_devices(void); | 30 | extern void edac_check_mc_devices(void); |
27 | extern int edac_get_log_ue(void); | 31 | extern int edac_get_log_ue(void); |
28 | extern int edac_get_log_ce(void); | 32 | extern int edac_get_log_ce(void); |