Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: evgpeblk - GPE block creation and initialization.
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("evgpeblk")
17 : : #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
18 : : /* Local prototypes */
19 : : static acpi_status
20 : : acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
21 : : u32 interrupt_number);
22 : :
23 : : static acpi_status
24 : : acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
25 : :
26 : : /*******************************************************************************
27 : : *
28 : : * FUNCTION: acpi_ev_install_gpe_block
29 : : *
30 : : * PARAMETERS: gpe_block - New GPE block
31 : : * interrupt_number - Xrupt to be associated with this
32 : : * GPE block
33 : : *
34 : : * RETURN: Status
35 : : *
36 : : * DESCRIPTION: Install new GPE block with mutex support
37 : : *
38 : : ******************************************************************************/
39 : :
40 : : static acpi_status
41 : 13 : acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
42 : : u32 interrupt_number)
43 : : {
44 : 13 : struct acpi_gpe_block_info *next_gpe_block;
45 : 13 : struct acpi_gpe_xrupt_info *gpe_xrupt_block;
46 : 13 : acpi_status status;
47 : 13 : acpi_cpu_flags flags;
48 : :
49 : 13 : ACPI_FUNCTION_TRACE(ev_install_gpe_block);
50 : :
51 : 13 : status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
52 [ + - ]: 13 : if (ACPI_FAILURE(status)) {
53 : : return_ACPI_STATUS(status);
54 : : }
55 : :
56 : 13 : status =
57 : 13 : acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
58 [ - + ]: 13 : if (ACPI_FAILURE(status)) {
59 : 0 : goto unlock_and_exit;
60 : : }
61 : :
62 : : /* Install the new block at the end of the list with lock */
63 : :
64 : 13 : flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
65 [ - + ]: 13 : if (gpe_xrupt_block->gpe_block_list_head) {
66 : : next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
67 [ # # ]: 0 : while (next_gpe_block->next) {
68 : : next_gpe_block = next_gpe_block->next;
69 : : }
70 : :
71 : 0 : next_gpe_block->next = gpe_block;
72 : 0 : gpe_block->previous = next_gpe_block;
73 : : } else {
74 : 13 : gpe_xrupt_block->gpe_block_list_head = gpe_block;
75 : : }
76 : :
77 : 13 : gpe_block->xrupt_block = gpe_xrupt_block;
78 : 13 : acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
79 : :
80 : 13 : unlock_and_exit:
81 : 13 : (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
82 : 13 : return_ACPI_STATUS(status);
83 : : }
84 : :
85 : : /*******************************************************************************
86 : : *
87 : : * FUNCTION: acpi_ev_delete_gpe_block
88 : : *
89 : : * PARAMETERS: gpe_block - Existing GPE block
90 : : *
91 : : * RETURN: Status
92 : : *
93 : : * DESCRIPTION: Remove a GPE block
94 : : *
95 : : ******************************************************************************/
96 : :
97 : 0 : acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
98 : : {
99 : 0 : acpi_status status;
100 : 0 : acpi_cpu_flags flags;
101 : :
102 : 0 : ACPI_FUNCTION_TRACE(ev_install_gpe_block);
103 : :
104 : 0 : status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
105 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
106 : : return_ACPI_STATUS(status);
107 : : }
108 : :
109 : : /* Disable all GPEs in this block */
110 : :
111 : 0 : status =
112 : 0 : acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
113 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
114 : : return_ACPI_STATUS(status);
115 : : }
116 : :
117 [ # # # # ]: 0 : if (!gpe_block->previous && !gpe_block->next) {
118 : :
119 : : /* This is the last gpe_block on this interrupt */
120 : :
121 : 0 : status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
122 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
123 : 0 : goto unlock_and_exit;
124 : : }
125 : : } else {
126 : : /* Remove the block on this interrupt with lock */
127 : :
128 : 0 : flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
129 [ # # ]: 0 : if (gpe_block->previous) {
130 : 0 : gpe_block->previous->next = gpe_block->next;
131 : : } else {
132 : 0 : gpe_block->xrupt_block->gpe_block_list_head =
133 : 0 : gpe_block->next;
134 : : }
135 : :
136 [ # # ]: 0 : if (gpe_block->next) {
137 : 0 : gpe_block->next->previous = gpe_block->previous;
138 : : }
139 : :
140 : 0 : acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
141 : : }
142 : :
143 : 0 : acpi_current_gpe_count -= gpe_block->gpe_count;
144 : :
145 : : /* Free the gpe_block */
146 : :
147 : 0 : ACPI_FREE(gpe_block->register_info);
148 : 0 : ACPI_FREE(gpe_block->event_info);
149 : 0 : ACPI_FREE(gpe_block);
150 : :
151 : 0 : unlock_and_exit:
152 : 0 : status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
153 : 0 : return_ACPI_STATUS(status);
154 : : }
155 : :
156 : : /*******************************************************************************
157 : : *
158 : : * FUNCTION: acpi_ev_create_gpe_info_blocks
159 : : *
160 : : * PARAMETERS: gpe_block - New GPE block
161 : : *
162 : : * RETURN: Status
163 : : *
164 : : * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
165 : : *
166 : : ******************************************************************************/
167 : :
168 : : static acpi_status
169 : 13 : acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
170 : : {
171 : 13 : struct acpi_gpe_register_info *gpe_register_info = NULL;
172 : 13 : struct acpi_gpe_event_info *gpe_event_info = NULL;
173 : 13 : struct acpi_gpe_event_info *this_event;
174 : 13 : struct acpi_gpe_register_info *this_register;
175 : 13 : u32 i;
176 : 13 : u32 j;
177 : 13 : acpi_status status;
178 : :
179 : 13 : ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
180 : :
181 : : /* Allocate the GPE register information block */
182 : :
183 : 13 : gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->
184 : : register_count *
185 : : sizeof(struct
186 : : acpi_gpe_register_info));
187 [ - + ]: 13 : if (!gpe_register_info) {
188 : 0 : ACPI_ERROR((AE_INFO,
189 : : "Could not allocate the GpeRegisterInfo table"));
190 : 0 : return_ACPI_STATUS(AE_NO_MEMORY);
191 : : }
192 : :
193 : : /*
194 : : * Allocate the GPE event_info block. There are eight distinct GPEs
195 : : * per register. Initialization to zeros is sufficient.
196 : : */
197 : 13 : gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count *
198 : : sizeof(struct
199 : : acpi_gpe_event_info));
200 [ - + ]: 13 : if (!gpe_event_info) {
201 : 0 : ACPI_ERROR((AE_INFO,
202 : : "Could not allocate the GpeEventInfo table"));
203 : 0 : status = AE_NO_MEMORY;
204 : 0 : goto error_exit;
205 : : }
206 : :
207 : : /* Save the new Info arrays in the GPE block */
208 : :
209 : 13 : gpe_block->register_info = gpe_register_info;
210 : 13 : gpe_block->event_info = gpe_event_info;
211 : :
212 : : /*
213 : : * Initialize the GPE Register and Event structures. A goal of these
214 : : * tables is to hide the fact that there are two separate GPE register
215 : : * sets in a given GPE hardware block, the status registers occupy the
216 : : * first half, and the enable registers occupy the second half.
217 : : */
218 : 13 : this_register = gpe_register_info;
219 : 13 : this_event = gpe_event_info;
220 : :
221 [ + + ]: 39 : for (i = 0; i < gpe_block->register_count; i++) {
222 : :
223 : : /* Init the register_info for this GPE register (8 GPEs) */
224 : :
225 : 26 : this_register->base_gpe_number = (u16)
226 : 26 : (gpe_block->block_base_number +
227 : : (i * ACPI_GPE_REGISTER_WIDTH));
228 : :
229 : 26 : this_register->status_address.address = gpe_block->address + i;
230 : :
231 : 26 : this_register->enable_address.address =
232 : 26 : gpe_block->address + i + gpe_block->register_count;
233 : :
234 : 26 : this_register->status_address.space_id = gpe_block->space_id;
235 : 26 : this_register->enable_address.space_id = gpe_block->space_id;
236 : 26 : this_register->status_address.bit_width =
237 : : ACPI_GPE_REGISTER_WIDTH;
238 : 26 : this_register->enable_address.bit_width =
239 : : ACPI_GPE_REGISTER_WIDTH;
240 : 26 : this_register->status_address.bit_offset = 0;
241 : 26 : this_register->enable_address.bit_offset = 0;
242 : :
243 : : /* Init the event_info for each GPE within this register */
244 : :
245 [ + + ]: 234 : for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
246 : 208 : this_event->gpe_number =
247 : 208 : (u8) (this_register->base_gpe_number + j);
248 : 208 : this_event->register_info = this_register;
249 : 208 : this_event++;
250 : : }
251 : :
252 : : /* Disable all GPEs within this register */
253 : :
254 : 26 : status = acpi_hw_write(0x00, &this_register->enable_address);
255 [ - + ]: 26 : if (ACPI_FAILURE(status)) {
256 : 0 : goto error_exit;
257 : : }
258 : :
259 : : /* Clear any pending GPE events within this register */
260 : :
261 : 26 : status = acpi_hw_write(0xFF, &this_register->status_address);
262 [ - + ]: 26 : if (ACPI_FAILURE(status)) {
263 : 0 : goto error_exit;
264 : : }
265 : :
266 : 26 : this_register++;
267 : : }
268 : :
269 : : return_ACPI_STATUS(AE_OK);
270 : :
271 : 0 : error_exit:
272 : 0 : if (gpe_register_info) {
273 : 0 : ACPI_FREE(gpe_register_info);
274 : : }
275 [ # # ]: 0 : if (gpe_event_info) {
276 : 0 : ACPI_FREE(gpe_event_info);
277 : : }
278 : :
279 : : return_ACPI_STATUS(status);
280 : : }
281 : :
282 : : /*******************************************************************************
283 : : *
284 : : * FUNCTION: acpi_ev_create_gpe_block
285 : : *
286 : : * PARAMETERS: gpe_device - Handle to the parent GPE block
287 : : * gpe_block_address - Address and space_ID
288 : : * register_count - Number of GPE register pairs in the block
289 : : * gpe_block_base_number - Starting GPE number for the block
290 : : * interrupt_number - H/W interrupt for the block
291 : : * return_gpe_block - Where the new block descriptor is returned
292 : : *
293 : : * RETURN: Status
294 : : *
295 : : * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
296 : : * the block are disabled at exit.
297 : : * Note: Assumes namespace is locked.
298 : : *
299 : : ******************************************************************************/
300 : :
301 : : acpi_status
302 : 13 : acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
303 : : u64 address,
304 : : u8 space_id,
305 : : u32 register_count,
306 : : u16 gpe_block_base_number,
307 : : u32 interrupt_number,
308 : : struct acpi_gpe_block_info **return_gpe_block)
309 : : {
310 : 13 : acpi_status status;
311 : 13 : struct acpi_gpe_block_info *gpe_block;
312 : 13 : struct acpi_gpe_walk_info walk_info;
313 : :
314 : 13 : ACPI_FUNCTION_TRACE(ev_create_gpe_block);
315 : :
316 [ + - ]: 13 : if (!register_count) {
317 : : return_ACPI_STATUS(AE_OK);
318 : : }
319 : :
320 : : /* Allocate a new GPE block */
321 : :
322 : 13 : gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
323 [ + - ]: 13 : if (!gpe_block) {
324 : : return_ACPI_STATUS(AE_NO_MEMORY);
325 : : }
326 : :
327 : : /* Initialize the new GPE block */
328 : :
329 : 13 : gpe_block->address = address;
330 : 13 : gpe_block->space_id = space_id;
331 : 13 : gpe_block->node = gpe_device;
332 : 13 : gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
333 : 13 : gpe_block->initialized = FALSE;
334 : 13 : gpe_block->register_count = register_count;
335 : 13 : gpe_block->block_base_number = gpe_block_base_number;
336 : :
337 : : /*
338 : : * Create the register_info and event_info sub-structures
339 : : * Note: disables and clears all GPEs in the block
340 : : */
341 : 13 : status = acpi_ev_create_gpe_info_blocks(gpe_block);
342 [ - + ]: 13 : if (ACPI_FAILURE(status)) {
343 : 0 : ACPI_FREE(gpe_block);
344 : 0 : return_ACPI_STATUS(status);
345 : : }
346 : :
347 : : /* Install the new block in the global lists */
348 : :
349 : 13 : status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
350 [ - + ]: 13 : if (ACPI_FAILURE(status)) {
351 : 0 : ACPI_FREE(gpe_block->register_info);
352 : 0 : ACPI_FREE(gpe_block->event_info);
353 : 0 : ACPI_FREE(gpe_block);
354 : 0 : return_ACPI_STATUS(status);
355 : : }
356 : :
357 : 13 : acpi_gbl_all_gpes_initialized = FALSE;
358 : :
359 : : /* Find all GPE methods (_Lxx or_Exx) for this block */
360 : :
361 : 13 : walk_info.gpe_block = gpe_block;
362 : 13 : walk_info.gpe_device = gpe_device;
363 : 13 : walk_info.execute_by_owner_id = FALSE;
364 : :
365 : 13 : (void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
366 : : ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
367 : : acpi_ev_match_gpe_method, NULL, &walk_info,
368 : : NULL);
369 : :
370 : : /* Return the new block */
371 : :
372 [ + - ]: 13 : if (return_gpe_block) {
373 : 13 : (*return_gpe_block) = gpe_block;
374 : : }
375 : :
376 : : ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
377 : : " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
378 : : (u32)gpe_block->block_base_number,
379 : : (u32)(gpe_block->block_base_number +
380 : : (gpe_block->gpe_count - 1)),
381 : : gpe_device->name.ascii, gpe_block->register_count,
382 : : interrupt_number,
383 : : interrupt_number ==
384 : 13 : acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
385 : :
386 : : /* Update global count of currently available GPEs */
387 : :
388 : 13 : acpi_current_gpe_count += gpe_block->gpe_count;
389 : 13 : return_ACPI_STATUS(AE_OK);
390 : : }
391 : :
392 : : /*******************************************************************************
393 : : *
394 : : * FUNCTION: acpi_ev_initialize_gpe_block
395 : : *
396 : : * PARAMETERS: acpi_gpe_callback
397 : : *
398 : : * RETURN: Status
399 : : *
400 : : * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
401 : : * associated methods.
402 : : * Note: Assumes namespace is locked.
403 : : *
404 : : ******************************************************************************/
405 : :
406 : : acpi_status
407 : 13 : acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
408 : : struct acpi_gpe_block_info *gpe_block,
409 : : void *context)
410 : : {
411 : 13 : acpi_status status;
412 : 13 : struct acpi_gpe_event_info *gpe_event_info;
413 : 13 : u32 gpe_enabled_count;
414 : 13 : u32 gpe_index;
415 : 13 : u32 i;
416 : 13 : u32 j;
417 : 13 : u8 *is_polling_needed = context;
418 : 13 : ACPI_ERROR_ONLY(u32 gpe_number);
419 : :
420 : 13 : ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
421 : :
422 : : /*
423 : : * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
424 : : * any GPE blocks that have been initialized already.
425 : : */
426 [ + - + - ]: 13 : if (!gpe_block || gpe_block->initialized) {
427 : : return_ACPI_STATUS(AE_OK);
428 : : }
429 : :
430 : : /*
431 : : * Enable all GPEs that have a corresponding method and have the
432 : : * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
433 : : * must be enabled via the acpi_enable_gpe() interface.
434 : : */
435 : : gpe_enabled_count = 0;
436 : :
437 [ + + ]: 39 : for (i = 0; i < gpe_block->register_count; i++) {
438 [ + + ]: 234 : for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
439 : :
440 : : /* Get the info block for this particular GPE */
441 : :
442 : 208 : gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
443 : 208 : gpe_event_info = &gpe_block->event_info[gpe_index];
444 : 208 : ACPI_ERROR_ONLY(gpe_number =
445 : : gpe_block->block_base_number +
446 : : gpe_index);
447 : 208 : gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
448 : :
449 : : /*
450 : : * Ignore GPEs that have no corresponding _Lxx/_Exx method
451 : : * and GPEs that are used for wakeup
452 : : */
453 [ + + ]: 208 : if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
454 : : ACPI_GPE_DISPATCH_METHOD)
455 : : || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
456 : 182 : continue;
457 : : }
458 : :
459 : 26 : status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
460 [ - + ]: 26 : if (ACPI_FAILURE(status)) {
461 : 0 : ACPI_EXCEPTION((AE_INFO, status,
462 : : "Could not enable GPE 0x%02X",
463 : : gpe_number));
464 : 0 : continue;
465 : : }
466 : :
467 : 26 : gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
468 : :
469 [ + - ]: 26 : if (is_polling_needed &&
470 [ + - + - ]: 26 : ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
471 : 26 : *is_polling_needed = TRUE;
472 : : }
473 : :
474 : 26 : gpe_enabled_count++;
475 : : }
476 : : }
477 : :
478 [ + - ]: 13 : if (gpe_enabled_count) {
479 : 13 : ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",
480 : : gpe_enabled_count, (u32)gpe_block->block_base_number,
481 : : (u32)(gpe_block->block_base_number +
482 : : (gpe_block->gpe_count - 1))));
483 : : }
484 : :
485 : 13 : gpe_block->initialized = TRUE;
486 : :
487 : 13 : return_ACPI_STATUS(AE_OK);
488 : : }
489 : :
490 : : #endif /* !ACPI_REDUCED_HARDWARE */
|