[PATCH v4 04/13] ACPI: extlog: Defer CXL protocol error handling to avoid lock inversion
Dave Jiang <[email protected]>
| Newsgroups | org.kernel.vger.linux-cxl,org.kernel.vger.linux-acpi |
|---|---|
| Message-ID | <[email protected]> |
extlog_print() calls cxl_cper_handle_prot_err() synchronously while the MCE notifier chain rwsem is held, and that path takes the PCI device_lock via guard(device)(). The probe path takes the two in the opposite order, holding device_lock while mce_register_decode_chain() takes the rwsem, so they can deadlock AB-BA. ghes.c already avoids this by posting protocol errors to a kfifo and handling them from a workqueue via cxl_cper_post_prot_err(). Export that function and call it instead. Declare it with the other CONFIG_ACPI_APEI_GHES exports rather than at the end of the header. No #else stub: ACPI_EXTLOG selects ACPI_APEI_GHES, so the only caller cannot exist without it. Reported-by: [email protected] Closes: https://lore.kernel.org/linux-cxl/[email protected]/ Reviewed-by: Alison Schofield <[email protected]> Reviewed-by: Shuai Xue <[email protected]> Assisted-by: Claude:claude-sonnet-4-6 Signed-off-by: Dave Jiang <[email protected]> --- v4: - Moved the cxl_cper_post_prot_err() declaration inside the CONFIG_ACPI_APEI_GHES block (Shuai Xue). --- drivers/acpi/acpi_extlog.c | 21 ++------------------- drivers/acpi/apei/ghes.c | 5 +++-- include/acpi/ghes.h | 4 ++++ 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 9ad0052aa20c..f6e3da4e13e7 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -163,23 +163,6 @@ static void extlog_print_pcie(struct cper_sec_pcie *pcie_err, #endif } -static void -extlog_cxl_cper_handle_prot_err(struct cxl_cper_sec_prot_err *prot_err, - int severity) -{ -#ifdef ACPI_APEI_PCIEAER - struct cxl_cper_prot_err_work_data wd; - - if (cxl_cper_sec_prot_err_valid(prot_err)) - return; - - if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity)) - return; - - cxl_cper_handle_prot_err(&wd); -#endif -} - static int extlog_print(struct notifier_block *nb, unsigned long val, void *data) { @@ -239,8 +222,8 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, struct cxl_cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata); - extlog_cxl_cper_handle_prot_err(prot_err, - gdata->error_severity); + cxl_cper_post_prot_err(prot_err, + gdata->error_severity); } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 3236a3ce79d6..a382aabf9835 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -752,8 +752,8 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, static DEFINE_SPINLOCK(cxl_cper_prot_err_work_lock); struct work_struct *cxl_cper_prot_err_work; -static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, - int severity) +void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, + int severity) { #ifdef CONFIG_ACPI_APEI_PCIEAER struct cxl_cper_prot_err_work_data wd; @@ -777,6 +777,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, schedule_work(cxl_cper_prot_err_work); #endif } +EXPORT_SYMBOL_FOR_MODULES(cxl_cper_post_prot_err, "acpi_extlog"); int cxl_cper_register_prot_err_work(struct work_struct *work) { diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 8d7e5caef3f1..be496bc0386f 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h @@ -85,6 +85,10 @@ int devm_ghes_register_vendor_record_notifier(struct device *dev, struct list_head *ghes_get_devices(void); void ghes_estatus_pool_region_free(unsigned long addr, u32 size); + +struct cxl_cper_sec_prot_err; +void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, + int severity); #else static inline struct list_head *ghes_get_devices(void) { return NULL; } -- 2.54.0