Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: evgpeinit - System GPE initialization and update
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acevents.h"
13 : : #include "acnamesp.h"
14 : :
15 : : #define _COMPONENT ACPI_EVENTS
16 : : ACPI_MODULE_NAME("evgpeinit")
17 : : #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
18 : : /*
19 : : * Note: History of _PRW support in ACPICA
20 : : *
21 : : * Originally (2000 - 2010), the GPE initialization code performed a walk of
22 : : * the entire namespace to execute the _PRW methods and detect all GPEs
23 : : * capable of waking the system.
24 : : *
25 : : * As of 10/2010, the _PRW method execution has been removed since it is
26 : : * actually unnecessary. The host OS must in fact execute all _PRW methods
27 : : * in order to identify the device/power-resource dependencies. We now put
28 : : * the onus on the host OS to identify the wake GPEs as part of this process
29 : : * and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This
30 : : * not only reduces the complexity of the ACPICA initialization code, but in
31 : : * some cases (on systems with very large namespaces) it should reduce the
32 : : * kernel boot time as well.
33 : : */
34 : :
35 : : /*******************************************************************************
36 : : *
37 : : * FUNCTION: acpi_ev_gpe_initialize
38 : : *
39 : : * PARAMETERS: None
40 : : *
41 : : * RETURN: Status
42 : : *
43 : : * DESCRIPTION: Initialize the GPE data structures and the FADT GPE 0/1 blocks
44 : : *
45 : : ******************************************************************************/
46 : 21 : acpi_status acpi_ev_gpe_initialize(void)
47 : : {
48 : 21 : u32 register_count0 = 0;
49 : 21 : u32 register_count1 = 0;
50 : 21 : u32 gpe_number_max = 0;
51 : 21 : acpi_status status;
52 : :
53 : 21 : ACPI_FUNCTION_TRACE(ev_gpe_initialize);
54 : :
55 : : ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
56 : 21 : "Initializing General Purpose Events (GPEs):\n"));
57 : :
58 : 21 : status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
59 [ + - ]: 21 : if (ACPI_FAILURE(status)) {
60 : : return_ACPI_STATUS(status);
61 : : }
62 : :
63 : : /*
64 : : * Initialize the GPE Block(s) defined in the FADT
65 : : *
66 : : * Why the GPE register block lengths are divided by 2: From the ACPI
67 : : * Spec, section "General-Purpose Event Registers", we have:
68 : : *
69 : : * "Each register block contains two registers of equal length
70 : : * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
71 : : * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
72 : : * The length of the GPE1_STS and GPE1_EN registers is equal to
73 : : * half the GPE1_LEN. If a generic register block is not supported
74 : : * then its respective block pointer and block length values in the
75 : : * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
76 : : * to be the same size."
77 : : */
78 : :
79 : : /*
80 : : * Determine the maximum GPE number for this machine.
81 : : *
82 : : * Note: both GPE0 and GPE1 are optional, and either can exist without
83 : : * the other.
84 : : *
85 : : * If EITHER the register length OR the block address are zero, then that
86 : : * particular block is not supported.
87 : : */
88 [ + - ]: 21 : if (acpi_gbl_FADT.gpe0_block_length &&
89 [ + - ]: 21 : acpi_gbl_FADT.xgpe0_block.address) {
90 : :
91 : : /* GPE block 0 exists (has both length and address > 0) */
92 : :
93 : 21 : register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2);
94 : 21 : gpe_number_max =
95 : 21 : (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
96 : :
97 : : /* Install GPE Block 0 */
98 : :
99 : 21 : status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
100 : : acpi_gbl_FADT.xgpe0_block.
101 : : address,
102 : 21 : acpi_gbl_FADT.xgpe0_block.
103 : : space_id, register_count0, 0,
104 : 21 : acpi_gbl_FADT.sci_interrupt,
105 : : &acpi_gbl_gpe_fadt_blocks[0]);
106 : :
107 [ - + ]: 21 : if (ACPI_FAILURE(status)) {
108 : 0 : ACPI_EXCEPTION((AE_INFO, status,
109 : : "Could not create GPE Block 0"));
110 : : }
111 : : }
112 : :
113 [ - + ]: 21 : if (acpi_gbl_FADT.gpe1_block_length &&
114 [ # # ]: 0 : acpi_gbl_FADT.xgpe1_block.address) {
115 : :
116 : : /* GPE block 1 exists (has both length and address > 0) */
117 : :
118 : 0 : register_count1 = (u16)(acpi_gbl_FADT.gpe1_block_length / 2);
119 : :
120 : : /* Check for GPE0/GPE1 overlap (if both banks exist) */
121 : :
122 [ # # ]: 0 : if ((register_count0) &&
123 [ # # ]: 0 : (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
124 : 0 : ACPI_ERROR((AE_INFO,
125 : : "GPE0 block (GPE 0 to %u) overlaps the GPE1 block "
126 : : "(GPE %u to %u) - Ignoring GPE1",
127 : : gpe_number_max, acpi_gbl_FADT.gpe1_base,
128 : : acpi_gbl_FADT.gpe1_base +
129 : : ((register_count1 *
130 : : ACPI_GPE_REGISTER_WIDTH) - 1)));
131 : :
132 : : /* Ignore GPE1 block by setting the register count to zero */
133 : :
134 : 0 : register_count1 = 0;
135 : : } else {
136 : : /* Install GPE Block 1 */
137 : :
138 : 0 : status =
139 : 0 : acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
140 : : acpi_gbl_FADT.xgpe1_block.
141 : : address,
142 : 0 : acpi_gbl_FADT.xgpe1_block.
143 : : space_id, register_count1,
144 : 0 : acpi_gbl_FADT.gpe1_base,
145 : 0 : acpi_gbl_FADT.
146 : : sci_interrupt,
147 : : &acpi_gbl_gpe_fadt_blocks
148 : : [1]);
149 : :
150 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
151 : 0 : ACPI_EXCEPTION((AE_INFO, status,
152 : : "Could not create GPE Block 1"));
153 : : }
154 : :
155 : : /*
156 : : * GPE0 and GPE1 do not have to be contiguous in the GPE number
157 : : * space. However, GPE0 always starts at GPE number zero.
158 : : */
159 : : }
160 : : }
161 : :
162 : : /* Exit if there are no GPE registers */
163 : :
164 : 21 : if ((register_count0 + register_count1) == 0) {
165 : :
166 : : /* GPEs are not required by ACPI, this is OK */
167 : :
168 : : ACPI_DEBUG_PRINT((ACPI_DB_INIT,
169 : : "There are no GPE blocks defined in the FADT\n"));
170 : : goto cleanup;
171 : : }
172 : :
173 : : cleanup:
174 : 21 : (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
175 : 21 : return_ACPI_STATUS(AE_OK);
176 : : }
177 : :
178 : : /*******************************************************************************
179 : : *
180 : : * FUNCTION: acpi_ev_update_gpes
181 : : *
182 : : * PARAMETERS: table_owner_id - ID of the newly-loaded ACPI table
183 : : *
184 : : * RETURN: None
185 : : *
186 : : * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
187 : : * result of a Load() or load_table() operation. If new GPE
188 : : * methods have been installed, register the new methods.
189 : : *
190 : : ******************************************************************************/
191 : :
192 : 0 : void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
193 : : {
194 : 0 : struct acpi_gpe_xrupt_info *gpe_xrupt_info;
195 : 0 : struct acpi_gpe_block_info *gpe_block;
196 : 0 : struct acpi_gpe_walk_info walk_info;
197 : 0 : acpi_status status = AE_OK;
198 : :
199 : : /*
200 : : * Find any _Lxx/_Exx GPE methods that have just been loaded.
201 : : *
202 : : * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
203 : : * enabled.
204 : : *
205 : : * Examine the namespace underneath each gpe_device within the
206 : : * gpe_block lists.
207 : : */
208 : 0 : status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
209 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
210 : : return;
211 : : }
212 : :
213 : 0 : walk_info.count = 0;
214 : 0 : walk_info.owner_id = table_owner_id;
215 : 0 : walk_info.execute_by_owner_id = TRUE;
216 : :
217 : : /* Walk the interrupt level descriptor list */
218 : :
219 : 0 : gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
220 [ # # ]: 0 : while (gpe_xrupt_info) {
221 : :
222 : : /* Walk all Gpe Blocks attached to this interrupt level */
223 : :
224 : 0 : gpe_block = gpe_xrupt_info->gpe_block_list_head;
225 [ # # ]: 0 : while (gpe_block) {
226 : 0 : walk_info.gpe_block = gpe_block;
227 : 0 : walk_info.gpe_device = gpe_block->node;
228 : :
229 : 0 : status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD,
230 : : walk_info.gpe_device,
231 : : ACPI_UINT32_MAX,
232 : : ACPI_NS_WALK_NO_UNLOCK,
233 : : acpi_ev_match_gpe_method,
234 : : NULL, &walk_info, NULL);
235 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
236 : 0 : ACPI_EXCEPTION((AE_INFO, status,
237 : : "While decoding _Lxx/_Exx methods"));
238 : : }
239 : :
240 : 0 : gpe_block = gpe_block->next;
241 : : }
242 : :
243 : 0 : gpe_xrupt_info = gpe_xrupt_info->next;
244 : : }
245 : :
246 [ # # ]: 0 : if (walk_info.count) {
247 : 0 : ACPI_INFO(("Enabled %u new GPEs", walk_info.count));
248 : : }
249 : :
250 : 0 : (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
251 : 0 : return;
252 : : }
253 : :
254 : : /*******************************************************************************
255 : : *
256 : : * FUNCTION: acpi_ev_match_gpe_method
257 : : *
258 : : * PARAMETERS: Callback from walk_namespace
259 : : *
260 : : * RETURN: Status
261 : : *
262 : : * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
263 : : * control method under the _GPE portion of the namespace.
264 : : * Extract the name and GPE type from the object, saving this
265 : : * information for quick lookup during GPE dispatch. Allows a
266 : : * per-owner_id evaluation if execute_by_owner_id is TRUE in the
267 : : * walk_info parameter block.
268 : : *
269 : : * The name of each GPE control method is of the form:
270 : : * "_Lxx" or "_Exx", where:
271 : : * L - means that the GPE is level triggered
272 : : * E - means that the GPE is edge triggered
273 : : * xx - is the GPE number [in HEX]
274 : : *
275 : : * If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
276 : : * with that owner.
277 : : *
278 : : ******************************************************************************/
279 : :
280 : : acpi_status
281 : 42 : acpi_ev_match_gpe_method(acpi_handle obj_handle,
282 : : u32 level, void *context, void **return_value)
283 : : {
284 : 42 : struct acpi_namespace_node *method_node =
285 : : ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
286 : 42 : struct acpi_gpe_walk_info *walk_info =
287 : : ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
288 : 42 : struct acpi_gpe_event_info *gpe_event_info;
289 : 42 : acpi_status status;
290 : 42 : u32 gpe_number;
291 : 42 : u8 temp_gpe_number;
292 : 42 : char name[ACPI_NAMESEG_SIZE + 1];
293 : 42 : u8 type;
294 : :
295 : 42 : ACPI_FUNCTION_TRACE(ev_match_gpe_method);
296 : :
297 : : /* Check if requested owner_id matches this owner_id */
298 : :
299 [ - + ]: 42 : if ((walk_info->execute_by_owner_id) &&
300 [ # # ]: 0 : (method_node->owner_id != walk_info->owner_id)) {
301 : : return_ACPI_STATUS(AE_OK);
302 : : }
303 : :
304 : : /*
305 : : * Match and decode the _Lxx and _Exx GPE method names
306 : : *
307 : : * 1) Extract the method name and null terminate it
308 : : */
309 : 42 : ACPI_MOVE_32_TO_32(name, &method_node->name.integer);
310 : 42 : name[ACPI_NAMESEG_SIZE] = 0;
311 : :
312 : : /* 2) Name must begin with an underscore */
313 : :
314 [ + - ]: 42 : if (name[0] != '_') {
315 : : return_ACPI_STATUS(AE_OK); /* Ignore this method */
316 : : }
317 : :
318 : : /*
319 : : * 3) Edge/Level determination is based on the 2nd character
320 : : * of the method name
321 : : */
322 [ + - - ]: 42 : switch (name[1]) {
323 : : case 'L':
324 : :
325 : : type = ACPI_GPE_LEVEL_TRIGGERED;
326 : : break;
327 : :
328 : 42 : case 'E':
329 : :
330 : 42 : type = ACPI_GPE_EDGE_TRIGGERED;
331 : 42 : break;
332 : :
333 : : default:
334 : :
335 : : /* Unknown method type, just ignore it */
336 : :
337 : : ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
338 : : "Ignoring unknown GPE method type: %s "
339 : : "(name not of form _Lxx or _Exx)", name));
340 : : return_ACPI_STATUS(AE_OK);
341 : : }
342 : :
343 : : /* 4) The last two characters of the name are the hex GPE Number */
344 : :
345 : 42 : status = acpi_ut_ascii_to_hex_byte(&name[2], &temp_gpe_number);
346 [ + - ]: 42 : if (ACPI_FAILURE(status)) {
347 : :
348 : : /* Conversion failed; invalid method, just ignore it */
349 : :
350 : : ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
351 : : "Could not extract GPE number from name: %s "
352 : : "(name is not of form _Lxx or _Exx)", name));
353 : : return_ACPI_STATUS(AE_OK);
354 : : }
355 : :
356 : : /* Ensure that we have a valid GPE number for this GPE block */
357 : :
358 : 42 : gpe_number = (u32)temp_gpe_number;
359 : 42 : gpe_event_info =
360 : 42 : acpi_ev_low_get_gpe_info(gpe_number, walk_info->gpe_block);
361 [ + - ]: 42 : if (!gpe_event_info) {
362 : : /*
363 : : * This gpe_number is not valid for this GPE block, just ignore it.
364 : : * However, it may be valid for a different GPE block, since GPE0
365 : : * and GPE1 methods both appear under \_GPE.
366 : : */
367 : : return_ACPI_STATUS(AE_OK);
368 : : }
369 : :
370 : 42 : if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
371 [ + - ]: 42 : ACPI_GPE_DISPATCH_HANDLER) ||
372 : : (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
373 : : ACPI_GPE_DISPATCH_RAW_HANDLER)) {
374 : :
375 : : /* If there is already a handler, ignore this GPE method */
376 : :
377 : : return_ACPI_STATUS(AE_OK);
378 : : }
379 : :
380 [ - + ]: 42 : if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
381 : : ACPI_GPE_DISPATCH_METHOD) {
382 : : /*
383 : : * If there is already a method, ignore this method. But check
384 : : * for a type mismatch (if both the _Lxx AND _Exx exist)
385 : : */
386 [ # # ]: 0 : if (type != (gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
387 : 0 : ACPI_ERROR((AE_INFO,
388 : : "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods",
389 : : gpe_number, gpe_number, gpe_number));
390 : : }
391 : 0 : return_ACPI_STATUS(AE_OK);
392 : : }
393 : :
394 : : /* Disable the GPE in case it's been enabled already. */
395 : :
396 : 42 : (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
397 : :
398 : : /*
399 : : * Add the GPE information from above to the gpe_event_info block for
400 : : * use during dispatch of this GPE.
401 : : */
402 : 42 : gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK);
403 : 42 : gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
404 : 42 : gpe_event_info->dispatch.method_node = method_node;
405 : :
406 : : ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
407 : : "Registered GPE method %s as GPE number 0x%.2X\n",
408 : 42 : name, gpe_number));
409 : 42 : return_ACPI_STATUS(AE_OK);
410 : : }
411 : :
412 : : #endif /* !ACPI_REDUCED_HARDWARE */
|