1616#include "init.h"
1717
1818struct agdi_data {
19+ unsigned char flags ; /* AGDI Signaling Mode */
1920 int sdei_event ;
21+ unsigned int gsiv ;
22+ bool use_nmi ;
23+ int irq ;
2024};
2125
2226static int agdi_sdei_handler (u32 sdei_event , struct pt_regs * regs , void * arg )
@@ -48,19 +52,73 @@ static int agdi_sdei_probe(struct platform_device *pdev,
4852 return 0 ;
4953}
5054
55+ static irqreturn_t agdi_interrupt_handler_nmi (int irq , void * dev_id )
56+ {
57+ nmi_panic (NULL , "Arm Generic Diagnostic Dump and Reset NMI Interrupt event issued\n" );
58+ return IRQ_HANDLED ;
59+ }
60+
61+ static irqreturn_t agdi_interrupt_handler_irq (int irq , void * dev_id )
62+ {
63+ panic ("Arm Generic Diagnostic Dump and Reset Interrupt event issued\n" );
64+ return IRQ_HANDLED ;
65+ }
66+
67+ static int agdi_interrupt_probe (struct platform_device * pdev ,
68+ struct agdi_data * adata )
69+ {
70+ unsigned long irq_flags ;
71+ int ret ;
72+ int irq ;
73+
74+ irq = acpi_register_gsi (NULL , adata -> gsiv , ACPI_EDGE_SENSITIVE , ACPI_ACTIVE_HIGH );
75+ if (irq < 0 ) {
76+ dev_err (& pdev -> dev , "cannot register GSI#%d (%d)\n" , adata -> gsiv , irq );
77+ return irq ;
78+ }
79+
80+ irq_flags = IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_AUTOEN |
81+ IRQF_NO_THREAD ;
82+ /* try NMI first */
83+ ret = request_nmi (irq , & agdi_interrupt_handler_nmi , irq_flags ,
84+ "agdi_interrupt_nmi" , NULL );
85+ if (!ret ) {
86+ enable_nmi (irq );
87+ adata -> irq = irq ;
88+ adata -> use_nmi = true;
89+ return 0 ;
90+ }
91+
92+ /* Then try normal interrupt */
93+ ret = request_irq (irq , & agdi_interrupt_handler_irq ,
94+ irq_flags , "agdi_interrupt_irq" , NULL );
95+ if (ret ) {
96+ dev_err (& pdev -> dev , "cannot register IRQ %d\n" , ret );
97+ acpi_unregister_gsi (adata -> gsiv );
98+ return ret ;
99+ }
100+ enable_irq (irq );
101+ adata -> irq = irq ;
102+
103+ return 0 ;
104+ }
105+
51106static int agdi_probe (struct platform_device * pdev )
52107{
53108 struct agdi_data * adata = dev_get_platdata (& pdev -> dev );
54109
55110 if (!adata )
56111 return - EINVAL ;
57112
58- return agdi_sdei_probe (pdev , adata );
113+ if (adata -> flags & ACPI_AGDI_SIGNALING_MODE )
114+ return agdi_interrupt_probe (pdev , adata );
115+ else
116+ return agdi_sdei_probe (pdev , adata );
59117}
60118
61- static void agdi_remove (struct platform_device * pdev )
119+ static void agdi_sdei_remove (struct platform_device * pdev ,
120+ struct agdi_data * adata )
62121{
63- struct agdi_data * adata = dev_get_platdata (& pdev -> dev );
64122 int err , i ;
65123
66124 err = sdei_event_disable (adata -> sdei_event );
@@ -83,6 +141,30 @@ static void agdi_remove(struct platform_device *pdev)
83141 adata -> sdei_event , ERR_PTR (err ));
84142}
85143
144+ static void agdi_interrupt_remove (struct platform_device * pdev ,
145+ struct agdi_data * adata )
146+ {
147+ if (adata -> irq == -1 )
148+ return ;
149+
150+ if (adata -> use_nmi )
151+ free_nmi (adata -> irq , NULL );
152+ else
153+ free_irq (adata -> irq , NULL );
154+
155+ acpi_unregister_gsi (adata -> gsiv );
156+ }
157+
158+ static void agdi_remove (struct platform_device * pdev )
159+ {
160+ struct agdi_data * adata = dev_get_platdata (& pdev -> dev );
161+
162+ if (adata -> flags & ACPI_AGDI_SIGNALING_MODE )
163+ agdi_interrupt_remove (pdev , adata );
164+ else
165+ agdi_sdei_remove (pdev , adata );
166+ }
167+
86168static struct platform_driver agdi_driver = {
87169 .driver = {
88170 .name = "agdi" ,
@@ -94,7 +176,7 @@ static struct platform_driver agdi_driver = {
94176void __init acpi_agdi_init (void )
95177{
96178 struct acpi_table_agdi * agdi_table ;
97- struct agdi_data pdata ;
179+ struct agdi_data pdata = { 0 } ;
98180 struct platform_device * pdev ;
99181 acpi_status status ;
100182
@@ -103,12 +185,13 @@ void __init acpi_agdi_init(void)
103185 if (ACPI_FAILURE (status ))
104186 return ;
105187
106- if (agdi_table -> flags & ACPI_AGDI_SIGNALING_MODE ) {
107- pr_warn ( "Interrupt signaling is not supported" ) ;
108- goto err_put_table ;
109- }
188+ if (agdi_table -> flags & ACPI_AGDI_SIGNALING_MODE )
189+ pdata . gsiv = agdi_table -> gsiv ;
190+ else
191+ pdata . sdei_event = agdi_table -> sdei_event ;
110192
111- pdata .sdei_event = agdi_table -> sdei_event ;
193+ pdata .irq = -1 ;
194+ pdata .flags = agdi_table -> flags ;
112195
113196 pdev = platform_device_register_data (NULL , "agdi" , 0 , & pdata , sizeof (pdata ));
114197 if (IS_ERR (pdev ))
0 commit comments