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