[PATCH v4 08/10] riscv: Introduce HEST SSE notification handlers
Anup Patel
anup at brainfault.org
Sun Aug 16 22:02:21 PDT 2026
On Wed, May 13, 2026 at 2:18 PM Himanshu Chauhan
<himanshu.chauhan at oss.qualcomm.com> 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 <himanshu.chauhan at oss.qualcomm.com>
> ---
> 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 <ying.huang at intel.com>
> */
>
> +#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
More information about the linux-riscv
mailing list