xref: /linux/drivers/acpi/acpica/evsci.c (revision 37744feebc086908fd89760650f458ab19071750)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
3  *
4  * Module Name: evsci - System Control Interrupt configuration and
5  *                      legacy to ACPI mode state transition functions
6  *
7  ******************************************************************************/
8 
9 #include <acpi/acpi.h>
10 #include "accommon.h"
11 #include "acevents.h"
12 
13 #define _COMPONENT          ACPI_EVENTS
14 ACPI_MODULE_NAME("evsci")
15 #if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
16 /* Local prototypes */
17 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context);
18 
19 /*******************************************************************************
20  *
21  * FUNCTION:    acpi_ev_sci_dispatch
22  *
23  * PARAMETERS:  None
24  *
25  * RETURN:      Status code indicates whether interrupt was handled.
26  *
27  * DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers.
28  *
29  ******************************************************************************/
30 
31 u32 acpi_ev_sci_dispatch(void)
32 {
33 	struct acpi_sci_handler_info *sci_handler;
34 	acpi_cpu_flags flags;
35 	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
36 
37 	ACPI_FUNCTION_NAME(ev_sci_dispatch);
38 
39 	/* Are there any host-installed SCI handlers? */
40 
41 	if (!acpi_gbl_sci_handler_list) {
42 		return (int_status);
43 	}
44 
45 	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
46 
47 	/* Invoke all host-installed SCI handlers */
48 
49 	sci_handler = acpi_gbl_sci_handler_list;
50 	while (sci_handler) {
51 
52 		/* Invoke the installed handler (at interrupt level) */
53 
54 		int_status |= sci_handler->address(sci_handler->context);
55 
56 		sci_handler = sci_handler->next;
57 	}
58 
59 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
60 	return (int_status);
61 }
62 
63 /*******************************************************************************
64  *
65  * FUNCTION:    acpi_ev_sci_xrupt_handler
66  *
67  * PARAMETERS:  context   - Calling Context
68  *
69  * RETURN:      Status code indicates whether interrupt was handled.
70  *
71  * DESCRIPTION: Interrupt handler that will figure out what function or
72  *              control method to call to deal with a SCI.
73  *
74  ******************************************************************************/
75 
76 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
77 {
78 	struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
79 	u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
80 
81 	ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
82 
83 	/*
84 	 * We are guaranteed by the ACPICA initialization/shutdown code that
85 	 * if this interrupt handler is installed, ACPI is enabled.
86 	 */
87 
88 	/*
89 	 * Fixed Events:
90 	 * Check for and dispatch any Fixed Events that have occurred
91 	 */
92 	interrupt_handled |= acpi_ev_fixed_event_detect();
93 
94 	/*
95 	 * General Purpose Events:
96 	 * Check for and dispatch any GPEs that have occurred
97 	 */
98 	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
99 
100 	/* Invoke all host-installed SCI handlers */
101 
102 	interrupt_handled |= acpi_ev_sci_dispatch();
103 
104 	acpi_sci_count++;
105 	return_UINT32(interrupt_handled);
106 }
107 
108 /*******************************************************************************
109  *
110  * FUNCTION:    acpi_ev_gpe_xrupt_handler
111  *
112  * PARAMETERS:  context   - Calling Context
113  *
114  * RETURN:      Status code indicates whether interrupt was handled.
115  *
116  * DESCRIPTION: Handler for GPE Block Device interrupts
117  *
118  ******************************************************************************/
119 
120 u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
121 {
122 	struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
123 	u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
124 
125 	ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler);
126 
127 	/*
128 	 * We are guaranteed by the ACPICA initialization/shutdown code that
129 	 * if this interrupt handler is installed, ACPI is enabled.
130 	 */
131 
132 	/* GPEs: Check for and dispatch any GPEs that have occurred */
133 
134 	interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
135 	return_UINT32(interrupt_handled);
136 }
137 
138 /******************************************************************************
139  *
140  * FUNCTION:    acpi_ev_install_sci_handler
141  *
142  * PARAMETERS:  none
143  *
144  * RETURN:      Status
145  *
146  * DESCRIPTION: Installs SCI handler.
147  *
148  ******************************************************************************/
149 
150 u32 acpi_ev_install_sci_handler(void)
151 {
152 	u32 status = AE_OK;
153 
154 	ACPI_FUNCTION_TRACE(ev_install_sci_handler);
155 
156 	status =
157 	    acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
158 					      acpi_ev_sci_xrupt_handler,
159 					      acpi_gbl_gpe_xrupt_list_head);
160 	return_ACPI_STATUS(status);
161 }
162 
163 /******************************************************************************
164  *
165  * FUNCTION:    acpi_ev_remove_all_sci_handlers
166  *
167  * PARAMETERS:  none
168  *
169  * RETURN:      AE_OK if handler uninstalled, AE_ERROR if handler was not
170  *              installed to begin with
171  *
172  * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
173  *              taken. Remove all host-installed SCI handlers.
174  *
175  * Note:  It doesn't seem important to disable all events or set the event
176  *        enable registers to their original values. The OS should disable
177  *        the SCI interrupt level when the handler is removed, so no more
178  *        events will come in.
179  *
180  ******************************************************************************/
181 
182 acpi_status acpi_ev_remove_all_sci_handlers(void)
183 {
184 	struct acpi_sci_handler_info *sci_handler;
185 	acpi_cpu_flags flags;
186 	acpi_status status;
187 
188 	ACPI_FUNCTION_TRACE(ev_remove_all_sci_handlers);
189 
190 	/* Just let the OS remove the handler and disable the level */
191 
192 	status =
193 	    acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
194 					     acpi_ev_sci_xrupt_handler);
195 
196 	if (!acpi_gbl_sci_handler_list) {
197 		return (status);
198 	}
199 
200 	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
201 
202 	/* Free all host-installed SCI handlers */
203 
204 	while (acpi_gbl_sci_handler_list) {
205 		sci_handler = acpi_gbl_sci_handler_list;
206 		acpi_gbl_sci_handler_list = sci_handler->next;
207 		ACPI_FREE(sci_handler);
208 	}
209 
210 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
211 	return_ACPI_STATUS(status);
212 }
213 
214 #endif				/* !ACPI_REDUCED_HARDWARE */
215