Re: [PATCH v3] ACPI: AGDI: Add interrupt signaling mode support
From: Hanjun Guo
Date: Fri Sep 26 2025 - 22:45:53 EST
Hi Kazuhiro,
Sorry for the late reply, some comments below.
On 2025/9/5 12:27, Kazuhiro Abe wrote:
AGDI has two types of signaling modes: SDEI and interrupt.
Currently, the AGDI driver only supports SDEI.
Therefore, add support for interrupt signaling mode
The interrupt vector is retrieved from the AGDI table, and call panic
function when an interrupt occurs.
Signed-off-by: Kazuhiro Abe <fj1078ii@xxxxxxxxxxxxxxxxx>
---
I keep normal IRQ code when NMI cannot be used.
If there is any concern, please let me know.
v2->v3
- Fix bug in the return value of agdi_probe function.
- Remove unnecessary curly braces in the agdi_remove function.
v2: https://lore.kernel.org/all/20250829101154.2377800-1-fj1078ii@xxxxxxxxxxxxxxxxx/
v1->v2
- Remove acpica update since there is no need to update define value
for this patch.
---
drivers/acpi/arm64/agdi.c | 95 ++++++++++++++++++++++++++++++++++++---
1 file changed, 88 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c
index e0df3daa4abf..2313a46f01cd 100644
--- a/drivers/acpi/arm64/agdi.c
+++ b/drivers/acpi/arm64/agdi.c
@@ -16,7 +16,11 @@
#include "init.h"
struct agdi_data {
+ unsigned char flags;
Adding a comment here for what's the falgs used for,
multi flags in this file such as irq_flags, just
make the code easy to understand.
int sdei_event;
+ unsigned int gsiv;
+ bool use_nmi;
+ int irq;
};
static int agdi_sdei_handler(u32 sdei_event, struct pt_regs *regs, void *arg)
@@ -48,6 +52,55 @@ static int agdi_sdei_probe(struct platform_device *pdev,
return 0;
}
+static irqreturn_t agdi_interrupt_handler_nmi(int irq, void *dev_id)
+{
+ nmi_panic(NULL, "Arm Generic Diagnostic Dump and Reset NMI Interrupt event issued\n");
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t agdi_interrupt_handler_irq(int irq, void *dev_id)
+{
+ panic("Arm Generic Diagnostic Dump and Reset Interrupt event issued\n");
+ return IRQ_HANDLED;
+}
+
+static int agdi_interrupt_probe(struct platform_device *pdev,
+ struct agdi_data *adata)
+{
+ unsigned long irq_flags;
+ int ret;
+ int irq;
+
+ irq = acpi_register_gsi(NULL, adata->gsiv, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot register GSI#%d (%d)\n", adata->gsiv, irq);
+ return irq;
+ }
+
+ irq_flags = IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
+ IRQF_NO_THREAD;
+ /* try NMI first */
+ ret = request_nmi(irq, &agdi_interrupt_handler_nmi, irq_flags,
+ "agdi_interrupt_nmi", NULL);
+ if (ret) {
+ ret = request_irq(irq, &agdi_interrupt_handler_irq,
+ irq_flags, "agdi_interrupt_irq", NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot register IRQ %d\n", ret);
+ acpi_unregister_gsi(adata->gsiv);
+ return ret;
+ }
+ enable_irq(irq);
+ adata->irq = irq;
+ } else {
+ enable_nmi(irq);
+ adata->irq = irq;
+ adata->use_nmi = true;
+ }
if (!ret) {
/* NMI handling code */
}
/* Then try normal interrupt */
ret = request_irq();
...
This makes code better organized.
+
+ return 0;
+}
+
static int agdi_probe(struct platform_device *pdev)
{
struct agdi_data *adata = dev_get_platdata(&pdev->dev);
@@ -55,12 +108,15 @@ static int agdi_probe(struct platform_device *pdev)
if (!adata)
return -EINVAL;
- return agdi_sdei_probe(pdev, adata);
+ if (adata->flags & ACPI_AGDI_SIGNALING_MODE)
+ return agdi_interrupt_probe(pdev, adata);
+ else
+ return agdi_sdei_probe(pdev, adata);
}
-static void agdi_remove(struct platform_device *pdev)
+static void agdi_sdei_remove(struct platform_device *pdev,
+ struct agdi_data *adata)
{
- struct agdi_data *adata = dev_get_platdata(&pdev->dev);
int err, i;
err = sdei_event_disable(adata->sdei_event);
@@ -83,6 +139,29 @@ static void agdi_remove(struct platform_device *pdev)
adata->sdei_event, ERR_PTR(err));
}
+static void agdi_interrupt_remove(struct platform_device *pdev,
+ struct agdi_data *adata)
+{
+ if (adata->irq != -1) {
+ if (adata->use_nmi)
+ free_nmi(adata->irq, NULL);
+ else
+ free_irq(adata->irq, NULL);
+
+ acpi_unregister_gsi(adata->gsiv);
+ }
if (adata->irq == -1)
return;
...
To save extra { }.
+}
+
+static void agdi_remove(struct platform_device *pdev)
+{
+ struct agdi_data *adata = dev_get_platdata(&pdev->dev);
+
+ if (adata->flags & ACPI_AGDI_SIGNALING_MODE)
+ agdi_interrupt_remove(pdev, adata);
+ else
+ agdi_sdei_remove(pdev, adata);
+}
+
static struct platform_driver agdi_driver = {
.driver = {
.name = "agdi",
@@ -94,7 +173,7 @@ static struct platform_driver agdi_driver = {
void __init acpi_agdi_init(void)
{
struct acpi_table_agdi *agdi_table;
- struct agdi_data pdata;
+ struct agdi_data pdata = {0};
struct agdi_data pdata = { 0 };
Thanks
Hanjun