1 // SPDX-License-Identifier: GPL-2.0-only
3 * This file implements handling of
4 * Arm Generic Diagnostic Dump and Reset Interface table (AGDI)
6 * Copyright (c) 2022, Ampere Computing LLC
9 #define pr_fmt(fmt) "ACPI: AGDI: " fmt
11 #include <linux/acpi.h>
12 #include <linux/arm_sdei.h>
14 #include <linux/kernel.h>
15 #include <linux/platform_device.h>
22 static int agdi_sdei_handler(u32 sdei_event
, struct pt_regs
*regs
, void *arg
)
24 nmi_panic(regs
, "Arm Generic Diagnostic Dump and Reset SDEI event issued");
28 static int agdi_sdei_probe(struct platform_device
*pdev
,
29 struct agdi_data
*adata
)
33 err
= sdei_event_register(adata
->sdei_event
, agdi_sdei_handler
, pdev
);
35 dev_err(&pdev
->dev
, "Failed to register for SDEI event %d",
40 err
= sdei_event_enable(adata
->sdei_event
);
42 sdei_event_unregister(adata
->sdei_event
);
43 dev_err(&pdev
->dev
, "Failed to enable event %d\n",
51 static int agdi_probe(struct platform_device
*pdev
)
53 struct agdi_data
*adata
= dev_get_platdata(&pdev
->dev
);
58 return agdi_sdei_probe(pdev
, adata
);
61 static void agdi_remove(struct platform_device
*pdev
)
63 struct agdi_data
*adata
= dev_get_platdata(&pdev
->dev
);
66 err
= sdei_event_disable(adata
->sdei_event
);
68 dev_err(&pdev
->dev
, "Failed to disable sdei-event #%d (%pe)\n",
69 adata
->sdei_event
, ERR_PTR(err
));
73 for (i
= 0; i
< 3; i
++) {
74 err
= sdei_event_unregister(adata
->sdei_event
);
75 if (err
!= -EINPROGRESS
)
82 dev_err(&pdev
->dev
, "Failed to unregister sdei-event #%d (%pe)\n",
83 adata
->sdei_event
, ERR_PTR(err
));
86 static struct platform_driver agdi_driver
= {
91 .remove
= agdi_remove
,
94 void __init
acpi_agdi_init(void)
96 struct acpi_table_agdi
*agdi_table
;
97 struct agdi_data pdata
;
98 struct platform_device
*pdev
;
101 status
= acpi_get_table(ACPI_SIG_AGDI
, 0,
102 (struct acpi_table_header
**) &agdi_table
);
103 if (ACPI_FAILURE(status
))
106 if (agdi_table
->flags
& ACPI_AGDI_SIGNALING_MODE
) {
107 pr_warn("Interrupt signaling is not supported");
111 pdata
.sdei_event
= agdi_table
->sdei_event
;
113 pdev
= platform_device_register_data(NULL
, "agdi", 0, &pdata
, sizeof(pdata
));
117 if (platform_driver_register(&agdi_driver
))
118 platform_device_unregister(pdev
);
121 acpi_put_table((struct acpi_table_header
*)agdi_table
);