1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
4 * Module Name: evgpeblk - GPE block creation and initialization.
6 * Copyright (C) 2000 - 2020, Intel Corp.
8 *****************************************************************************/
10 #include <acpi/acpi.h>
15 #define _COMPONENT ACPI_EVENTS
16 ACPI_MODULE_NAME("evgpeblk")
17 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
18 /* Local prototypes */
20 acpi_ev_install_gpe_block(struct acpi_gpe_block_info
*gpe_block
,
21 u32 interrupt_number
);
24 acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info
*gpe_block
);
26 /*******************************************************************************
28 * FUNCTION: acpi_ev_install_gpe_block
30 * PARAMETERS: gpe_block - New GPE block
31 * interrupt_number - Xrupt to be associated with this
36 * DESCRIPTION: Install new GPE block with mutex support
38 ******************************************************************************/
41 acpi_ev_install_gpe_block(struct acpi_gpe_block_info
*gpe_block
,
44 struct acpi_gpe_block_info
*next_gpe_block
;
45 struct acpi_gpe_xrupt_info
*gpe_xrupt_block
;
49 ACPI_FUNCTION_TRACE(ev_install_gpe_block
);
51 status
= acpi_ut_acquire_mutex(ACPI_MTX_EVENTS
);
52 if (ACPI_FAILURE(status
)) {
53 return_ACPI_STATUS(status
);
57 acpi_ev_get_gpe_xrupt_block(interrupt_number
, &gpe_xrupt_block
);
58 if (ACPI_FAILURE(status
)) {
62 /* Install the new block at the end of the list with lock */
64 flags
= acpi_os_acquire_lock(acpi_gbl_gpe_lock
);
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
;
71 next_gpe_block
->next
= gpe_block
;
72 gpe_block
->previous
= next_gpe_block
;
74 gpe_xrupt_block
->gpe_block_list_head
= gpe_block
;
77 gpe_block
->xrupt_block
= gpe_xrupt_block
;
78 acpi_os_release_lock(acpi_gbl_gpe_lock
, flags
);
81 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS
);
82 return_ACPI_STATUS(status
);
85 /*******************************************************************************
87 * FUNCTION: acpi_ev_delete_gpe_block
89 * PARAMETERS: gpe_block - Existing GPE block
93 * DESCRIPTION: Remove a GPE block
95 ******************************************************************************/
97 acpi_status
acpi_ev_delete_gpe_block(struct acpi_gpe_block_info
*gpe_block
)
100 acpi_cpu_flags flags
;
102 ACPI_FUNCTION_TRACE(ev_install_gpe_block
);
104 status
= acpi_ut_acquire_mutex(ACPI_MTX_EVENTS
);
105 if (ACPI_FAILURE(status
)) {
106 return_ACPI_STATUS(status
);
109 /* Disable all GPEs in this block */
112 acpi_hw_disable_gpe_block(gpe_block
->xrupt_block
, gpe_block
, NULL
);
113 if (ACPI_FAILURE(status
)) {
114 return_ACPI_STATUS(status
);
117 if (!gpe_block
->previous
&& !gpe_block
->next
) {
119 /* This is the last gpe_block on this interrupt */
121 status
= acpi_ev_delete_gpe_xrupt(gpe_block
->xrupt_block
);
122 if (ACPI_FAILURE(status
)) {
123 goto unlock_and_exit
;
126 /* Remove the block on this interrupt with lock */
128 flags
= acpi_os_acquire_lock(acpi_gbl_gpe_lock
);
129 if (gpe_block
->previous
) {
130 gpe_block
->previous
->next
= gpe_block
->next
;
132 gpe_block
->xrupt_block
->gpe_block_list_head
=
136 if (gpe_block
->next
) {
137 gpe_block
->next
->previous
= gpe_block
->previous
;
140 acpi_os_release_lock(acpi_gbl_gpe_lock
, flags
);
143 acpi_current_gpe_count
-= gpe_block
->gpe_count
;
145 /* Free the gpe_block */
147 ACPI_FREE(gpe_block
->register_info
);
148 ACPI_FREE(gpe_block
->event_info
);
149 ACPI_FREE(gpe_block
);
152 status
= acpi_ut_release_mutex(ACPI_MTX_EVENTS
);
153 return_ACPI_STATUS(status
);
156 /*******************************************************************************
158 * FUNCTION: acpi_ev_create_gpe_info_blocks
160 * PARAMETERS: gpe_block - New GPE block
164 * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
166 ******************************************************************************/
169 acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info
*gpe_block
)
171 struct acpi_gpe_register_info
*gpe_register_info
= NULL
;
172 struct acpi_gpe_event_info
*gpe_event_info
= NULL
;
173 struct acpi_gpe_event_info
*this_event
;
174 struct acpi_gpe_register_info
*this_register
;
179 ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks
);
181 /* Allocate the GPE register information block */
183 gpe_register_info
= ACPI_ALLOCATE_ZEROED((acpi_size
)gpe_block
->
186 acpi_gpe_register_info
));
187 if (!gpe_register_info
) {
189 "Could not allocate the GpeRegisterInfo table"));
190 return_ACPI_STATUS(AE_NO_MEMORY
);
194 * Allocate the GPE event_info block. There are eight distinct GPEs
195 * per register. Initialization to zeros is sufficient.
197 gpe_event_info
= ACPI_ALLOCATE_ZEROED((acpi_size
)gpe_block
->gpe_count
*
199 acpi_gpe_event_info
));
200 if (!gpe_event_info
) {
202 "Could not allocate the GpeEventInfo table"));
203 status
= AE_NO_MEMORY
;
207 /* Save the new Info arrays in the GPE block */
209 gpe_block
->register_info
= gpe_register_info
;
210 gpe_block
->event_info
= gpe_event_info
;
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.
218 this_register
= gpe_register_info
;
219 this_event
= gpe_event_info
;
221 for (i
= 0; i
< gpe_block
->register_count
; i
++) {
223 /* Init the register_info for this GPE register (8 GPEs) */
225 this_register
->base_gpe_number
= (u16
)
226 (gpe_block
->block_base_number
+
227 (i
* ACPI_GPE_REGISTER_WIDTH
));
229 this_register
->status_address
.address
= gpe_block
->address
+ i
;
231 this_register
->enable_address
.address
=
232 gpe_block
->address
+ i
+ gpe_block
->register_count
;
234 this_register
->status_address
.space_id
= gpe_block
->space_id
;
235 this_register
->enable_address
.space_id
= gpe_block
->space_id
;
236 this_register
->status_address
.bit_width
=
237 ACPI_GPE_REGISTER_WIDTH
;
238 this_register
->enable_address
.bit_width
=
239 ACPI_GPE_REGISTER_WIDTH
;
240 this_register
->status_address
.bit_offset
= 0;
241 this_register
->enable_address
.bit_offset
= 0;
243 /* Init the event_info for each GPE within this register */
245 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++) {
246 this_event
->gpe_number
=
247 (u8
) (this_register
->base_gpe_number
+ j
);
248 this_event
->register_info
= this_register
;
252 /* Disable all GPEs within this register */
254 status
= acpi_hw_write(0x00, &this_register
->enable_address
);
255 if (ACPI_FAILURE(status
)) {
259 /* Clear any pending GPE events within this register */
261 status
= acpi_hw_write(0xFF, &this_register
->status_address
);
262 if (ACPI_FAILURE(status
)) {
269 return_ACPI_STATUS(AE_OK
);
272 if (gpe_register_info
) {
273 ACPI_FREE(gpe_register_info
);
275 if (gpe_event_info
) {
276 ACPI_FREE(gpe_event_info
);
279 return_ACPI_STATUS(status
);
282 /*******************************************************************************
284 * FUNCTION: acpi_ev_create_gpe_block
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
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.
299 ******************************************************************************/
302 acpi_ev_create_gpe_block(struct acpi_namespace_node
*gpe_device
,
306 u16 gpe_block_base_number
,
307 u32 interrupt_number
,
308 struct acpi_gpe_block_info
**return_gpe_block
)
311 struct acpi_gpe_block_info
*gpe_block
;
312 struct acpi_gpe_walk_info walk_info
;
314 ACPI_FUNCTION_TRACE(ev_create_gpe_block
);
316 if (!register_count
) {
317 return_ACPI_STATUS(AE_OK
);
320 /* Allocate a new GPE block */
322 gpe_block
= ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info
));
324 return_ACPI_STATUS(AE_NO_MEMORY
);
327 /* Initialize the new GPE block */
329 gpe_block
->address
= address
;
330 gpe_block
->space_id
= space_id
;
331 gpe_block
->node
= gpe_device
;
332 gpe_block
->gpe_count
= (u16
)(register_count
* ACPI_GPE_REGISTER_WIDTH
);
333 gpe_block
->initialized
= FALSE
;
334 gpe_block
->register_count
= register_count
;
335 gpe_block
->block_base_number
= gpe_block_base_number
;
338 * Create the register_info and event_info sub-structures
339 * Note: disables and clears all GPEs in the block
341 status
= acpi_ev_create_gpe_info_blocks(gpe_block
);
342 if (ACPI_FAILURE(status
)) {
343 ACPI_FREE(gpe_block
);
344 return_ACPI_STATUS(status
);
347 /* Install the new block in the global lists */
349 status
= acpi_ev_install_gpe_block(gpe_block
, interrupt_number
);
350 if (ACPI_FAILURE(status
)) {
351 ACPI_FREE(gpe_block
->register_info
);
352 ACPI_FREE(gpe_block
->event_info
);
353 ACPI_FREE(gpe_block
);
354 return_ACPI_STATUS(status
);
357 acpi_gbl_all_gpes_initialized
= FALSE
;
359 /* Find all GPE methods (_Lxx or_Exx) for this block */
361 walk_info
.gpe_block
= gpe_block
;
362 walk_info
.gpe_device
= gpe_device
;
363 walk_info
.execute_by_owner_id
= FALSE
;
365 (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
,
370 /* Return the new block */
372 if (return_gpe_block
) {
373 (*return_gpe_block
) = gpe_block
;
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
,
384 acpi_gbl_FADT
.sci_interrupt
? " (SCI)" : ""));
386 /* Update global count of currently available GPEs */
388 acpi_current_gpe_count
+= gpe_block
->gpe_count
;
389 return_ACPI_STATUS(AE_OK
);
392 /*******************************************************************************
394 * FUNCTION: acpi_ev_initialize_gpe_block
396 * PARAMETERS: acpi_gpe_callback
400 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
401 * associated methods.
402 * Note: Assumes namespace is locked.
404 ******************************************************************************/
407 acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info
*gpe_xrupt_info
,
408 struct acpi_gpe_block_info
*gpe_block
,
412 struct acpi_gpe_event_info
*gpe_event_info
;
413 u32 gpe_enabled_count
;
417 u8
*is_polling_needed
= context
;
418 ACPI_ERROR_ONLY(u32 gpe_number
);
420 ACPI_FUNCTION_TRACE(ev_initialize_gpe_block
);
423 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
424 * any GPE blocks that have been initialized already.
426 if (!gpe_block
|| gpe_block
->initialized
) {
427 return_ACPI_STATUS(AE_OK
);
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.
435 gpe_enabled_count
= 0;
437 for (i
= 0; i
< gpe_block
->register_count
; i
++) {
438 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++) {
440 /* Get the info block for this particular GPE */
442 gpe_index
= (i
* ACPI_GPE_REGISTER_WIDTH
) + j
;
443 gpe_event_info
= &gpe_block
->event_info
[gpe_index
];
444 ACPI_ERROR_ONLY(gpe_number
=
445 gpe_block
->block_base_number
+
447 gpe_event_info
->flags
|= ACPI_GPE_INITIALIZED
;
450 * Ignore GPEs that have no corresponding _Lxx/_Exx method
451 * and GPEs that are used for wakeup
453 if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info
->flags
) !=
454 ACPI_GPE_DISPATCH_METHOD
)
455 || (gpe_event_info
->flags
& ACPI_GPE_CAN_WAKE
)) {
459 status
= acpi_ev_add_gpe_reference(gpe_event_info
, FALSE
);
460 if (ACPI_FAILURE(status
)) {
461 ACPI_EXCEPTION((AE_INFO
, status
,
462 "Could not enable GPE 0x%02X",
467 gpe_event_info
->flags
|= ACPI_GPE_AUTO_ENABLED
;
469 if (is_polling_needed
&&
470 ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info
)) {
471 *is_polling_needed
= TRUE
;
478 if (gpe_enabled_count
) {
479 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))));
485 gpe_block
->initialized
= TRUE
;
487 return_ACPI_STATUS(AE_OK
);
490 #endif /* !ACPI_REDUCED_HARDWARE */