1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: evevent - Fixed Event handling and dispatch |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acevents.h" |
13 | |
14 | #define _COMPONENT ACPI_EVENTS |
15 | ACPI_MODULE_NAME("evevent" ) |
16 | #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ |
17 | /* Local prototypes */ |
18 | static acpi_status acpi_ev_fixed_event_initialize(void); |
19 | |
20 | static u32 acpi_ev_fixed_event_dispatch(u32 event); |
21 | |
22 | /******************************************************************************* |
23 | * |
24 | * FUNCTION: acpi_ev_initialize_events |
25 | * |
26 | * PARAMETERS: None |
27 | * |
28 | * RETURN: Status |
29 | * |
30 | * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE) |
31 | * |
32 | ******************************************************************************/ |
33 | |
34 | acpi_status acpi_ev_initialize_events(void) |
35 | { |
36 | acpi_status status; |
37 | |
38 | ACPI_FUNCTION_TRACE(ev_initialize_events); |
39 | |
40 | /* If Hardware Reduced flag is set, there are no fixed events */ |
41 | |
42 | if (acpi_gbl_reduced_hardware) { |
43 | return_ACPI_STATUS(AE_OK); |
44 | } |
45 | |
46 | /* |
47 | * Initialize the Fixed and General Purpose Events. This is done prior to |
48 | * enabling SCIs to prevent interrupts from occurring before the handlers |
49 | * are installed. |
50 | */ |
51 | status = acpi_ev_fixed_event_initialize(); |
52 | if (ACPI_FAILURE(status)) { |
53 | ACPI_EXCEPTION((AE_INFO, status, |
54 | "Unable to initialize fixed events" )); |
55 | return_ACPI_STATUS(status); |
56 | } |
57 | |
58 | status = acpi_ev_gpe_initialize(); |
59 | if (ACPI_FAILURE(status)) { |
60 | ACPI_EXCEPTION((AE_INFO, status, |
61 | "Unable to initialize general purpose events" )); |
62 | return_ACPI_STATUS(status); |
63 | } |
64 | |
65 | return_ACPI_STATUS(status); |
66 | } |
67 | |
68 | /******************************************************************************* |
69 | * |
70 | * FUNCTION: acpi_ev_install_xrupt_handlers |
71 | * |
72 | * PARAMETERS: None |
73 | * |
74 | * RETURN: Status |
75 | * |
76 | * DESCRIPTION: Install interrupt handlers for the SCI and Global Lock |
77 | * |
78 | ******************************************************************************/ |
79 | |
80 | acpi_status acpi_ev_install_xrupt_handlers(void) |
81 | { |
82 | acpi_status status; |
83 | |
84 | ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers); |
85 | |
86 | /* If Hardware Reduced flag is set, there is no ACPI h/w */ |
87 | |
88 | if (acpi_gbl_reduced_hardware) { |
89 | return_ACPI_STATUS(AE_OK); |
90 | } |
91 | |
92 | /* Install the SCI handler */ |
93 | |
94 | status = acpi_ev_install_sci_handler(); |
95 | if (ACPI_FAILURE(status)) { |
96 | ACPI_EXCEPTION((AE_INFO, status, |
97 | "Unable to install System Control Interrupt handler" )); |
98 | return_ACPI_STATUS(status); |
99 | } |
100 | |
101 | /* Install the handler for the Global Lock */ |
102 | |
103 | status = acpi_ev_init_global_lock_handler(); |
104 | if (ACPI_FAILURE(status)) { |
105 | ACPI_EXCEPTION((AE_INFO, status, |
106 | "Unable to initialize Global Lock handler" )); |
107 | return_ACPI_STATUS(status); |
108 | } |
109 | |
110 | acpi_gbl_events_initialized = TRUE; |
111 | return_ACPI_STATUS(status); |
112 | } |
113 | |
114 | /******************************************************************************* |
115 | * |
116 | * FUNCTION: acpi_ev_fixed_event_initialize |
117 | * |
118 | * PARAMETERS: None |
119 | * |
120 | * RETURN: Status |
121 | * |
122 | * DESCRIPTION: Install the fixed event handlers and disable all fixed events. |
123 | * |
124 | ******************************************************************************/ |
125 | |
126 | static acpi_status acpi_ev_fixed_event_initialize(void) |
127 | { |
128 | u32 i; |
129 | acpi_status status; |
130 | |
131 | /* |
132 | * Initialize the structure that keeps track of fixed event handlers and |
133 | * disable all of the fixed events. |
134 | */ |
135 | for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
136 | acpi_gbl_fixed_event_handlers[i].handler = NULL; |
137 | acpi_gbl_fixed_event_handlers[i].context = NULL; |
138 | |
139 | /* Disable the fixed event */ |
140 | |
141 | if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { |
142 | status = |
143 | acpi_write_bit_register(acpi_gbl_fixed_event_info |
144 | [i].enable_register_id, |
145 | ACPI_DISABLE_EVENT); |
146 | if (ACPI_FAILURE(status)) { |
147 | return (status); |
148 | } |
149 | } |
150 | } |
151 | |
152 | return (AE_OK); |
153 | } |
154 | |
155 | /******************************************************************************* |
156 | * |
157 | * FUNCTION: acpi_ev_fixed_event_detect |
158 | * |
159 | * PARAMETERS: None |
160 | * |
161 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
162 | * |
163 | * DESCRIPTION: Checks the PM status register for active fixed events |
164 | * |
165 | ******************************************************************************/ |
166 | |
167 | u32 acpi_ev_fixed_event_detect(void) |
168 | { |
169 | u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; |
170 | u32 fixed_status; |
171 | u32 fixed_enable; |
172 | u32 i; |
173 | acpi_status status; |
174 | |
175 | ACPI_FUNCTION_NAME(ev_fixed_event_detect); |
176 | |
177 | /* |
178 | * Read the fixed feature status and enable registers, as all the cases |
179 | * depend on their values. Ignore errors here. |
180 | */ |
181 | status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); |
182 | status |= |
183 | acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); |
184 | if (ACPI_FAILURE(status)) { |
185 | return (int_status); |
186 | } |
187 | |
188 | ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, |
189 | "Fixed Event Block: Enable %08X Status %08X\n" , |
190 | fixed_enable, fixed_status)); |
191 | |
192 | /* |
193 | * Check for all possible Fixed Events and dispatch those that are active |
194 | */ |
195 | for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
196 | |
197 | /* Both the status and enable bits must be on for this event */ |
198 | |
199 | if ((fixed_status & acpi_gbl_fixed_event_info[i]. |
200 | status_bit_mask) |
201 | && (fixed_enable & acpi_gbl_fixed_event_info[i]. |
202 | enable_bit_mask)) { |
203 | /* |
204 | * Found an active (signalled) event. Invoke global event |
205 | * handler if present. |
206 | */ |
207 | acpi_fixed_event_count[i]++; |
208 | if (acpi_gbl_global_event_handler) { |
209 | acpi_gbl_global_event_handler |
210 | (ACPI_EVENT_TYPE_FIXED, NULL, i, |
211 | acpi_gbl_global_event_handler_context); |
212 | } |
213 | |
214 | int_status |= acpi_ev_fixed_event_dispatch(i); |
215 | } |
216 | } |
217 | |
218 | return (int_status); |
219 | } |
220 | |
221 | /******************************************************************************* |
222 | * |
223 | * FUNCTION: acpi_ev_fixed_event_dispatch |
224 | * |
225 | * PARAMETERS: event - Event type |
226 | * |
227 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
228 | * |
229 | * DESCRIPTION: Clears the status bit for the requested event, calls the |
230 | * handler that previously registered for the event. |
231 | * NOTE: If there is no handler for the event, the event is |
232 | * disabled to prevent further interrupts. |
233 | * |
234 | ******************************************************************************/ |
235 | |
236 | static u32 acpi_ev_fixed_event_dispatch(u32 event) |
237 | { |
238 | |
239 | ACPI_FUNCTION_ENTRY(); |
240 | |
241 | /* Clear the status bit */ |
242 | |
243 | (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
244 | status_register_id, ACPI_CLEAR_STATUS); |
245 | |
246 | /* |
247 | * Make sure that a handler exists. If not, report an error |
248 | * and disable the event to prevent further interrupts. |
249 | */ |
250 | if (!acpi_gbl_fixed_event_handlers[event].handler) { |
251 | (void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event]. |
252 | enable_register_id, |
253 | ACPI_DISABLE_EVENT); |
254 | |
255 | ACPI_ERROR((AE_INFO, |
256 | "No installed handler for fixed event - %s (%u), disabling" , |
257 | acpi_ut_get_event_name(event), event)); |
258 | |
259 | return (ACPI_INTERRUPT_NOT_HANDLED); |
260 | } |
261 | |
262 | /* Invoke the Fixed Event handler */ |
263 | |
264 | return ((acpi_gbl_fixed_event_handlers[event]. |
265 | handler) (acpi_gbl_fixed_event_handlers[event].context)); |
266 | } |
267 | |
268 | /******************************************************************************* |
269 | * |
270 | * FUNCTION: acpi_any_fixed_event_status_set |
271 | * |
272 | * PARAMETERS: None |
273 | * |
274 | * RETURN: TRUE or FALSE |
275 | * |
276 | * DESCRIPTION: Checks the PM status register for active fixed events |
277 | * |
278 | ******************************************************************************/ |
279 | |
280 | u32 acpi_any_fixed_event_status_set(void) |
281 | { |
282 | acpi_status status; |
283 | u32 in_status; |
284 | u32 in_enable; |
285 | u32 i; |
286 | |
287 | status = acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &in_enable); |
288 | if (ACPI_FAILURE(status)) { |
289 | return (FALSE); |
290 | } |
291 | |
292 | status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &in_status); |
293 | if (ACPI_FAILURE(status)) { |
294 | return (FALSE); |
295 | } |
296 | |
297 | /* |
298 | * Check for all possible Fixed Events and dispatch those that are active |
299 | */ |
300 | for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { |
301 | |
302 | /* Both the status and enable bits must be on for this event */ |
303 | |
304 | if ((in_status & acpi_gbl_fixed_event_info[i].status_bit_mask) && |
305 | (in_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) { |
306 | return (TRUE); |
307 | } |
308 | } |
309 | |
310 | return (FALSE); |
311 | } |
312 | |
313 | #endif /* !ACPI_REDUCED_HARDWARE */ |
314 | |