From 2367dafd020539da039f614d7541f8d52cc3b540 Mon Sep 17 00:00:00 2001 From: Shuai Xue Date: Mon, 6 Nov 2023 17:39:56 +0800 Subject: [PATCH 1/7] ACPI: APEI: explicit init of HEST and GHES in apci_init() mainline inclusion from mainline-v5.18-rc1 commit dc4e8c07e9e2f69387579c49caca26ba239f7270 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=dc4e8c07e9e2f69387579c49caca26ba239f7270 ---------------------------------------------------------------------- From commit e147133a42cb ("ACPI / APEI: Make hest.c manage the estatus memory pool") was merged, ghes_init() relies on acpi_hest_init() to manage the estatus memory pool. On the other hand, ghes_init() relies on sdei_init() to detect the SDEI version and (un)register events. The dependencies are as follows: ghes_init() => acpi_hest_init() => acpi_bus_init() => acpi_init() ghes_init() => sdei_init() HEST is not PCI-specific and initcall ordering is implicit and not well-defined within a level. Based on above, remove acpi_hest_init() from acpi_pci_root_init() and convert ghes_init() and sdei_init() from initcalls to explicit calls in the following order: acpi_hest_init() ghes_init() sdei_init() Signed-off-by: Shuai Xue Signed-off-by: Rafael J. Wysocki Signed-off-by: Qian Zou --- drivers/acpi/apei/ghes.c | 19 ++++++++----------- drivers/acpi/bus.c | 2 ++ drivers/acpi/pci_root.c | 3 --- drivers/firmware/Kconfig | 1 + drivers/firmware/arm_sdei.c | 13 ++----------- include/acpi/apei.h | 4 +++- include/linux/arm_sdei.h | 2 ++ 7 files changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 650a8feda23b..6535b444ad7b 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1473,33 +1473,35 @@ static struct platform_driver ghes_platform_driver = { .remove = ghes_remove, }; -static int __init ghes_init(void) +void __init ghes_init(void) { int rc; + sdei_init(); + if (acpi_disabled) - return -ENODEV; + return; switch (hest_disable) { case HEST_NOT_FOUND: - return -ENODEV; + return; case HEST_DISABLED: pr_info(GHES_PFX "HEST is not enabled!\n"); - return -EINVAL; + return; default: break; } if (ghes_disable) { pr_info(GHES_PFX "GHES is not enabled!\n"); - return -EINVAL; + return; } ghes_nmi_init_cxt(); rc = platform_driver_register(&ghes_platform_driver); if (rc) - goto err; + return; rc = apei_osc_setup(); if (rc == 0 && osc_sb_apei_support_acked) @@ -1510,9 +1512,4 @@ static int __init ghes_init(void) pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n"); else pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); - - return 0; -err: - return rc; } -device_initcall(ghes_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 50a65ff16d5a..d8086d49ce6b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1286,6 +1286,8 @@ static int __init acpi_init(void) pci_mmcfg_late_init(); acpi_iort_init(); + acpi_hest_init(); + ghes_init(); acpi_scan_init(); acpi_ec_init(); acpi_debugfs_init(); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c12b5fb3e8fb..d972ea057a03 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -20,8 +20,6 @@ #include #include #include -#include /* for acpi_hest_init() */ - #include "internal.h" #define ACPI_PCI_ROOT_CLASS "pci_bridge" @@ -950,7 +948,6 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, void __init acpi_pci_root_init(void) { - acpi_hest_init(); if (acpi_pci_disabled) return; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index a34d4bfb27fe..a3996a6fc913 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -72,6 +72,7 @@ config ARM_SCPI_POWER_DOMAIN config ARM_SDE_INTERFACE bool "ARM Software Delegated Exception Interface (SDEI)" depends on ARM64 + depends on ACPI_APEI_GHES help The Software Delegated Exception Interface (SDEI) is an ARM standard for registering callbacks from the platform firmware diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index 8e9d565c24fe..0459e1d4446e 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -1081,14 +1081,14 @@ static bool __init sdei_present_acpi(void) return true; } -static int __init sdei_init(void) +void __init sdei_init(void) { struct platform_device *pdev; int ret; ret = platform_driver_register(&sdei_driver); if (ret || !sdei_present_acpi()) - return ret; + return; pdev = platform_device_register_simple(sdei_driver.driver.name, 0, NULL, 0); @@ -1098,17 +1098,8 @@ static int __init sdei_init(void) pr_info("Failed to register ACPI:SDEI platform device %d\n", ret); } - - return ret; } -/* - * On an ACPI system SDEI needs to be ready before HEST:GHES tries to register - * its events. ACPI is initialised from a subsys_initcall(), GHES is initialised - * by device_initcall(). We want to be called in the middle. - */ -subsys_initcall_sync(sdei_init); - int sdei_event_handler(struct pt_regs *regs, struct sdei_registered_event *arg) { diff --git a/include/acpi/apei.h b/include/acpi/apei.h index 680f80960c3d..a6ac2e8b72da 100644 --- a/include/acpi/apei.h +++ b/include/acpi/apei.h @@ -27,14 +27,16 @@ extern int hest_disable; extern int erst_disable; #ifdef CONFIG_ACPI_APEI_GHES extern bool ghes_disable; +void __init ghes_init(void); #else #define ghes_disable 1 +static inline void ghes_init(void) { } #endif #ifdef CONFIG_ACPI_APEI void __init acpi_hest_init(void); #else -static inline void acpi_hest_init(void) { return; } +static inline void acpi_hest_init(void) { } #endif typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h index f3027342c964..b1233196cd3c 100644 --- a/include/linux/arm_sdei.h +++ b/include/linux/arm_sdei.h @@ -51,9 +51,11 @@ int sdei_unregister_ghes(struct ghes *ghes); /* For use by arch code when CPU hotplug notifiers are not appropriate. */ int sdei_mask_local_cpu(void); int sdei_unmask_local_cpu(void); +void __init sdei_init(void); #else static inline int sdei_mask_local_cpu(void) { return 0; } static inline int sdei_unmask_local_cpu(void) { return 0; } +static inline void sdei_init(void) { } #endif /* CONFIG_ARM_SDE_INTERFACE */ -- Gitee From 760042e0cc4e5dc3c1ce15e4492a28dda8eb8187 Mon Sep 17 00:00:00 2001 From: Jia He Date: Mon, 6 Nov 2023 17:39:57 +0800 Subject: [PATCH 2/7] EDAC/ghes: Make ghes_edac a proper module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v6.2-rc1 commit 802e7f1dfed7cc7fb309995e0c4138f08977fdfc category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=802e7f1dfed7cc7fb309995e0c4138f08977fdfc ---------------------------------------------------------------------- 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 Signed-off-by: Borislav Petkov Signed-off-by: Jia He Signed-off-by: Borislav Petkov Link: https://lore.kernel.org/r/20221010023559.69655-5-justin.he@arm.com Signed-off-by: Qian Zou --- drivers/acpi/apei/ghes.c | 4 ---- drivers/edac/Kconfig | 4 ++-- drivers/edac/ghes_edac.c | 40 ++++++++++++++++++++++++++++++++++++++-- include/acpi/ghes.h | 20 ++------------------ 4 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 6535b444ad7b..15f908d198ca 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1392,8 +1392,6 @@ static int ghes_probe(struct platform_device *ghes_dev) platform_set_drvdata(ghes_dev, ghes); - ghes_edac_register(ghes, &ghes_dev->dev); - /* Handle any pending errors right away */ spin_lock_irqsave(&ghes_notify_lock_irq, flags); ghes_proc(ghes); @@ -1456,8 +1454,6 @@ static int ghes_remove(struct platform_device *ghes_dev) ghes_fini(ghes); - ghes_edac_unregister(ghes); - kfree(ghes); platform_set_drvdata(ghes_dev, NULL); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 7a47680d6f07..7366ea1d2eac 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -53,8 +53,8 @@ config EDAC_DECODE_MCE has been initialized. config EDAC_GHES - bool "Output ACPI APEI/GHES BIOS detected errors via EDAC" - depends on ACPI_APEI_GHES && (EDAC=y) + tristate "Output ACPI APEI/GHES BIOS detected errors via EDAC" + depends on ACPI_APEI_GHES help Not all machines support hardware-driven error report. Some of those provide a BIOS-driven error report mechanism via ACPI, using the diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index df5897c90bec..51c1c16cee6f 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -57,6 +57,8 @@ module_param(force_load, bool, 0); static bool system_scanned; +static struct list_head *ghes_devs; + /* Memory Device - Type 17 of SMBIOS spec */ struct memdev_dmi_entry { u8 type; @@ -510,7 +512,7 @@ static struct acpi_platform_list plat_list[] = { { } /* End */ }; -int ghes_edac_register(struct ghes *ghes, struct device *dev) +static int ghes_edac_register(struct device *dev) { bool fake = false; struct mem_ctl_info *mci; @@ -643,7 +645,7 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev) return rc; } -void ghes_edac_unregister(struct ghes *ghes) +static void ghes_edac_unregister(struct ghes *ghes) { struct mem_ctl_info *mci; unsigned long flags; @@ -677,3 +679,37 @@ void ghes_edac_unregister(struct ghes *ghes) unlock: mutex_unlock(&ghes_reg_mutex); } + +static int __init ghes_edac_init(void) +{ + struct ghes *g, *g_tmp; + + ghes_devs = ghes_get_devices(); + if (!ghes_devs) + return -ENODEV; + + if (list_empty(ghes_devs)) { + pr_info("GHES probing device list is empty"); + return -ENODEV; + } + + list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) { + ghes_edac_register(g->dev); + } + + return 0; +} +module_init(ghes_edac_init); + +static void __exit ghes_edac_exit(void) +{ + struct ghes *g, *g_tmp; + + list_for_each_entry_safe(g, g_tmp, ghes_devs, elist) { + ghes_edac_unregister(g); + } +} +module_exit(ghes_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Output ACPI APEI/GHES BIOS detected errors via EDAC"); diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 544d92789b34..f9cf7b8ac15c 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h @@ -71,33 +71,17 @@ int ghes_register_vendor_record_notifier(struct notifier_block *nb); void ghes_unregister_vendor_record_notifier(struct notifier_block *nb); #endif -int ghes_estatus_pool_init(unsigned int num_ghes); - -/* From drivers/edac/ghes_edac.c */ - #ifdef CONFIG_EDAC_GHES void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err); - -int ghes_edac_register(struct ghes *ghes, struct device *dev); - -void ghes_edac_unregister(struct ghes *ghes); - #else static inline void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err) { } - -static inline int ghes_edac_register(struct ghes *ghes, struct device *dev) -{ - return -ENODEV; -} - -static inline void ghes_edac_unregister(struct ghes *ghes) -{ -} #endif +int ghes_estatus_pool_init(unsigned int num_ghes); + static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata) { return gdata->revision >> 8; -- Gitee From d3d3dcb6b91a0e902c4b110ba1b1df530e66fe9d Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Mon, 6 Nov 2023 17:39:58 +0800 Subject: [PATCH 3/7] ACPI: tables: Add AGDI to the list of known table signatures mainline inclusion from mainline-v5.18-rc1 commit e86801b0ff1c5c6d1f78232f7e3b52c0b0631560 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e86801b0ff1c5c6d1f78232f7e3b52c0b0631560 ---------------------------------------------------------------------- Add AGDI to the list of known ACPI table signatures to allow the kernel to recognize it when upgrading tables via initrd. Signed-off-by: Ilkka Koskinen Reviewed-by: Russell King (Oracle) Signed-off-by: Rafael J. Wysocki Signed-off-by: Qian Zou --- drivers/acpi/tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 5943ae4f76bb..3635c7be6e55 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -509,7 +509,7 @@ static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = { ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, - ACPI_SIG_NHLT }; + ACPI_SIG_NHLT, ACPI_SIG_AGDI }; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) -- Gitee From 24246d052d8c98b32a6a02d3bee044a62b36bd35 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Mon, 6 Nov 2023 17:39:59 +0800 Subject: [PATCH 4/7] ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v5.18-rc1 commit a2a591fb76e6f5461dfd04715b69c317e50c43a5 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a2a591fb76e6f5461dfd04715b69c317e50c43a5 ---------------------------------------------------------------------- ACPI for Arm Components 1.1 Platform Design Document v1.1 [0] specifices Arm Generic Diagnostic Device Interface (AGDI). It allows an admin to issue diagnostic dump and reset via an SDEI event or an interrupt. This patch implements SDEI path. [0] https://developer.arm.com/documentation/den0093/latest/ Signed-off-by: Ilkka Koskinen Reviewed-by: Russell King (Oracle) Acked-by: Lorenzo Pieralisi Signed-off-by: Rafael J. Wysocki Signed-off-by: “Qian Zou” --- drivers/acpi/arm64/Kconfig | 10 ++++ drivers/acpi/arm64/Makefile | 1 + drivers/acpi/arm64/agdi.c | 116 ++++++++++++++++++++++++++++++++++++ drivers/acpi/bus.c | 2 + include/linux/acpi_agdi.h | 13 ++++ 5 files changed, 142 insertions(+) create mode 100644 drivers/acpi/arm64/agdi.c create mode 100644 include/linux/acpi_agdi.h diff --git a/drivers/acpi/arm64/Kconfig b/drivers/acpi/arm64/Kconfig index 664d2ca05799..d6f98f89c8bf 100644 --- a/drivers/acpi/arm64/Kconfig +++ b/drivers/acpi/arm64/Kconfig @@ -11,3 +11,13 @@ config ACPI_GTDT config ACPI_MPAM bool + +config ACPI_AGDI + bool "Arm Generic Diagnostic Dump and Reset Device Interface" + depends on ARM_SDE_INTERFACE + help + Arm Generic Diagnostic Dump and Reset Device Interface (AGDI) is + a standard that enables issuing a non-maskable diagnostic dump and + reset command. + + If set, the kernel parses AGDI table and listens for the command. diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 2bae08207e51..7d3c52952437 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_ACPI_AGDI) += agdi.o obj-$(CONFIG_ACPI_IORT) += iort.o obj-$(CONFIG_ACPI_GTDT) += gtdt.o obj-$(CONFIG_ACPI_MPAM) += mpam.o mpam_v2.o diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c new file mode 100644 index 000000000000..4df337d545b7 --- /dev/null +++ b/drivers/acpi/arm64/agdi.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file implements handling of + * Arm Generic Diagnostic Dump and Reset Interface table (AGDI) + * + * Copyright (c) 2022, Ampere Computing LLC + */ + +#define pr_fmt(fmt) "ACPI: AGDI: " fmt + +#include +#include +#include +#include +#include + +struct agdi_data { + int sdei_event; +}; + +static int agdi_sdei_handler(u32 sdei_event, struct pt_regs *regs, void *arg) +{ + nmi_panic(regs, "Arm Generic Diagnostic Dump and Reset SDEI event issued"); + return 0; +} + +static int agdi_sdei_probe(struct platform_device *pdev, + struct agdi_data *adata) +{ + int err; + + err = sdei_event_register(adata->sdei_event, agdi_sdei_handler, pdev); + if (err) { + dev_err(&pdev->dev, "Failed to register for SDEI event %d", + adata->sdei_event); + return err; + } + + err = sdei_event_enable(adata->sdei_event); + if (err) { + sdei_event_unregister(adata->sdei_event); + dev_err(&pdev->dev, "Failed to enable event %d\n", + adata->sdei_event); + return err; + } + + return 0; +} + +static int agdi_probe(struct platform_device *pdev) +{ + struct agdi_data *adata = dev_get_platdata(&pdev->dev); + + if (!adata) + return -EINVAL; + + return agdi_sdei_probe(pdev, adata); +} + +static int agdi_remove(struct platform_device *pdev) +{ + struct agdi_data *adata = dev_get_platdata(&pdev->dev); + int err, i; + + err = sdei_event_disable(adata->sdei_event); + if (err) + return err; + + for (i = 0; i < 3; i++) { + err = sdei_event_unregister(adata->sdei_event); + if (err != -EINPROGRESS) + break; + + schedule(); + } + + return err; +} + +static struct platform_driver agdi_driver = { + .driver = { + .name = "agdi", + }, + .probe = agdi_probe, + .remove = agdi_remove, +}; + +void __init acpi_agdi_init(void) +{ + struct acpi_table_agdi *agdi_table; + struct agdi_data pdata; + struct platform_device *pdev; + acpi_status status; + + status = acpi_get_table(ACPI_SIG_AGDI, 0, + (struct acpi_table_header **) &agdi_table); + if (ACPI_FAILURE(status)) + return; + + if (agdi_table->flags & ACPI_AGDI_SIGNALING_MODE) { + pr_warn("Interrupt signaling is not supported"); + goto err_put_table; + } + + pdata.sdei_event = agdi_table->sdei_event; + + pdev = platform_device_register_data(NULL, "agdi", 0, &pdata, sizeof(pdata)); + if (IS_ERR(pdev)) + goto err_put_table; + + if (platform_driver_register(&agdi_driver)) + platform_device_unregister(pdev); + +err_put_table: + acpi_put_table((struct acpi_table_header *)agdi_table); +} diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d8086d49ce6b..bb213ade965b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -24,6 +24,7 @@ #include #include #endif +#include #include #include #include @@ -1295,6 +1296,7 @@ static int __init acpi_init(void) acpi_wakeup_device_init(); acpi_debugger_init(); acpi_setup_sb_notify_handler(); + acpi_agdi_init(); return 0; } diff --git a/include/linux/acpi_agdi.h b/include/linux/acpi_agdi.h new file mode 100644 index 000000000000..f477f0b452fa --- /dev/null +++ b/include/linux/acpi_agdi.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ACPI_AGDI_H__ +#define __ACPI_AGDI_H__ + +#include + +#ifdef CONFIG_ACPI_AGDI +void __init acpi_agdi_init(void); +#else +static inline void acpi_agdi_init(void) {} +#endif +#endif /* __ACPI_AGDI_H__ */ -- Gitee From 48d5dbc33f05140ab227594d94c20a11f6b41a74 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Mon, 6 Nov 2023 17:40:00 +0800 Subject: [PATCH 5/7] ACPICA: iASL: Add suppport for AGDI table mainline inclusion from mainline-v5.17-rc1 commit 5579649e7eb756a4e3d5784b6958374e5bfc41de category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5579649e7eb756a4e3d5784b6958374e5bfc41de ---------------------------------------------------------------------- ACPICA commit cf36a6d658ca5aa8c329c2edfc3322c095ffd844 Add support for Arm Generic Diagnostic Dump and Reset Interface, which is described by "ACPI for Arm Components 1.1 Platform Design Document" ARM DEN0093. Add the necessary types in the ACPICA header files and support for compiling and decompiling the table. Link: https://github.com/acpica/acpica/commit/cf36a6d6 Signed-off-by: Ilkka Koskinen Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Qian Zou --- include/acpi/actbl2.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 2fe351437140..aa4568c4f0b3 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -24,6 +24,7 @@ * file. Useful because they make it more difficult to inadvertently type in * the wrong signature. */ +#define ACPI_SIG_AGDI "AGDI" /* Arm Generic Diagnostic Dump and Reset Device Interface */ #define ACPI_SIG_IORT "IORT" /* IO Remapping Table */ #define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ #define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ @@ -65,6 +66,25 @@ * See http://stackoverflow.com/a/1053662/41661 */ +/******************************************************************************* + * AGDI - Arm Generic Diagnostic Dump and Reset Device Interface + * + * Conforms to "ACPI for Arm Components 1.1, Platform Design Document" + * ARM DEN0093 v1.1 + * + ******************************************************************************/ +struct acpi_table_agdi { + struct acpi_table_header header; /* Common ACPI table header */ + u8 flags; + u8 reserved[3]; + u32 sdei_event; + u32 gsiv; +}; + +/* Mask for Flags field above */ + +#define ACPI_AGDI_SIGNALING_MODE (1) + /******************************************************************************* * * IORT - IO Remapping Table -- Gitee From 6b640a2a7c52b4fe648c349f4402625813ee22b7 Mon Sep 17 00:00:00 2001 From: Ilkka Koskinen Date: Mon, 6 Nov 2023 17:40:01 +0800 Subject: [PATCH 6/7] ACPI: AGDI: Fix missing prototype warning for acpi_agdi_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mainline inclusion from mainline-v5.19-rc1 commit 988d7a14408db4183202f16bb02b8149b9da3727 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=988d7a14408db4183202f16bb02b8149b9da3727 ---------------------------------------------------------------------- When building with W=1, we get the following warning: drivers/acpi/arm64/agdi.c:88:13: warning: no previous prototype for ‘acpi_agdi_init’ [-Wmissing-prototypes] void __init acpi_agdi_init(void) Include AGDI driver's header file to pull in the prototype definition for acpi_agdi_init() to get rid of the compiler warning Fixes: a2a591fb76e6 ("ACPI: AGDI: Add driver for Arm Generic Diagnostic Dump and Reset device") Reported-by: kernel test robot Signed-off-by: Ilkka Koskinen Signed-off-by: Rafael J. Wysocki Signed-off-by: Qian Zou --- drivers/acpi/arm64/agdi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c index 4df337d545b7..cf31abd0ed1b 100644 --- a/drivers/acpi/arm64/agdi.c +++ b/drivers/acpi/arm64/agdi.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) "ACPI: AGDI: " fmt #include +#include #include #include #include -- Gitee From e23c4283354e0612b124a2a9e8811eb8fe338d6f Mon Sep 17 00:00:00 2001 From: D Scott Phillips Date: Mon, 6 Nov 2023 17:40:02 +0800 Subject: [PATCH 7/7] arm64: sdei: abort running SDEI handlers during crash mainline inclusion from mainline-v6.6-rc1 commit 5cd474e57368f0957c343bb21e309cf82826b1ef category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DQUX CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5cd474e57368f0957c343bb21e309cf82826b1ef ---------------------------------------------------------------------- Interrupts are blocked in SDEI context, per the SDEI spec: "The client interrupts cannot preempt the event handler." If we crashed in the SDEI handler-running context (as with ACPI's AGDI) then we need to clean up the SDEI state before proceeding to the crash kernel so that the crash kernel can have working interrupts. Track the active SDEI handler per-cpu so that we can COMPLETE_AND_RESUME the handler, discarding the interrupted context. Fixes: f5df26961853 ("arm64: kernel: Add arch-specific SDEI entry code and CPU masking") Signed-off-by: D Scott Phillips Cc: stable@vger.kernel.org Reviewed-by: James Morse Tested-by: Mihai Carabas Link: https://lore.kernel.org/r/20230627002939.2758-1-scott@os.amperecomputing.com Signed-off-by: Will Deacon Signed-off-by: Qian Zou --- arch/arm64/include/asm/sdei.h | 6 ++++++ arch/arm64/kernel/entry.S | 27 +++++++++++++++++++++++++-- arch/arm64/kernel/sdei.c | 3 +++ arch/arm64/kernel/smp.c | 8 ++++---- drivers/firmware/arm_sdei.c | 19 +++++++++++++++++++ include/linux/arm_sdei.h | 2 ++ 6 files changed, 59 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/sdei.h b/arch/arm64/include/asm/sdei.h index 63e0b92a5fbb..5882c0e29331 100644 --- a/arch/arm64/include/asm/sdei.h +++ b/arch/arm64/include/asm/sdei.h @@ -17,6 +17,9 @@ #include +DECLARE_PER_CPU(struct sdei_registered_event *, sdei_active_normal_event); +DECLARE_PER_CPU(struct sdei_registered_event *, sdei_active_critical_event); + extern unsigned long sdei_exit_mode; /* Software Delegated Exception entry point from firmware*/ @@ -29,6 +32,9 @@ asmlinkage void __sdei_asm_entry_trampoline(unsigned long event_num, unsigned long pc, unsigned long pstate); +/* Abort a running handler. Context is discarded. */ +void __sdei_handler_abort(void); + /* * The above entry point does the minimum to call C code. This function does * anything else, before calling the driver. diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 64145bfab48f..34c58ad95171 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -1134,9 +1134,13 @@ SYM_CODE_START(__sdei_asm_handler) mov x19, x1 -#if defined(CONFIG_VMAP_STACK) || defined(CONFIG_SHADOW_CALL_STACK) + /* Store the registered-event for crash_smp_send_stop() */ ldrb w4, [x19, #SDEI_EVENT_PRIORITY] -#endif + cbnz w4, 1f + adr_this_cpu dst=x5, sym=sdei_active_normal_event, tmp=x6 + b 2f +1: adr_this_cpu dst=x5, sym=sdei_active_critical_event, tmp=x6 +2: str x19, [x5] #ifdef CONFIG_VMAP_STACK /* @@ -1201,6 +1205,14 @@ SYM_CODE_START(__sdei_asm_handler) ldr_l x2, sdei_exit_mode + /* Clear the registered-event seen by crash_smp_send_stop() */ + ldrb w3, [x4, #SDEI_EVENT_PRIORITY] + cbnz w3, 1f + adr_this_cpu dst=x5, sym=sdei_active_normal_event, tmp=x6 + b 2f +1: adr_this_cpu dst=x5, sym=sdei_active_critical_event, tmp=x6 +2: str xzr, [x5] + alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0 sdei_handler_exit exit_mode=x2 alternative_else_nop_endif @@ -1211,4 +1223,15 @@ alternative_else_nop_endif #endif SYM_CODE_END(__sdei_asm_handler) NOKPROBE(__sdei_asm_handler) + +SYM_CODE_START(__sdei_handler_abort) + mov_q x0, SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME + adr x1, 1f + ldr_l x2, sdei_exit_mode + sdei_handler_exit exit_mode=x2 + // exit the handler and jump to the next instruction. + // Exit will stomp x0-x17, PSTATE, ELR_ELx, and SPSR_ELx. +1: ret +SYM_CODE_END(__sdei_handler_abort) +NOKPROBE(__sdei_handler_abort) #endif /* CONFIG_ARM_SDE_INTERFACE */ diff --git a/arch/arm64/kernel/sdei.c b/arch/arm64/kernel/sdei.c index 2132bd953a87..6d51d873bbfc 100644 --- a/arch/arm64/kernel/sdei.c +++ b/arch/arm64/kernel/sdei.c @@ -38,6 +38,9 @@ DEFINE_PER_CPU(unsigned long *, sdei_stack_normal_ptr); DEFINE_PER_CPU(unsigned long *, sdei_stack_critical_ptr); #endif +DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_normal_event); +DEFINE_PER_CPU(struct sdei_registered_event *, sdei_active_critical_event); + static void _free_sdei_stack(unsigned long * __percpu *ptr, int cpu) { unsigned long *p; diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 08328ec025a8..23707812f87a 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -1138,10 +1138,8 @@ void crash_smp_send_stop(void) * If this cpu is the only one alive at this point in time, online or * not, there are no stop messages to be sent around, so just back out. */ - if (num_other_online_cpus() == 0) { - sdei_mask_local_cpu(); - return; - } + if (num_other_online_cpus() == 0) + goto skip_ipi; cpumask_copy(&mask, cpu_online_mask); cpumask_clear_cpu(smp_processor_id(), &mask); @@ -1160,7 +1158,9 @@ void crash_smp_send_stop(void) pr_warn("SMP: failed to stop secondary CPUs %*pbl\n", cpumask_pr_args(&mask)); +skip_ipi: sdei_mask_local_cpu(); + sdei_handler_abort(); } bool smp_crash_stop_failed(void) diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c index 0459e1d4446e..0f0629a94b68 100644 --- a/drivers/firmware/arm_sdei.c +++ b/drivers/firmware/arm_sdei.c @@ -1114,3 +1114,22 @@ int sdei_event_handler(struct pt_regs *regs, return err; } NOKPROBE_SYMBOL(sdei_event_handler); + +void sdei_handler_abort(void) +{ + /* + * If the crash happened in an SDEI event handler then we need to + * finish the handler with the firmware so that we can have working + * interrupts in the crash kernel. + */ + if (__this_cpu_read(sdei_active_critical_event)) { + pr_warn("still in SDEI critical event context, attempting to finish handler.\n"); + __sdei_handler_abort(); + __this_cpu_write(sdei_active_critical_event, NULL); + } + if (__this_cpu_read(sdei_active_normal_event)) { + pr_warn("still in SDEI normal event context, attempting to finish handler.\n"); + __sdei_handler_abort(); + __this_cpu_write(sdei_active_normal_event, NULL); + } +} diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h index b1233196cd3c..28e247dd5773 100644 --- a/include/linux/arm_sdei.h +++ b/include/linux/arm_sdei.h @@ -52,10 +52,12 @@ int sdei_unregister_ghes(struct ghes *ghes); int sdei_mask_local_cpu(void); int sdei_unmask_local_cpu(void); void __init sdei_init(void); +void sdei_handler_abort(void); #else static inline int sdei_mask_local_cpu(void) { return 0; } static inline int sdei_unmask_local_cpu(void) { return 0; } static inline void sdei_init(void) { } +static inline void sdei_handler_abort(void) { } #endif /* CONFIG_ARM_SDE_INTERFACE */ -- Gitee