diff options
| -rw-r--r-- | drivers/edac/edac_core.h | 10 | ||||
| -rw-r--r-- | drivers/edac/edac_device.c | 37 | ||||
| -rw-r--r-- | drivers/edac/edac_device_sysfs.c | 341 | ||||
| -rw-r--r-- | drivers/edac/edac_module.h | 4 |
4 files changed, 277 insertions, 115 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index bd7f00cf2443..4e31ac438760 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h | |||
| @@ -337,6 +337,9 @@ struct mcidev_sysfs_attribute { | |||
| 337 | */ | 337 | */ |
| 338 | struct mem_ctl_info { | 338 | struct mem_ctl_info { |
| 339 | struct list_head link; /* for global list of mem_ctl_info structs */ | 339 | struct list_head link; /* for global list of mem_ctl_info structs */ |
| 340 | |||
| 341 | struct module *owner; /* Module owner of this control struct */ | ||
| 342 | |||
| 340 | unsigned long mtype_cap; /* memory types supported by mc */ | 343 | unsigned long mtype_cap; /* memory types supported by mc */ |
| 341 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ | 344 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ |
| 342 | unsigned long edac_cap; /* configuration capabilities - this is | 345 | unsigned long edac_cap; /* configuration capabilities - this is |
| @@ -510,7 +513,6 @@ struct edac_device_block { | |||
| 510 | 513 | ||
| 511 | /* edac sysfs device control */ | 514 | /* edac sysfs device control */ |
| 512 | struct kobject kobj; | 515 | struct kobject kobj; |
| 513 | struct completion kobj_complete; | ||
| 514 | }; | 516 | }; |
| 515 | 517 | ||
| 516 | /* device instance control structure */ | 518 | /* device instance control structure */ |
| @@ -525,7 +527,6 @@ struct edac_device_instance { | |||
| 525 | 527 | ||
| 526 | /* edac sysfs device control */ | 528 | /* edac sysfs device control */ |
| 527 | struct kobject kobj; | 529 | struct kobject kobj; |
| 528 | struct completion kobj_complete; | ||
| 529 | }; | 530 | }; |
| 530 | 531 | ||
| 531 | 532 | ||
| @@ -537,6 +538,8 @@ struct edac_device_ctl_info { | |||
| 537 | /* for global list of edac_device_ctl_info structs */ | 538 | /* for global list of edac_device_ctl_info structs */ |
| 538 | struct list_head link; | 539 | struct list_head link; |
| 539 | 540 | ||
| 541 | struct module *owner; /* Module owner of this control struct */ | ||
| 542 | |||
| 540 | int dev_idx; | 543 | int dev_idx; |
| 541 | 544 | ||
| 542 | /* Per instance controls for this edac_device */ | 545 | /* Per instance controls for this edac_device */ |
| @@ -587,7 +590,7 @@ struct edac_device_ctl_info { | |||
| 587 | * NMI handlers may be traversing list | 590 | * NMI handlers may be traversing list |
| 588 | */ | 591 | */ |
| 589 | struct rcu_head rcu; | 592 | struct rcu_head rcu; |
| 590 | struct completion complete; | 593 | struct completion removal_complete; |
| 591 | 594 | ||
| 592 | /* sysfs top name under 'edac' directory | 595 | /* sysfs top name under 'edac' directory |
| 593 | * and instance name: | 596 | * and instance name: |
| @@ -611,7 +614,6 @@ struct edac_device_ctl_info { | |||
| 611 | * device this structure controls | 614 | * device this structure controls |
| 612 | */ | 615 | */ |
| 613 | struct kobject kobj; | 616 | struct kobject kobj; |
| 614 | struct completion kobj_complete; | ||
| 615 | }; | 617 | }; |
| 616 | 618 | ||
| 617 | /* To get from the instance's wq to the beginning of the ctl structure */ | 619 | /* To get from the instance's wq to the beginning of the ctl structure */ |
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 6020da68cbef..173f4ba0f7c8 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c | |||
| @@ -48,6 +48,7 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) | |||
| 48 | } | 48 | } |
| 49 | #endif /* CONFIG_EDAC_DEBUG */ | 49 | #endif /* CONFIG_EDAC_DEBUG */ |
| 50 | 50 | ||
| 51 | |||
| 51 | /* | 52 | /* |
| 52 | * edac_device_alloc_ctl_info() | 53 | * edac_device_alloc_ctl_info() |
| 53 | * Allocate a new edac device control info structure | 54 | * Allocate a new edac device control info structure |
| @@ -78,6 +79,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( | |||
| 78 | unsigned count; | 79 | unsigned count; |
| 79 | unsigned instance, block, attr; | 80 | unsigned instance, block, attr; |
| 80 | void *pvt; | 81 | void *pvt; |
| 82 | int err; | ||
| 81 | 83 | ||
| 82 | debugf1("%s() instances=%d blocks=%d\n", | 84 | debugf1("%s() instances=%d blocks=%d\n", |
| 83 | __func__, nr_instances, nr_blocks); | 85 | __func__, nr_instances, nr_blocks); |
| @@ -208,6 +210,22 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( | |||
| 208 | /* Mark this instance as merely ALLOCATED */ | 210 | /* Mark this instance as merely ALLOCATED */ |
| 209 | dev_ctl->op_state = OP_ALLOC; | 211 | dev_ctl->op_state = OP_ALLOC; |
| 210 | 212 | ||
| 213 | /* | ||
| 214 | * Initialize the 'root' kobj for the edac_device controller | ||
| 215 | */ | ||
| 216 | err = edac_device_register_sysfs_main_kobj(dev_ctl); | ||
| 217 | if (err) { | ||
| 218 | kfree(dev_ctl); | ||
| 219 | return NULL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* at this point, the root kobj is valid, and in order to | ||
| 223 | * 'free' the object, then the function: | ||
| 224 | * edac_device_unregister_sysfs_main_kobj() must be called | ||
| 225 | * which will perform kobj unregistration and the actual free | ||
| 226 | * will occur during the kobject callback operation | ||
| 227 | */ | ||
| 228 | |||
| 211 | return dev_ctl; | 229 | return dev_ctl; |
| 212 | } | 230 | } |
| 213 | EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); | 231 | EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); |
| @@ -219,7 +237,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); | |||
| 219 | */ | 237 | */ |
| 220 | void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) | 238 | void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) |
| 221 | { | 239 | { |
| 222 | kfree(ctl_info); | 240 | edac_device_unregister_sysfs_main_kobj(ctl_info); |
| 223 | } | 241 | } |
| 224 | EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); | 242 | EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); |
| 225 | 243 | ||
| @@ -315,22 +333,23 @@ static void complete_edac_device_list_del(struct rcu_head *head) | |||
| 315 | 333 | ||
| 316 | edac_dev = container_of(head, struct edac_device_ctl_info, rcu); | 334 | edac_dev = container_of(head, struct edac_device_ctl_info, rcu); |
| 317 | INIT_LIST_HEAD(&edac_dev->link); | 335 | INIT_LIST_HEAD(&edac_dev->link); |
| 318 | complete(&edac_dev->complete); | 336 | complete(&edac_dev->removal_complete); |
| 319 | } | 337 | } |
| 320 | 338 | ||
| 321 | /* | 339 | /* |
| 322 | * del_edac_device_from_global_list | 340 | * del_edac_device_from_global_list |
| 323 | * | 341 | * |
| 324 | * remove the RCU, setup for a callback call, then wait for the | 342 | * remove the RCU, setup for a callback call, |
| 325 | * callback to occur | 343 | * then wait for the callback to occur |
| 326 | */ | 344 | */ |
| 327 | static void del_edac_device_from_global_list(struct edac_device_ctl_info | 345 | static void del_edac_device_from_global_list(struct edac_device_ctl_info |
| 328 | *edac_device) | 346 | *edac_device) |
| 329 | { | 347 | { |
| 330 | list_del_rcu(&edac_device->link); | 348 | list_del_rcu(&edac_device->link); |
| 331 | init_completion(&edac_device->complete); | 349 | |
| 350 | init_completion(&edac_device->removal_complete); | ||
| 332 | call_rcu(&edac_device->rcu, complete_edac_device_list_del); | 351 | call_rcu(&edac_device->rcu, complete_edac_device_list_del); |
| 333 | wait_for_completion(&edac_device->complete); | 352 | wait_for_completion(&edac_device->removal_complete); |
| 334 | } | 353 | } |
| 335 | 354 | ||
| 336 | /** | 355 | /** |
| @@ -542,14 +561,14 @@ struct edac_device_ctl_info *edac_device_del_device(struct device *dev) | |||
| 542 | /* clear workq processing on this instance */ | 561 | /* clear workq processing on this instance */ |
| 543 | edac_device_workq_teardown(edac_dev); | 562 | edac_device_workq_teardown(edac_dev); |
| 544 | 563 | ||
| 545 | /* Tear down the sysfs entries for this instance */ | ||
| 546 | edac_device_remove_sysfs(edac_dev); | ||
| 547 | |||
| 548 | /* deregister from global list */ | 564 | /* deregister from global list */ |
| 549 | del_edac_device_from_global_list(edac_dev); | 565 | del_edac_device_from_global_list(edac_dev); |
| 550 | 566 | ||
| 551 | mutex_unlock(&device_ctls_mutex); | 567 | mutex_unlock(&device_ctls_mutex); |
| 552 | 568 | ||
| 569 | /* Tear down the sysfs entries for this instance */ | ||
| 570 | edac_device_remove_sysfs(edac_dev); | ||
| 571 | |||
| 553 | edac_printk(KERN_INFO, EDAC_MC, | 572 | edac_printk(KERN_INFO, EDAC_MC, |
| 554 | "Removed device %d for %s %s: DEV %s\n", | 573 | "Removed device %d for %s %s: DEV %s\n", |
| 555 | edac_dev->dev_idx, | 574 | edac_dev->dev_idx, |
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 235b4c79355d..52769ae69bd2 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * file for managing the edac_device class of devices for EDAC | 2 | * file for managing the edac_device class of devices for EDAC |
| 3 | * | 3 | * |
| 4 | * (C) 2007 SoftwareBitMaker(http://www.softwarebitmaker.com) | 4 | * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com) |
| 5 | * | ||
| 5 | * This file may be distributed under the terms of the | 6 | * This file may be distributed under the terms of the |
| 6 | * GNU General Public License. | 7 | * GNU General Public License. |
| 7 | * | 8 | * |
| @@ -10,6 +11,7 @@ | |||
| 10 | */ | 11 | */ |
| 11 | 12 | ||
| 12 | #include <linux/ctype.h> | 13 | #include <linux/ctype.h> |
| 14 | #include <linux/module.h> | ||
| 13 | 15 | ||
| 14 | #include "edac_core.h" | 16 | #include "edac_core.h" |
| 15 | #include "edac_module.h" | 17 | #include "edac_module.h" |
| @@ -19,7 +21,6 @@ | |||
| 19 | #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj) | 21 | #define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj) |
| 20 | #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr) | 22 | #define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr) |
| 21 | 23 | ||
| 22 | /************************** edac_device sysfs code and data **************/ | ||
| 23 | 24 | ||
| 24 | /* | 25 | /* |
| 25 | * Set of edac_device_ctl_info attribute store/show functions | 26 | * Set of edac_device_ctl_info attribute store/show functions |
| @@ -103,8 +104,8 @@ static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info | |||
| 103 | /* edac_device_ctl_info specific attribute structure */ | 104 | /* edac_device_ctl_info specific attribute structure */ |
| 104 | struct ctl_info_attribute { | 105 | struct ctl_info_attribute { |
| 105 | struct attribute attr; | 106 | struct attribute attr; |
| 106 | ssize_t(*show) (struct edac_device_ctl_info *, char *); | 107 | ssize_t(*show) (struct edac_device_ctl_info *, char *); |
| 107 | ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t); | 108 | ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t); |
| 108 | }; | 109 | }; |
| 109 | 110 | ||
| 110 | #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj) | 111 | #define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj) |
| @@ -168,45 +169,76 @@ static struct ctl_info_attribute *device_ctrl_attr[] = { | |||
| 168 | NULL, | 169 | NULL, |
| 169 | }; | 170 | }; |
| 170 | 171 | ||
| 171 | /* Main DEVICE kobject release() function */ | 172 | /* |
| 173 | * edac_device_ctrl_master_release | ||
| 174 | * | ||
| 175 | * called when the reference count for the 'main' kobj | ||
| 176 | * for a edac_device control struct reaches zero | ||
| 177 | * | ||
| 178 | * Reference count model: | ||
| 179 | * One 'main' kobject for each control structure allocated. | ||
| 180 | * That main kobj is initially set to one AND | ||
| 181 | * the reference count for the EDAC 'core' module is | ||
| 182 | * bumped by one, thus added 'keep in memory' dependency. | ||
| 183 | * | ||
| 184 | * Each new internal kobj (in instances and blocks) then | ||
| 185 | * bumps the 'main' kobject. | ||
| 186 | * | ||
| 187 | * When they are released their release functions decrement | ||
| 188 | * the 'main' kobj. | ||
| 189 | * | ||
| 190 | * When the main kobj reaches zero (0) then THIS function | ||
| 191 | * is called which then decrements the EDAC 'core' module. | ||
| 192 | * When the module reference count reaches zero then the | ||
| 193 | * module no longer has dependency on keeping the release | ||
| 194 | * function code in memory and module can be unloaded. | ||
| 195 | * | ||
| 196 | * This will support several control objects as well, each | ||
| 197 | * with its own 'main' kobj. | ||
| 198 | */ | ||
| 172 | static void edac_device_ctrl_master_release(struct kobject *kobj) | 199 | static void edac_device_ctrl_master_release(struct kobject *kobj) |
| 173 | { | 200 | { |
| 174 | struct edac_device_ctl_info *edac_dev; | 201 | struct edac_device_ctl_info *edac_dev = to_edacdev(kobj); |
| 175 | 202 | ||
| 176 | edac_dev = to_edacdev(kobj); | 203 | debugf1("%s() control index=%d\n", __func__, edac_dev->dev_idx); |
| 177 | 204 | ||
| 178 | debugf1("%s()\n", __func__); | 205 | /* decrement the EDAC CORE module ref count */ |
| 179 | complete(&edac_dev->kobj_complete); | 206 | module_put(edac_dev->owner); |
| 207 | |||
| 208 | /* free the control struct containing the 'main' kobj | ||
| 209 | * passed in to this routine | ||
| 210 | */ | ||
| 211 | kfree(edac_dev); | ||
| 180 | } | 212 | } |
| 181 | 213 | ||
| 214 | /* ktype for the main (master) kobject */ | ||
| 182 | static struct kobj_type ktype_device_ctrl = { | 215 | static struct kobj_type ktype_device_ctrl = { |
| 183 | .release = edac_device_ctrl_master_release, | 216 | .release = edac_device_ctrl_master_release, |
| 184 | .sysfs_ops = &device_ctl_info_ops, | 217 | .sysfs_ops = &device_ctl_info_ops, |
| 185 | .default_attrs = (struct attribute **)device_ctrl_attr, | 218 | .default_attrs = (struct attribute **)device_ctrl_attr, |
| 186 | }; | 219 | }; |
| 187 | 220 | ||
| 188 | /**************** edac_device main kobj ctor/dtor code *********************/ | ||
| 189 | |||
| 190 | /* | 221 | /* |
| 191 | * edac_device_register_main_kobj | 222 | * edac_device_register_sysfs_main_kobj |
| 192 | * | 223 | * |
| 193 | * perform the high level setup for the new edac_device instance | 224 | * perform the high level setup for the new edac_device instance |
| 194 | * | 225 | * |
| 195 | * Return: 0 SUCCESS | 226 | * Return: 0 SUCCESS |
| 196 | * !0 FAILURE | 227 | * !0 FAILURE |
| 197 | */ | 228 | */ |
| 198 | static int edac_device_register_main_kobj(struct edac_device_ctl_info *edac_dev) | 229 | int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) |
| 199 | { | 230 | { |
| 200 | int err = 0; | ||
| 201 | struct sysdev_class *edac_class; | 231 | struct sysdev_class *edac_class; |
| 232 | int err; | ||
| 202 | 233 | ||
| 203 | debugf1("%s()\n", __func__); | 234 | debugf1("%s()\n", __func__); |
| 204 | 235 | ||
| 205 | /* get the /sys/devices/system/edac reference */ | 236 | /* get the /sys/devices/system/edac reference */ |
| 206 | edac_class = edac_get_edac_class(); | 237 | edac_class = edac_get_edac_class(); |
| 207 | if (edac_class == NULL) { | 238 | if (edac_class == NULL) { |
| 208 | debugf1("%s() no edac_class error=%d\n", __func__, err); | 239 | debugf1("%s() no edac_class error\n", __func__); |
| 209 | return err; | 240 | err = -ENODEV; |
| 241 | goto err_out; | ||
| 210 | } | 242 | } |
| 211 | 243 | ||
| 212 | /* Point to the 'edac_class' this instance 'reports' to */ | 244 | /* Point to the 'edac_class' this instance 'reports' to */ |
| @@ -223,42 +255,65 @@ static int edac_device_register_main_kobj(struct edac_device_ctl_info *edac_dev) | |||
| 223 | debugf1("%s() set name of kobject to: %s\n", __func__, edac_dev->name); | 255 | debugf1("%s() set name of kobject to: %s\n", __func__, edac_dev->name); |
| 224 | err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); | 256 | err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); |
| 225 | if (err) | 257 | if (err) |
| 226 | return err; | 258 | goto err_out; |
| 259 | |||
| 260 | /* Record which module 'owns' this control structure | ||
| 261 | * and bump the ref count of the module | ||
| 262 | */ | ||
| 263 | edac_dev->owner = THIS_MODULE; | ||
| 264 | |||
| 265 | if (!try_module_get(edac_dev->owner)) { | ||
| 266 | err = -ENODEV; | ||
| 267 | goto err_out; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* register */ | ||
| 227 | err = kobject_register(&edac_dev->kobj); | 271 | err = kobject_register(&edac_dev->kobj); |
| 228 | if (err) { | 272 | if (err) { |
| 229 | debugf1("%s()Failed to register '.../edac/%s'\n", | 273 | debugf1("%s()Failed to register '.../edac/%s'\n", |
| 230 | __func__, edac_dev->name); | 274 | __func__, edac_dev->name); |
| 231 | return err; | 275 | goto err_kobj_reg; |
| 232 | } | 276 | } |
| 233 | 277 | ||
| 278 | /* At this point, to 'free' the control struct, | ||
| 279 | * edac_device_unregister_sysfs_main_kobj() must be used | ||
| 280 | */ | ||
| 281 | |||
| 234 | debugf1("%s() Registered '.../edac/%s' kobject\n", | 282 | debugf1("%s() Registered '.../edac/%s' kobject\n", |
| 235 | __func__, edac_dev->name); | 283 | __func__, edac_dev->name); |
| 236 | 284 | ||
| 237 | return 0; | 285 | return 0; |
| 286 | |||
| 287 | /* Error exit stack */ | ||
| 288 | err_kobj_reg: | ||
| 289 | module_put(edac_dev->owner); | ||
| 290 | |||
| 291 | err_out: | ||
| 292 | return err; | ||
| 238 | } | 293 | } |
| 239 | 294 | ||
| 240 | /* | 295 | /* |
| 241 | * edac_device_unregister_main_kobj: | 296 | * edac_device_unregister_sysfs_main_kobj: |
| 242 | * the '..../edac/<name>' kobject | 297 | * the '..../edac/<name>' kobject |
| 243 | */ | 298 | */ |
| 244 | static void edac_device_unregister_main_kobj(struct edac_device_ctl_info | 299 | void edac_device_unregister_sysfs_main_kobj( |
| 245 | *edac_dev) | 300 | struct edac_device_ctl_info *edac_dev) |
| 246 | { | 301 | { |
| 247 | debugf0("%s()\n", __func__); | 302 | debugf0("%s()\n", __func__); |
| 248 | debugf1("%s() name of kobject is: %s\n", | 303 | debugf1("%s() name of kobject is: %s\n", |
| 249 | __func__, kobject_name(&edac_dev->kobj)); | 304 | __func__, kobject_name(&edac_dev->kobj)); |
| 250 | 305 | ||
| 251 | init_completion(&edac_dev->kobj_complete); | ||
| 252 | |||
| 253 | /* | 306 | /* |
| 254 | * Unregister the edac device's kobject and | 307 | * Unregister the edac device's kobject and |
| 255 | * wait for reference count to reach 0. | 308 | * allow for reference count to reach 0 at which point |
| 309 | * the callback will be called to: | ||
| 310 | * a) module_put() this module | ||
| 311 | * b) 'kfree' the memory | ||
| 256 | */ | 312 | */ |
| 257 | kobject_unregister(&edac_dev->kobj); | 313 | kobject_unregister(&edac_dev->kobj); |
| 258 | wait_for_completion(&edac_dev->kobj_complete); | ||
| 259 | } | 314 | } |
| 260 | 315 | ||
| 261 | /*************** edac_dev -> instance information ***********/ | 316 | /* edac_dev -> instance information */ |
| 262 | 317 | ||
| 263 | /* | 318 | /* |
| 264 | * Set of low-level instance attribute show functions | 319 | * Set of low-level instance attribute show functions |
| @@ -285,8 +340,11 @@ static void edac_device_ctrl_instance_release(struct kobject *kobj) | |||
| 285 | 340 | ||
| 286 | debugf1("%s()\n", __func__); | 341 | debugf1("%s()\n", __func__); |
| 287 | 342 | ||
| 343 | /* map from this kobj to the main control struct | ||
| 344 | * and then dec the main kobj count | ||
| 345 | */ | ||
| 288 | instance = to_instance(kobj); | 346 | instance = to_instance(kobj); |
| 289 | complete(&instance->kobj_complete); | 347 | kobject_put(&instance->ctl->kobj); |
| 290 | } | 348 | } |
| 291 | 349 | ||
| 292 | /* instance specific attribute structure */ | 350 | /* instance specific attribute structure */ |
| @@ -356,7 +414,7 @@ static struct kobj_type ktype_instance_ctrl = { | |||
| 356 | .default_attrs = (struct attribute **)device_instance_attr, | 414 | .default_attrs = (struct attribute **)device_instance_attr, |
| 357 | }; | 415 | }; |
| 358 | 416 | ||
| 359 | /*************** edac_dev -> instance -> block information *********/ | 417 | /* edac_dev -> instance -> block information */ |
| 360 | 418 | ||
| 361 | /* | 419 | /* |
| 362 | * Set of low-level block attribute show functions | 420 | * Set of low-level block attribute show functions |
| @@ -381,8 +439,13 @@ static void edac_device_ctrl_block_release(struct kobject *kobj) | |||
| 381 | 439 | ||
| 382 | debugf1("%s()\n", __func__); | 440 | debugf1("%s()\n", __func__); |
| 383 | 441 | ||
| 442 | /* get the container of the kobj */ | ||
| 384 | block = to_block(kobj); | 443 | block = to_block(kobj); |
| 385 | complete(&block->kobj_complete); | 444 | |
| 445 | /* map from 'block kobj' to 'block->instance->controller->main_kobj' | ||
| 446 | * now 'release' the block kobject | ||
| 447 | */ | ||
| 448 | kobject_put(&block->instance->ctl->kobj); | ||
| 386 | } | 449 | } |
| 387 | 450 | ||
| 388 | /* block specific attribute structure */ | 451 | /* block specific attribute structure */ |
| @@ -447,49 +510,60 @@ static struct kobj_type ktype_block_ctrl = { | |||
| 447 | .default_attrs = (struct attribute **)device_block_attr, | 510 | .default_attrs = (struct attribute **)device_block_attr, |
| 448 | }; | 511 | }; |
| 449 | 512 | ||
| 450 | /************** block ctor/dtor code ************/ | 513 | /* block ctor/dtor code */ |
| 451 | 514 | ||
| 452 | /* | 515 | /* |
| 453 | * edac_device_create_block | 516 | * edac_device_create_block |
| 454 | */ | 517 | */ |
| 455 | static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, | 518 | static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, |
| 456 | struct edac_device_instance *instance, | 519 | struct edac_device_instance *instance, |
| 457 | int idx) | 520 | struct edac_device_block *block) |
| 458 | { | 521 | { |
| 459 | int i; | 522 | int i; |
| 460 | int err; | 523 | int err; |
| 461 | struct edac_device_block *block; | ||
| 462 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; | 524 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; |
| 525 | struct kobject *main_kobj; | ||
| 463 | 526 | ||
| 464 | block = &instance->blocks[idx]; | 527 | debugf1("%s() Instance '%s' block '%s'\n", |
| 465 | 528 | __func__, instance->name, block->name); | |
| 466 | debugf1("%s() Instance '%s' block[%d] '%s'\n", | ||
| 467 | __func__, instance->name, idx, block->name); | ||
| 468 | 529 | ||
| 469 | /* init this block's kobject */ | 530 | /* init this block's kobject */ |
| 470 | memset(&block->kobj, 0, sizeof(struct kobject)); | 531 | memset(&block->kobj, 0, sizeof(struct kobject)); |
| 471 | block->kobj.parent = &instance->kobj; | 532 | block->kobj.parent = &instance->kobj; |
| 472 | block->kobj.ktype = &ktype_block_ctrl; | 533 | block->kobj.ktype = &ktype_block_ctrl; |
| 534 | block->instance = instance; | ||
| 473 | 535 | ||
| 474 | err = kobject_set_name(&block->kobj, "%s", block->name); | 536 | err = kobject_set_name(&block->kobj, "%s", block->name); |
| 475 | if (err) | 537 | if (err) |
| 476 | return err; | 538 | return err; |
| 477 | 539 | ||
| 540 | /* bump the main kobject's reference count for this controller | ||
| 541 | * and this instance is dependant on the main | ||
| 542 | */ | ||
| 543 | main_kobj = kobject_get(&edac_dev->kobj); | ||
| 544 | if (!main_kobj) { | ||
| 545 | err = -ENODEV; | ||
| 546 | goto err_out; | ||
| 547 | } | ||
| 548 | |||
| 549 | /* Add this block's kobject */ | ||
| 478 | err = kobject_register(&block->kobj); | 550 | err = kobject_register(&block->kobj); |
| 479 | if (err) { | 551 | if (err) { |
| 480 | debugf1("%s()Failed to register instance '%s'\n", | 552 | debugf1("%s() Failed to register instance '%s'\n", |
| 481 | __func__, block->name); | 553 | __func__, block->name); |
| 482 | return err; | 554 | kobject_put(main_kobj); |
| 555 | err = -ENODEV; | ||
| 556 | goto err_out; | ||
| 483 | } | 557 | } |
| 484 | 558 | ||
| 485 | /* If there are driver level block attributes, then added them | 559 | /* If there are driver level block attributes, then added them |
| 486 | * to the block kobject | 560 | * to the block kobject |
| 487 | */ | 561 | */ |
| 488 | sysfs_attrib = block->block_attributes; | 562 | sysfs_attrib = block->block_attributes; |
| 489 | if (sysfs_attrib != NULL) { | 563 | if (sysfs_attrib) { |
| 490 | for (i = 0; i < block->nr_attribs; i++) { | 564 | for (i = 0; i < block->nr_attribs; i++) { |
| 491 | err = sysfs_create_file(&block->kobj, | 565 | err = sysfs_create_file(&block->kobj, |
| 492 | (struct attribute *) &sysfs_attrib[i]); | 566 | (struct attribute *) sysfs_attrib); |
| 493 | if (err) | 567 | if (err) |
| 494 | goto err_on_attrib; | 568 | goto err_on_attrib; |
| 495 | 569 | ||
| @@ -499,30 +573,41 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, | |||
| 499 | 573 | ||
| 500 | return 0; | 574 | return 0; |
| 501 | 575 | ||
| 576 | /* Error unwind stack */ | ||
| 502 | err_on_attrib: | 577 | err_on_attrib: |
| 503 | kobject_unregister(&block->kobj); | 578 | kobject_unregister(&block->kobj); |
| 504 | 579 | ||
| 580 | err_out: | ||
| 505 | return err; | 581 | return err; |
| 506 | } | 582 | } |
| 507 | 583 | ||
| 508 | /* | 584 | /* |
| 509 | * edac_device_delete_block(edac_dev,j); | 585 | * edac_device_delete_block(edac_dev,block); |
| 510 | */ | 586 | */ |
| 511 | static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, | 587 | static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, |
| 512 | struct edac_device_instance *instance, | 588 | struct edac_device_block *block) |
| 513 | int idx) | ||
| 514 | { | 589 | { |
| 515 | struct edac_device_block *block; | 590 | struct edac_dev_sysfs_block_attribute *sysfs_attrib; |
| 591 | int i; | ||
| 516 | 592 | ||
| 517 | block = &instance->blocks[idx]; | 593 | /* if this block has 'attributes' then we need to iterate over the list |
| 594 | * and 'remove' the attributes on this block | ||
| 595 | */ | ||
| 596 | sysfs_attrib = block->block_attributes; | ||
| 597 | if (sysfs_attrib && block->nr_attribs) { | ||
| 598 | for (i = 0; i < block->nr_attribs; i++) { | ||
| 599 | sysfs_remove_file(&block->kobj, | ||
| 600 | (struct attribute *) sysfs_attrib); | ||
| 601 | } | ||
| 602 | } | ||
| 518 | 603 | ||
| 519 | /* unregister this block's kobject */ | 604 | /* unregister this block's kobject, SEE: |
| 520 | init_completion(&block->kobj_complete); | 605 | * edac_device_ctrl_block_release() callback operation |
| 606 | */ | ||
| 521 | kobject_unregister(&block->kobj); | 607 | kobject_unregister(&block->kobj); |
| 522 | wait_for_completion(&block->kobj_complete); | ||
| 523 | } | 608 | } |
| 524 | 609 | ||
| 525 | /************** instance ctor/dtor code ************/ | 610 | /* instance ctor/dtor code */ |
| 526 | 611 | ||
| 527 | /* | 612 | /* |
| 528 | * edac_device_create_instance | 613 | * edac_device_create_instance |
| @@ -534,6 +619,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
| 534 | int i, j; | 619 | int i, j; |
| 535 | int err; | 620 | int err; |
| 536 | struct edac_device_instance *instance; | 621 | struct edac_device_instance *instance; |
| 622 | struct kobject *main_kobj; | ||
| 537 | 623 | ||
| 538 | instance = &edac_dev->instances[idx]; | 624 | instance = &edac_dev->instances[idx]; |
| 539 | 625 | ||
| @@ -543,16 +629,28 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
| 543 | /* set this new device under the edac_device main kobject */ | 629 | /* set this new device under the edac_device main kobject */ |
| 544 | instance->kobj.parent = &edac_dev->kobj; | 630 | instance->kobj.parent = &edac_dev->kobj; |
| 545 | instance->kobj.ktype = &ktype_instance_ctrl; | 631 | instance->kobj.ktype = &ktype_instance_ctrl; |
| 632 | instance->ctl = edac_dev; | ||
| 546 | 633 | ||
| 547 | err = kobject_set_name(&instance->kobj, "%s", instance->name); | 634 | err = kobject_set_name(&instance->kobj, "%s", instance->name); |
| 548 | if (err) | 635 | if (err) |
| 549 | return err; | 636 | goto err_out; |
| 637 | |||
| 638 | /* bump the main kobject's reference count for this controller | ||
| 639 | * and this instance is dependant on the main | ||
| 640 | */ | ||
| 641 | main_kobj = kobject_get(&edac_dev->kobj); | ||
| 642 | if (!main_kobj) { | ||
| 643 | err = -ENODEV; | ||
| 644 | goto err_out; | ||
| 645 | } | ||
| 550 | 646 | ||
| 647 | /* Formally register this instance's kobject */ | ||
| 551 | err = kobject_register(&instance->kobj); | 648 | err = kobject_register(&instance->kobj); |
| 552 | if (err != 0) { | 649 | if (err != 0) { |
| 553 | debugf2("%s() Failed to register instance '%s'\n", | 650 | debugf2("%s() Failed to register instance '%s'\n", |
| 554 | __func__, instance->name); | 651 | __func__, instance->name); |
| 555 | return err; | 652 | kobject_put(main_kobj); |
| 653 | goto err_out; | ||
| 556 | } | 654 | } |
| 557 | 655 | ||
| 558 | debugf1("%s() now register '%d' blocks for instance %d\n", | 656 | debugf1("%s() now register '%d' blocks for instance %d\n", |
| @@ -560,11 +658,14 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
| 560 | 658 | ||
| 561 | /* register all blocks of this instance */ | 659 | /* register all blocks of this instance */ |
| 562 | for (i = 0; i < instance->nr_blocks; i++) { | 660 | for (i = 0; i < instance->nr_blocks; i++) { |
| 563 | err = edac_device_create_block(edac_dev, instance, i); | 661 | err = edac_device_create_block(edac_dev, instance, |
| 662 | &instance->blocks[i]); | ||
| 564 | if (err) { | 663 | if (err) { |
| 664 | /* If any fail, remove all previous ones */ | ||
| 565 | for (j = 0; j < i; j++) | 665 | for (j = 0; j < i; j++) |
| 566 | edac_device_delete_block(edac_dev, instance, j); | 666 | edac_device_delete_block(edac_dev, |
| 567 | return err; | 667 | &instance->blocks[j]); |
| 668 | goto err_release_instance_kobj; | ||
| 568 | } | 669 | } |
| 569 | } | 670 | } |
| 570 | 671 | ||
| @@ -572,6 +673,13 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
| 572 | __func__, idx, instance->name); | 673 | __func__, idx, instance->name); |
| 573 | 674 | ||
| 574 | return 0; | 675 | return 0; |
| 676 | |||
| 677 | /* error unwind stack */ | ||
| 678 | err_release_instance_kobj: | ||
| 679 | kobject_unregister(&instance->kobj); | ||
| 680 | |||
| 681 | err_out: | ||
| 682 | return err; | ||
| 575 | } | 683 | } |
| 576 | 684 | ||
| 577 | /* | 685 | /* |
| @@ -581,19 +689,19 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, | |||
| 581 | static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, | 689 | static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, |
| 582 | int idx) | 690 | int idx) |
| 583 | { | 691 | { |
| 584 | int i; | ||
| 585 | struct edac_device_instance *instance; | 692 | struct edac_device_instance *instance; |
| 693 | int i; | ||
| 586 | 694 | ||
| 587 | instance = &edac_dev->instances[idx]; | 695 | instance = &edac_dev->instances[idx]; |
| 588 | 696 | ||
| 589 | /* unregister all blocks in this instance */ | 697 | /* unregister all blocks in this instance */ |
| 590 | for (i = 0; i < instance->nr_blocks; i++) | 698 | for (i = 0; i < instance->nr_blocks; i++) |
| 591 | edac_device_delete_block(edac_dev, instance, i); | 699 | edac_device_delete_block(edac_dev, &instance->blocks[i]); |
| 592 | 700 | ||
| 593 | /* unregister this instance's kobject */ | 701 | /* unregister this instance's kobject, SEE: |
| 594 | init_completion(&instance->kobj_complete); | 702 | * edac_device_ctrl_instance_release() for callback operation |
| 703 | */ | ||
| 595 | kobject_unregister(&instance->kobj); | 704 | kobject_unregister(&instance->kobj); |
| 596 | wait_for_completion(&instance->kobj_complete); | ||
| 597 | } | 705 | } |
| 598 | 706 | ||
| 599 | /* | 707 | /* |
| @@ -635,39 +743,69 @@ static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev) | |||
| 635 | edac_device_delete_instance(edac_dev, i); | 743 | edac_device_delete_instance(edac_dev, i); |
| 636 | } | 744 | } |
| 637 | 745 | ||
| 638 | /******************* edac_dev sysfs ctor/dtor code *************/ | 746 | /* edac_dev sysfs ctor/dtor code */ |
| 639 | 747 | ||
| 640 | /* | 748 | /* |
| 641 | * edac_device_add_sysfs_attributes | 749 | * edac_device_add_main_sysfs_attributes |
| 642 | * add some attributes to this instance's main kobject | 750 | * add some attributes to this instance's main kobject |
| 643 | */ | 751 | */ |
| 644 | static int edac_device_add_sysfs_attributes( | 752 | static int edac_device_add_main_sysfs_attributes( |
| 645 | struct edac_device_ctl_info *edac_dev) | 753 | struct edac_device_ctl_info *edac_dev) |
| 646 | { | 754 | { |
| 647 | int err; | ||
| 648 | struct edac_dev_sysfs_attribute *sysfs_attrib; | 755 | struct edac_dev_sysfs_attribute *sysfs_attrib; |
| 756 | int err = 0; | ||
| 649 | 757 | ||
| 650 | /* point to the start of the array and iterate over it | ||
| 651 | * adding each attribute listed to this mci instance's kobject | ||
| 652 | */ | ||
| 653 | sysfs_attrib = edac_dev->sysfs_attributes; | 758 | sysfs_attrib = edac_dev->sysfs_attributes; |
| 654 | 759 | if (sysfs_attrib) { | |
| 655 | while (sysfs_attrib->attr.name != NULL) { | 760 | /* iterate over the array and create an attribute for each |
| 656 | err = sysfs_create_file(&edac_dev->kobj, | 761 | * entry in the list |
| 762 | */ | ||
| 763 | while (sysfs_attrib->attr.name != NULL) { | ||
| 764 | err = sysfs_create_file(&edac_dev->kobj, | ||
| 657 | (struct attribute*) sysfs_attrib); | 765 | (struct attribute*) sysfs_attrib); |
| 658 | if (err) | 766 | if (err) |
| 659 | return err; | 767 | goto err_out; |
| 660 | 768 | ||
| 661 | sysfs_attrib++; | 769 | sysfs_attrib++; |
| 770 | } | ||
| 662 | } | 771 | } |
| 663 | 772 | ||
| 664 | return 0; | 773 | err_out: |
| 774 | return err; | ||
| 775 | } | ||
| 776 | |||
| 777 | /* | ||
| 778 | * edac_device_remove_main_sysfs_attributes | ||
| 779 | * remove any attributes to this instance's main kobject | ||
| 780 | */ | ||
| 781 | static void edac_device_remove_main_sysfs_attributes( | ||
| 782 | struct edac_device_ctl_info *edac_dev) | ||
| 783 | { | ||
| 784 | struct edac_dev_sysfs_attribute *sysfs_attrib; | ||
| 785 | |||
| 786 | /* if there are main attributes, defined, remove them. First, | ||
| 787 | * point to the start of the array and iterate over it | ||
| 788 | * removing each attribute listed from this device's instance's kobject | ||
| 789 | */ | ||
| 790 | sysfs_attrib = edac_dev->sysfs_attributes; | ||
| 791 | if (sysfs_attrib) { | ||
| 792 | while (sysfs_attrib->attr.name != NULL) { | ||
| 793 | sysfs_remove_file(&edac_dev->kobj, | ||
| 794 | (struct attribute *) sysfs_attrib); | ||
| 795 | sysfs_attrib++; | ||
| 796 | } | ||
| 797 | } | ||
| 665 | } | 798 | } |
| 666 | 799 | ||
| 667 | /* | 800 | /* |
| 668 | * edac_device_create_sysfs() Constructor | 801 | * edac_device_create_sysfs() Constructor |
| 669 | * | 802 | * |
| 670 | * Create a new edac_device kobject instance, | 803 | * accept a created edac_device control structure |
| 804 | * and 'export' it to sysfs. The 'main' kobj should already have been | ||
| 805 | * created. 'instance' and 'block' kobjects should be registered | ||
| 806 | * along with any 'block' attributes from the low driver. In addition, | ||
| 807 | * the main attributes (if any) are connected to the main kobject of | ||
| 808 | * the control structure. | ||
| 671 | * | 809 | * |
| 672 | * Return: | 810 | * Return: |
| 673 | * 0 Success | 811 | * 0 Success |
| @@ -678,23 +816,13 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
| 678 | int err; | 816 | int err; |
| 679 | struct kobject *edac_kobj = &edac_dev->kobj; | 817 | struct kobject *edac_kobj = &edac_dev->kobj; |
| 680 | 818 | ||
| 681 | /* register this instance's main kobj with the edac class kobj */ | ||
| 682 | err = edac_device_register_main_kobj(edac_dev); | ||
| 683 | if (err) | ||
| 684 | return err; | ||
| 685 | |||
| 686 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); | 819 | debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx); |
| 687 | 820 | ||
| 688 | /* If the low level driver requests some sysfs entries | 821 | /* go create any main attributes callers wants */ |
| 689 | * then go create them here | 822 | err = edac_device_add_main_sysfs_attributes(edac_dev); |
| 690 | */ | 823 | if (err) { |
| 691 | if (edac_dev->sysfs_attributes != NULL) { | 824 | debugf0("%s() failed to add sysfs attribs\n", __func__); |
| 692 | err = edac_device_add_sysfs_attributes(edac_dev); | 825 | goto err_out; |
| 693 | if (err) { | ||
| 694 | debugf0("%s() failed to add sysfs attribs\n", | ||
| 695 | __func__); | ||
| 696 | goto err_unreg_object; | ||
| 697 | } | ||
| 698 | } | 826 | } |
| 699 | 827 | ||
| 700 | /* create a symlink from the edac device | 828 | /* create a symlink from the edac device |
| @@ -705,16 +833,23 @@ int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev) | |||
| 705 | if (err) { | 833 | if (err) { |
| 706 | debugf0("%s() sysfs_create_link() returned err= %d\n", | 834 | debugf0("%s() sysfs_create_link() returned err= %d\n", |
| 707 | __func__, err); | 835 | __func__, err); |
| 708 | goto err_unreg_object; | 836 | goto err_remove_main_attribs; |
| 709 | } | 837 | } |
| 710 | 838 | ||
| 711 | debugf0("%s() calling create-instances, idx=%d\n", | 839 | /* Create the first level instance directories |
| 712 | __func__, edac_dev->dev_idx); | 840 | * In turn, the nested blocks beneath the instances will |
| 713 | 841 | * be registered as well | |
| 714 | /* Create the first level instance directories */ | 842 | */ |
| 715 | err = edac_device_create_instances(edac_dev); | 843 | err = edac_device_create_instances(edac_dev); |
| 716 | if (err) | 844 | if (err) { |
| 845 | debugf0("%s() edac_device_create_instances() " | ||
| 846 | "returned err= %d\n", __func__, err); | ||
| 717 | goto err_remove_link; | 847 | goto err_remove_link; |
| 848 | } | ||
| 849 | |||
| 850 | |||
| 851 | debugf0("%s() calling create-instances, idx=%d\n", | ||
| 852 | __func__, edac_dev->dev_idx); | ||
| 718 | 853 | ||
| 719 | return 0; | 854 | return 0; |
| 720 | 855 | ||
| @@ -723,26 +858,28 @@ err_remove_link: | |||
| 723 | /* remove the sym link */ | 858 | /* remove the sym link */ |
| 724 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | 859 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); |
| 725 | 860 | ||
| 726 | err_unreg_object: | 861 | err_remove_main_attribs: |
| 727 | edac_device_unregister_main_kobj(edac_dev); | 862 | edac_device_remove_main_sysfs_attributes(edac_dev); |
| 728 | 863 | ||
| 864 | err_out: | ||
| 729 | return err; | 865 | return err; |
| 730 | } | 866 | } |
| 731 | 867 | ||
| 732 | /* | 868 | /* |
| 733 | * edac_device_remove_sysfs() destructor | 869 | * edac_device_remove_sysfs() destructor |
| 734 | * | 870 | * |
| 735 | * remove a edac_device instance | 871 | * given an edac_device struct, tear down the kobject resources |
| 736 | */ | 872 | */ |
| 737 | void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev) | 873 | void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev) |
| 738 | { | 874 | { |
| 739 | debugf0("%s()\n", __func__); | 875 | debugf0("%s()\n", __func__); |
| 740 | 876 | ||
| 741 | edac_device_delete_instances(edac_dev); | 877 | /* remove any main attributes for this device */ |
| 878 | edac_device_remove_main_sysfs_attributes(edac_dev); | ||
| 742 | 879 | ||
| 743 | /* remove the sym link */ | 880 | /* remove the device sym link */ |
| 744 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); | 881 | sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK); |
| 745 | 882 | ||
| 746 | /* unregister the instance's main kobj */ | 883 | /* walk the instance/block kobject tree, deconstructing it */ |
| 747 | edac_device_unregister_main_kobj(edac_dev); | 884 | edac_device_delete_instances(edac_dev); |
| 748 | } | 885 | } |
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 6368cc658fc6..a2134dfc3cc6 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
| @@ -37,6 +37,10 @@ extern int edac_mc_get_panic_on_ue(void); | |||
| 37 | extern int edac_get_poll_msec(void); | 37 | extern int edac_get_poll_msec(void); |
| 38 | extern int edac_mc_get_poll_msec(void); | 38 | extern int edac_mc_get_poll_msec(void); |
| 39 | 39 | ||
| 40 | extern int edac_device_register_sysfs_main_kobj( | ||
| 41 | struct edac_device_ctl_info *edac_dev); | ||
| 42 | extern void edac_device_unregister_sysfs_main_kobj( | ||
| 43 | struct edac_device_ctl_info *edac_dev); | ||
| 40 | extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); | 44 | extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); |
| 41 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); | 45 | extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev); |
| 42 | extern struct sysdev_class *edac_get_edac_class(void); | 46 | extern struct sysdev_class *edac_get_edac_class(void); |
