diff options
-rw-r--r-- | drivers/edac/edac_mc.c | 76 | ||||
-rw-r--r-- | drivers/edac/edac_mc.h | 9 |
2 files changed, 42 insertions, 43 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index e6ecc7da38a5..7ee9419234aa 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -139,6 +139,12 @@ static struct sysdev_class edac_class = { | |||
139 | static struct kobject edac_memctrl_kobj; | 139 | static struct kobject edac_memctrl_kobj; |
140 | static struct kobject edac_pci_kobj; | 140 | static struct kobject edac_pci_kobj; |
141 | 141 | ||
142 | /* We use these to wait for the reference counts on edac_memctrl_kobj and | ||
143 | * edac_pci_kobj to reach 0. | ||
144 | */ | ||
145 | static struct completion edac_memctrl_kobj_complete; | ||
146 | static struct completion edac_pci_kobj_complete; | ||
147 | |||
142 | /* | 148 | /* |
143 | * /sys/devices/system/edac/mc; | 149 | * /sys/devices/system/edac/mc; |
144 | * data structures and methods | 150 | * data structures and methods |
@@ -244,6 +250,7 @@ static struct memctrl_dev_attribute *memctrl_attr[] = { | |||
244 | static void edac_memctrl_master_release(struct kobject *kobj) | 250 | static void edac_memctrl_master_release(struct kobject *kobj) |
245 | { | 251 | { |
246 | debugf1("%s()\n", __func__); | 252 | debugf1("%s()\n", __func__); |
253 | complete(&edac_memctrl_kobj_complete); | ||
247 | } | 254 | } |
248 | 255 | ||
249 | static struct kobj_type ktype_memctrl = { | 256 | static struct kobj_type ktype_memctrl = { |
@@ -309,8 +316,12 @@ static void edac_sysfs_memctrl_teardown(void) | |||
309 | #ifndef DISABLE_EDAC_SYSFS | 316 | #ifndef DISABLE_EDAC_SYSFS |
310 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 317 | debugf0("MC: " __FILE__ ": %s()\n", __func__); |
311 | 318 | ||
312 | /* Unregister the MC's kobject */ | 319 | /* Unregister the MC's kobject and wait for reference count to reach |
320 | * 0. | ||
321 | */ | ||
322 | init_completion(&edac_memctrl_kobj_complete); | ||
313 | kobject_unregister(&edac_memctrl_kobj); | 323 | kobject_unregister(&edac_memctrl_kobj); |
324 | wait_for_completion(&edac_memctrl_kobj_complete); | ||
314 | 325 | ||
315 | /* Unregister the 'edac' object */ | 326 | /* Unregister the 'edac' object */ |
316 | sysdev_class_unregister(&edac_class); | 327 | sysdev_class_unregister(&edac_class); |
@@ -563,6 +574,7 @@ static struct edac_pci_dev_attribute *edac_pci_attr[] = { | |||
563 | static void edac_pci_release(struct kobject *kobj) | 574 | static void edac_pci_release(struct kobject *kobj) |
564 | { | 575 | { |
565 | debugf1("%s()\n", __func__); | 576 | debugf1("%s()\n", __func__); |
577 | complete(&edac_pci_kobj_complete); | ||
566 | } | 578 | } |
567 | 579 | ||
568 | static struct kobj_type ktype_edac_pci = { | 580 | static struct kobj_type ktype_edac_pci = { |
@@ -610,8 +622,9 @@ static void edac_sysfs_pci_teardown(void) | |||
610 | { | 622 | { |
611 | #ifndef DISABLE_EDAC_SYSFS | 623 | #ifndef DISABLE_EDAC_SYSFS |
612 | debugf0("%s()\n", __func__); | 624 | debugf0("%s()\n", __func__); |
613 | 625 | init_completion(&edac_pci_kobj_complete); | |
614 | kobject_unregister(&edac_pci_kobj); | 626 | kobject_unregister(&edac_pci_kobj); |
627 | wait_for_completion(&edac_pci_kobj_complete); | ||
615 | #endif | 628 | #endif |
616 | } | 629 | } |
617 | 630 | ||
@@ -800,7 +813,11 @@ static struct csrowdev_attribute *csrow_attr[] = { | |||
800 | /* No memory to release */ | 813 | /* No memory to release */ |
801 | static void edac_csrow_instance_release(struct kobject *kobj) | 814 | static void edac_csrow_instance_release(struct kobject *kobj) |
802 | { | 815 | { |
816 | struct csrow_info *cs; | ||
817 | |||
803 | debugf1("%s()\n", __func__); | 818 | debugf1("%s()\n", __func__); |
819 | cs = container_of(kobj, struct csrow_info, kobj); | ||
820 | complete(&cs->kobj_complete); | ||
804 | } | 821 | } |
805 | 822 | ||
806 | static struct kobj_type ktype_csrow = { | 823 | static struct kobj_type ktype_csrow = { |
@@ -1055,11 +1072,10 @@ static struct mcidev_attribute *mci_attr[] = { | |||
1055 | static void edac_mci_instance_release(struct kobject *kobj) | 1072 | static void edac_mci_instance_release(struct kobject *kobj) |
1056 | { | 1073 | { |
1057 | struct mem_ctl_info *mci; | 1074 | struct mem_ctl_info *mci; |
1058 | mci = container_of(kobj,struct mem_ctl_info,edac_mci_kobj); | ||
1059 | 1075 | ||
1060 | debugf0("%s() idx=%d calling kfree\n", __func__, mci->mc_idx); | 1076 | mci = to_mci(kobj); |
1061 | 1077 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | |
1062 | kfree(mci); | 1078 | complete(&mci->kobj_complete); |
1063 | } | 1079 | } |
1064 | 1080 | ||
1065 | static struct kobj_type ktype_mci = { | 1081 | static struct kobj_type ktype_mci = { |
@@ -1131,21 +1147,23 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
1131 | } | 1147 | } |
1132 | } | 1148 | } |
1133 | 1149 | ||
1134 | /* Mark this MCI instance as having sysfs entries */ | ||
1135 | mci->sysfs_active = MCI_SYSFS_ACTIVE; | ||
1136 | |||
1137 | return 0; | 1150 | return 0; |
1138 | 1151 | ||
1139 | 1152 | ||
1140 | /* CSROW error: backout what has already been registered, */ | 1153 | /* CSROW error: backout what has already been registered, */ |
1141 | fail1: | 1154 | fail1: |
1142 | for ( i--; i >= 0; i--) { | 1155 | for ( i--; i >= 0; i--) { |
1143 | if (csrow->nr_pages > 0) | 1156 | if (csrow->nr_pages > 0) { |
1157 | init_completion(&csrow->kobj_complete); | ||
1144 | kobject_unregister(&mci->csrows[i].kobj); | 1158 | kobject_unregister(&mci->csrows[i].kobj); |
1159 | wait_for_completion(&csrow->kobj_complete); | ||
1160 | } | ||
1145 | } | 1161 | } |
1146 | 1162 | ||
1147 | fail0: | 1163 | fail0: |
1164 | init_completion(&mci->kobj_complete); | ||
1148 | kobject_unregister(edac_mci_kobj); | 1165 | kobject_unregister(edac_mci_kobj); |
1166 | wait_for_completion(&mci->kobj_complete); | ||
1149 | 1167 | ||
1150 | return err; | 1168 | return err; |
1151 | } | 1169 | } |
@@ -1163,13 +1181,17 @@ static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
1163 | 1181 | ||
1164 | /* remove all csrow kobjects */ | 1182 | /* remove all csrow kobjects */ |
1165 | for (i = 0; i < mci->nr_csrows; i++) { | 1183 | for (i = 0; i < mci->nr_csrows; i++) { |
1166 | if (mci->csrows[i].nr_pages > 0) | 1184 | if (mci->csrows[i].nr_pages > 0) { |
1185 | init_completion(&mci->csrows[i].kobj_complete); | ||
1167 | kobject_unregister(&mci->csrows[i].kobj); | 1186 | kobject_unregister(&mci->csrows[i].kobj); |
1187 | wait_for_completion(&mci->csrows[i].kobj_complete); | ||
1188 | } | ||
1168 | } | 1189 | } |
1169 | 1190 | ||
1170 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | 1191 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); |
1171 | 1192 | init_completion(&mci->kobj_complete); | |
1172 | kobject_unregister(&mci->edac_mci_kobj); | 1193 | kobject_unregister(&mci->edac_mci_kobj); |
1194 | wait_for_completion(&mci->kobj_complete); | ||
1173 | #endif /* DISABLE_EDAC_SYSFS */ | 1195 | #endif /* DISABLE_EDAC_SYSFS */ |
1174 | } | 1196 | } |
1175 | 1197 | ||
@@ -1342,31 +1364,10 @@ EXPORT_SYMBOL(edac_mc_free); | |||
1342 | /** | 1364 | /** |
1343 | * edac_mc_free: Free a previously allocated 'mci' structure | 1365 | * edac_mc_free: Free a previously allocated 'mci' structure |
1344 | * @mci: pointer to a struct mem_ctl_info structure | 1366 | * @mci: pointer to a struct mem_ctl_info structure |
1345 | * | ||
1346 | * Free up a previously allocated mci structure | ||
1347 | * A MCI structure can be in 2 states after being allocated | ||
1348 | * by edac_mc_alloc(). | ||
1349 | * 1) Allocated in a MC driver's probe, but not yet committed | ||
1350 | * 2) Allocated and committed, by a call to edac_mc_add_mc() | ||
1351 | * edac_mc_add_mc() is the function that adds the sysfs entries | ||
1352 | * thus, this free function must determine which state the 'mci' | ||
1353 | * structure is in, then either free it directly or | ||
1354 | * perform kobject cleanup by calling edac_remove_sysfs_mci_device(). | ||
1355 | * | ||
1356 | * VOID Return | ||
1357 | */ | 1367 | */ |
1358 | void edac_mc_free(struct mem_ctl_info *mci) | 1368 | void edac_mc_free(struct mem_ctl_info *mci) |
1359 | { | 1369 | { |
1360 | /* only if sysfs entries for this mci instance exist | 1370 | kfree(mci); |
1361 | * do we remove them and defer the actual kfree via | ||
1362 | * the kobject 'release()' callback. | ||
1363 | * | ||
1364 | * Otherwise, do a straight kfree now. | ||
1365 | */ | ||
1366 | if (mci->sysfs_active == MCI_SYSFS_ACTIVE) | ||
1367 | edac_remove_sysfs_mci_device(mci); | ||
1368 | else | ||
1369 | kfree(mci); | ||
1370 | } | 1371 | } |
1371 | 1372 | ||
1372 | 1373 | ||
@@ -1456,7 +1457,8 @@ static void del_mc_from_global_list (struct mem_ctl_info *mci) | |||
1456 | EXPORT_SYMBOL(edac_mc_add_mc); | 1457 | EXPORT_SYMBOL(edac_mc_add_mc); |
1457 | 1458 | ||
1458 | /** | 1459 | /** |
1459 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list | 1460 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and |
1461 | * create sysfs entries associated with mci structure | ||
1460 | * @mci: pointer to the mci structure to be added to the list | 1462 | * @mci: pointer to the mci structure to be added to the list |
1461 | * | 1463 | * |
1462 | * Return: | 1464 | * Return: |
@@ -1516,7 +1518,8 @@ fail0: | |||
1516 | EXPORT_SYMBOL(edac_mc_del_mc); | 1518 | EXPORT_SYMBOL(edac_mc_del_mc); |
1517 | 1519 | ||
1518 | /** | 1520 | /** |
1519 | * edac_mc_del_mc: Remove the specified mci structure from global list | 1521 | * edac_mc_del_mc: Remove sysfs entries for specified mci structure and |
1522 | * remove mci structure from global list | ||
1520 | * @mci: Pointer to struct mem_ctl_info structure | 1523 | * @mci: Pointer to struct mem_ctl_info structure |
1521 | * | 1524 | * |
1522 | * Returns: | 1525 | * Returns: |
@@ -1528,6 +1531,7 @@ int edac_mc_del_mc(struct mem_ctl_info *mci) | |||
1528 | int rc = 1; | 1531 | int rc = 1; |
1529 | 1532 | ||
1530 | debugf0("MC%d: %s()\n", mci->mc_idx, __func__); | 1533 | debugf0("MC%d: %s()\n", mci->mc_idx, __func__); |
1534 | edac_remove_sysfs_mci_device(mci); | ||
1531 | down(&mem_ctls_mutex); | 1535 | down(&mem_ctls_mutex); |
1532 | del_mc_from_global_list(mci); | 1536 | del_mc_from_global_list(mci); |
1533 | edac_printk(KERN_INFO, EDAC_MC, | 1537 | edac_printk(KERN_INFO, EDAC_MC, |
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 0bcc3797c753..c9c1590db721 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h | |||
@@ -185,11 +185,6 @@ enum scrub_type { | |||
185 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) | 185 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) |
186 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) | 186 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) |
187 | 187 | ||
188 | enum mci_sysfs_status { | ||
189 | MCI_SYSFS_INACTIVE = 0, /* sysfs entries NOT registered */ | ||
190 | MCI_SYSFS_ACTIVE /* sysfs entries ARE registered */ | ||
191 | }; | ||
192 | |||
193 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ | 188 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ |
194 | 189 | ||
195 | /* | 190 | /* |
@@ -299,6 +294,7 @@ struct csrow_info { | |||
299 | struct mem_ctl_info *mci; /* the parent */ | 294 | struct mem_ctl_info *mci; /* the parent */ |
300 | 295 | ||
301 | struct kobject kobj; /* sysfs kobject for this csrow */ | 296 | struct kobject kobj; /* sysfs kobject for this csrow */ |
297 | struct completion kobj_complete; | ||
302 | 298 | ||
303 | /* FIXME the number of CHANNELs might need to become dynamic */ | 299 | /* FIXME the number of CHANNELs might need to become dynamic */ |
304 | u32 nr_channels; | 300 | u32 nr_channels; |
@@ -320,8 +316,6 @@ struct mem_ctl_info { | |||
320 | unsigned long scrub_cap; /* chipset scrub capabilities */ | 316 | unsigned long scrub_cap; /* chipset scrub capabilities */ |
321 | enum scrub_type scrub_mode; /* current scrub mode */ | 317 | enum scrub_type scrub_mode; /* current scrub mode */ |
322 | 318 | ||
323 | enum mci_sysfs_status sysfs_active; /* status of sysfs */ | ||
324 | |||
325 | /* pointer to edac checking routine */ | 319 | /* pointer to edac checking routine */ |
326 | void (*edac_check) (struct mem_ctl_info * mci); | 320 | void (*edac_check) (struct mem_ctl_info * mci); |
327 | /* | 321 | /* |
@@ -359,6 +353,7 @@ struct mem_ctl_info { | |||
359 | 353 | ||
360 | /* edac sysfs device control */ | 354 | /* edac sysfs device control */ |
361 | struct kobject edac_mci_kobj; | 355 | struct kobject edac_mci_kobj; |
356 | struct completion kobj_complete; | ||
362 | }; | 357 | }; |
363 | 358 | ||
364 | 359 | ||