aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/edac_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac/edac_device.c')
-rw-r--r--drivers/edac/edac_device.c37
1 files changed, 28 insertions, 9 deletions
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}
213EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); 231EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
@@ -219,7 +237,7 @@ EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
219 */ 237 */
220void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) 238void 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}
224EXPORT_SYMBOL_GPL(edac_device_free_ctl_info); 242EXPORT_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 */
327static void del_edac_device_from_global_list(struct edac_device_ctl_info 345static 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,