Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

EDAC/ghes: Make ghes_edac a proper module

Commit

dc4e8c07e9e2 ("ACPI: APEI: explicit init of HEST and GHES in apci_init()")

introduced a bug leading to ghes_edac_register() to be invoked before
edac_init(). Because at that time the bus "edac" hadn't been even
registered, this created sysfs nodes as /devices/mc0 instead of
/sys/devices/system/edac/mc/mc0 on an Ampere eMag server.

Fix this by turning ghes_edac into a proper module.

The list of GHES devices returned is not protected from being modified
concurrently but it is pretty static as it gets created only during GHES
init and latter is not a module so...

[ bp: Massage. ]

Fixes: dc4e8c07e9e2 ("ACPI: APEI: explicit init of HEST and GHES in apci_init()")
Co-developed-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Jia He <justin.he@arm.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/20221010023559.69655-5-justin.he@arm.com

authored by

Jia He and committed by
Borislav Petkov
802e7f1d 9057a3f7

+44 -30
-4
drivers/acpi/apei/ghes.c
··· 1392 1392 1393 1393 platform_set_drvdata(ghes_dev, ghes); 1394 1394 1395 - ghes_edac_register(ghes, &ghes_dev->dev); 1396 - 1397 1395 ghes->dev = &ghes_dev->dev; 1398 1396 1399 1397 mutex_lock(&ghes_devs_mutex); ··· 1459 1461 } 1460 1462 1461 1463 ghes_fini(ghes); 1462 - 1463 - ghes_edac_unregister(ghes); 1464 1464 1465 1465 mutex_lock(&ghes_devs_mutex); 1466 1466 list_del(&ghes->elist);
+2 -2
drivers/edac/Kconfig
··· 53 53 has been initialized. 54 54 55 55 config EDAC_GHES 56 - bool "Output ACPI APEI/GHES BIOS detected errors via EDAC" 57 - depends on ACPI_APEI_GHES && (EDAC=y) 56 + tristate "Output ACPI APEI/GHES BIOS detected errors via EDAC" 57 + depends on ACPI_APEI_GHES 58 58 select UEFI_CPER 59 59 help 60 60 Not all machines support hardware-driven error report. Some of those
+38 -2
drivers/edac/ghes_edac.c
··· 56 56 57 57 static bool system_scanned; 58 58 59 + static struct list_head *ghes_devs; 60 + 59 61 /* Memory Device - Type 17 of SMBIOS spec */ 60 62 struct memdev_dmi_entry { 61 63 u8 type; ··· 385 383 .priority = 0, 386 384 }; 387 385 388 - int ghes_edac_register(struct ghes *ghes, struct device *dev) 386 + static int ghes_edac_register(struct device *dev) 389 387 { 390 388 bool fake = false; 391 389 struct mem_ctl_info *mci; ··· 504 502 return rc; 505 503 } 506 504 507 - void ghes_edac_unregister(struct ghes *ghes) 505 + static void ghes_edac_unregister(struct ghes *ghes) 508 506 { 509 507 struct mem_ctl_info *mci; 510 508 unsigned long flags; ··· 537 535 unlock: 538 536 mutex_unlock(&ghes_reg_mutex); 539 537 } 538 + 539 + static int __init ghes_edac_init(void) 540 + { 541 + struct ghes *g, *g_tmp; 542 + 543 + ghes_devs = ghes_get_devices(); 544 + if (!ghes_devs) 545 + return -ENODEV; 546 + 547 + if (list_empty(ghes_devs)) { 548 + pr_info("GHES probing device list is empty"); 549 + return -ENODEV; 550 + } 551 + 552 + list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) { 553 + ghes_edac_register(g->dev); 554 + } 555 + 556 + return 0; 557 + } 558 + module_init(ghes_edac_init); 559 + 560 + static void __exit ghes_edac_exit(void) 561 + { 562 + struct ghes *g, *g_tmp; 563 + 564 + list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) { 565 + ghes_edac_unregister(g); 566 + } 567 + } 568 + module_exit(ghes_edac_exit); 569 + 570 + MODULE_LICENSE("GPL"); 571 + MODULE_DESCRIPTION("Output ACPI APEI/GHES BIOS detected errors via EDAC");
+4 -22
include/acpi/ghes.h
··· 71 71 * @nb: pointer to the notifier_block structure of the vendor record handler. 72 72 */ 73 73 void ghes_unregister_vendor_record_notifier(struct notifier_block *nb); 74 + 75 + struct list_head *ghes_get_devices(void); 76 + #else 77 + static inline struct list_head *ghes_get_devices(void) { return NULL; } 74 78 #endif 75 79 76 80 int ghes_estatus_pool_init(int num_ghes); 77 - 78 - /* From drivers/edac/ghes_edac.c */ 79 - 80 - #ifdef CONFIG_EDAC_GHES 81 - int ghes_edac_register(struct ghes *ghes, struct device *dev); 82 - 83 - void ghes_edac_unregister(struct ghes *ghes); 84 - 85 - struct list_head *ghes_get_devices(void); 86 - 87 - #else 88 - static inline int ghes_edac_register(struct ghes *ghes, struct device *dev) 89 - { 90 - return -ENODEV; 91 - } 92 - 93 - static inline void ghes_edac_unregister(struct ghes *ghes) 94 - { 95 - } 96 - 97 - static inline struct list_head *ghes_get_devices(void) { return NULL; } 98 - #endif 99 81 100 82 static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata) 101 83 {