Re: [PATCH v4 08/10] riscv: Introduce HEST SSE notification handlers
Anup Patel <[email protected]>
| Newsgroups | org.kernel.vger.linux-efi,dev.linux.lists.acpica-devel,org.infradead.lists.linux-riscv,org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <CAAhSdy2LkwC_FBFWP3M66X-mY8WwpSHiOCOKf=e4Fri=gkt27Q@mail.gmail.com> |
On Wed, May 13, 2026 at 2:18 PM Himanshu Chauhan <[email protected]> wrote: > > Add config option to enable SSE in APEI. When it is enabled, functions > to register/unregister a ghes entry with SSE are avilable along with > low and high priority event handers. If a SSE notification type is > determined, a ghes common handler to handle an error event is registered. > > Signed-off-by: Himanshu Chauhan <[email protected]> > --- > drivers/acpi/apei/Kconfig | 5 ++ > drivers/acpi/apei/ghes.c | 99 ++++++++++++++++++++++++++++++++++----- > 2 files changed, 93 insertions(+), 11 deletions(-) > > diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig > index 428458c623f0..895a843d0e36 100644 > --- a/drivers/acpi/apei/Kconfig > +++ b/drivers/acpi/apei/Kconfig > @@ -46,6 +46,11 @@ config ACPI_APEI_SEA > depends on ARM64 && ACPI_APEI_GHES > default y > > +config ACPI_APEI_SSE > + bool > + depends on RISCV && RISCV_SBI_SSE && ACPI_APEI_GHES > + default y > + > config ACPI_APEI_MEMORY_FAILURE > bool "APEI memory error recovering support" > depends on ACPI_APEI && MEMORY_FAILURE > diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c > index 8edc2c8db1bb..1baa8ddd10ea 100644 > --- a/drivers/acpi/apei/ghes.c > +++ b/drivers/acpi/apei/ghes.c > @@ -17,6 +17,8 @@ > * Author: Huang Ying <[email protected]> > */ > > +#include <linux/err.h> > +#include <linux/riscv_sbi_sse.h> > #include <linux/arm_sdei.h> > #include <linux/kernel.h> > #include <linux/moduleparam.h> > @@ -100,6 +102,11 @@ > #define FIX_APEI_GHES_SDEI_CRITICAL __end_of_fixed_addresses > #endif > > +#ifndef CONFIG_RISCV_SBI_SSE > +#define FIX_APEI_GHES_SSE_LOW_PRIORITY __end_of_fixed_addresses > +#define FIX_APEI_GHES_SSE_HIGH_PRIORITY __end_of_fixed_addresses > +#endif > + > static ATOMIC_NOTIFIER_HEAD(ghes_report_chain); > > static inline bool is_hest_type_generic_v2(struct ghes *ghes) > @@ -1662,6 +1669,63 @@ static int apei_sdei_unregister_ghes(struct ghes *ghes) > return sdei_unregister_ghes(ghes); > } > > +#if defined(CONFIG_ACPI_APEI_SSE) > +/* SSE Handlers */ > +static int __ghes_sse_callback(struct ghes *ghes, > + enum fixed_addresses fixmap_idx) > +{ > + if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx)) { > + irq_work_queue(&ghes_proc_irq_work); > + > + return 0; > + } > + > + return -ENOENT; > +} > + > +/* Low priority */ > +static int ghes_sse_lo_callback(u32 event_num, void *arg, struct pt_regs *regs) > +{ > + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sse_lo); > + struct ghes *ghes = arg; > + int err; > + > + raw_spin_lock(&ghes_notify_lock_sse_lo); > + err = __ghes_sse_callback(ghes, FIX_APEI_GHES_SSE_LOW_PRIORITY); > + raw_spin_unlock(&ghes_notify_lock_sse_lo); > + > + return err; > +} > + > +/* High priority */ > +static int ghes_sse_hi_callback(u32 event_num, void *arg, struct pt_regs *regs) > +{ > + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sse_hi); > + struct ghes *ghes = arg; > + int err; > + > + raw_spin_lock(&ghes_notify_lock_sse_hi); > + err = __ghes_sse_callback(ghes, FIX_APEI_GHES_SSE_HIGH_PRIORITY); > + raw_spin_unlock(&ghes_notify_lock_sse_hi); > + > + return err; > +} > + > +static int apei_sse_register_ghes(struct ghes *ghes) > +{ > + return sse_register_ghes(ghes, ghes_sse_lo_callback, > + ghes_sse_hi_callback); > +} > + > +static int apei_sse_unregister_ghes(struct ghes *ghes) > +{ > + return sse_unregister_ghes(ghes); > +} > +#else /* CONFIG_ACPI_APEI_SSE */ > +static int apei_sse_register_ghes(struct ghes *ghes) { return -EOPNOTSUPP; } > +static int apei_sse_unregister_ghes(struct ghes *ghes) { return -EOPNOTSUPP; } > +#endif > + > static int ghes_probe(struct platform_device *ghes_dev) > { > struct acpi_hest_generic *generic; > @@ -1708,6 +1772,14 @@ static int ghes_probe(struct platform_device *ghes_dev) > pr_warn(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n", > generic->header.source_id); > goto err; > + case ACPI_HEST_NOTIFY_SSE: > + if (!IS_ENABLED(CONFIG_ACPI_APEI_SSE)) { > + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SSE is not supported\n", > + generic->header.source_id); > + rc = -EOPNOTSUPP; > + goto err; > + } > + break; > default: > pr_warn(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n", > generic->notify.type, generic->header.source_id); > @@ -1775,6 +1847,17 @@ static int ghes_probe(struct platform_device *ghes_dev) > if (rc) > goto err; > break; > + > + case ACPI_HEST_NOTIFY_SSE: > + rc = apei_sse_register_ghes(ghes); > + if (rc) { > + pr_err(GHES_PFX "Failed to register for SSE notification on vector %d\n", > + generic->notify.vector); > + goto err; > + } > + pr_err(GHES_PFX "Registered SSE notification on vector %d\n", > + generic->notify.vector); This needs to be pr_info() instead of pr_err(). > + break; > default: > BUG(); > } > @@ -1804,7 +1887,6 @@ static int ghes_probe(struct platform_device *ghes_dev) > > static void ghes_remove(struct platform_device *ghes_dev) > { > - int rc; > struct ghes *ghes; > struct acpi_hest_generic *generic; > > @@ -1838,16 +1920,11 @@ static void ghes_remove(struct platform_device *ghes_dev) > ghes_nmi_remove(ghes); > break; > case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: > - rc = apei_sdei_unregister_ghes(ghes); > - if (rc) { > - /* > - * Returning early results in a resource leak, but we're > - * only here if stopping the hardware failed. > - */ > - dev_err(&ghes_dev->dev, "Failed to unregister ghes (%pe)\n", > - ERR_PTR(rc)); > - return; > - } > + apei_sdei_unregister_ghes(ghes); > + break; > + > + case ACPI_HEST_NOTIFY_SSE: > + apei_sse_unregister_ghes(ghes); > break; > default: > BUG(); > -- > 2.43.0 > > Regards, Anup