162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: evgpeblk - GPE block creation and initialization. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acevents.h" 1362306a36Sopenharmony_ci#include "acnamesp.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define _COMPONENT ACPI_EVENTS 1662306a36Sopenharmony_ciACPI_MODULE_NAME("evgpeblk") 1762306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 1862306a36Sopenharmony_ci/* Local prototypes */ 1962306a36Sopenharmony_cistatic acpi_status 2062306a36Sopenharmony_ciacpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, 2162306a36Sopenharmony_ci u32 interrupt_number); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic acpi_status 2462306a36Sopenharmony_ciacpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/******************************************************************************* 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * FUNCTION: acpi_ev_install_gpe_block 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * PARAMETERS: gpe_block - New GPE block 3162306a36Sopenharmony_ci * interrupt_number - Xrupt to be associated with this 3262306a36Sopenharmony_ci * GPE block 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * RETURN: Status 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * DESCRIPTION: Install new GPE block with mutex support 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci ******************************************************************************/ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic acpi_status 4162306a36Sopenharmony_ciacpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, 4262306a36Sopenharmony_ci u32 interrupt_number) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct acpi_gpe_block_info *next_gpe_block; 4562306a36Sopenharmony_ci struct acpi_gpe_xrupt_info *gpe_xrupt_block; 4662306a36Sopenharmony_ci acpi_status status; 4762306a36Sopenharmony_ci acpi_cpu_flags flags; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_install_gpe_block); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); 5262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 5362306a36Sopenharmony_ci return_ACPI_STATUS(status); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci status = 5762306a36Sopenharmony_ci acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block); 5862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 5962306a36Sopenharmony_ci goto unlock_and_exit; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Install the new block at the end of the list with lock */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 6562306a36Sopenharmony_ci if (gpe_xrupt_block->gpe_block_list_head) { 6662306a36Sopenharmony_ci next_gpe_block = gpe_xrupt_block->gpe_block_list_head; 6762306a36Sopenharmony_ci while (next_gpe_block->next) { 6862306a36Sopenharmony_ci next_gpe_block = next_gpe_block->next; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci next_gpe_block->next = gpe_block; 7262306a36Sopenharmony_ci gpe_block->previous = next_gpe_block; 7362306a36Sopenharmony_ci } else { 7462306a36Sopenharmony_ci gpe_xrupt_block->gpe_block_list_head = gpe_block; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci gpe_block->xrupt_block = gpe_xrupt_block; 7862306a36Sopenharmony_ci acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciunlock_and_exit: 8162306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); 8262306a36Sopenharmony_ci return_ACPI_STATUS(status); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/******************************************************************************* 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * FUNCTION: acpi_ev_delete_gpe_block 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * PARAMETERS: gpe_block - Existing GPE block 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * RETURN: Status 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * DESCRIPTION: Remove a GPE block 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci ******************************************************************************/ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciacpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci acpi_status status; 10062306a36Sopenharmony_ci acpi_cpu_flags flags; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_install_gpe_block); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); 10562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10662306a36Sopenharmony_ci return_ACPI_STATUS(status); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Disable all GPEs in this block */ 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci status = 11262306a36Sopenharmony_ci acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL); 11362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 11462306a36Sopenharmony_ci return_ACPI_STATUS(status); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (!gpe_block->previous && !gpe_block->next) { 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* This is the last gpe_block on this interrupt */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block); 12262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12362306a36Sopenharmony_ci goto unlock_and_exit; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci } else { 12662306a36Sopenharmony_ci /* Remove the block on this interrupt with lock */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 12962306a36Sopenharmony_ci if (gpe_block->previous) { 13062306a36Sopenharmony_ci gpe_block->previous->next = gpe_block->next; 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci gpe_block->xrupt_block->gpe_block_list_head = 13362306a36Sopenharmony_ci gpe_block->next; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (gpe_block->next) { 13762306a36Sopenharmony_ci gpe_block->next->previous = gpe_block->previous; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci acpi_current_gpe_count -= gpe_block->gpe_count; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Free the gpe_block */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ACPI_FREE(gpe_block->register_info); 14862306a36Sopenharmony_ci ACPI_FREE(gpe_block->event_info); 14962306a36Sopenharmony_ci ACPI_FREE(gpe_block); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciunlock_and_exit: 15262306a36Sopenharmony_ci status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); 15362306a36Sopenharmony_ci return_ACPI_STATUS(status); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/******************************************************************************* 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * FUNCTION: acpi_ev_create_gpe_info_blocks 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * PARAMETERS: gpe_block - New GPE block 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * RETURN: Status 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * DESCRIPTION: Create the register_info and event_info blocks for this GPE block 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci ******************************************************************************/ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic acpi_status 16962306a36Sopenharmony_ciacpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct acpi_gpe_register_info *gpe_register_info = NULL; 17262306a36Sopenharmony_ci struct acpi_gpe_event_info *gpe_event_info = NULL; 17362306a36Sopenharmony_ci struct acpi_gpe_event_info *this_event; 17462306a36Sopenharmony_ci struct acpi_gpe_register_info *this_register; 17562306a36Sopenharmony_ci u32 i; 17662306a36Sopenharmony_ci u32 j; 17762306a36Sopenharmony_ci acpi_status status; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Allocate the GPE register information block */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block-> 18462306a36Sopenharmony_ci register_count * 18562306a36Sopenharmony_ci sizeof(struct 18662306a36Sopenharmony_ci acpi_gpe_register_info)); 18762306a36Sopenharmony_ci if (!gpe_register_info) { 18862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 18962306a36Sopenharmony_ci "Could not allocate the GpeRegisterInfo table")); 19062306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Allocate the GPE event_info block. There are eight distinct GPEs 19562306a36Sopenharmony_ci * per register. Initialization to zeros is sufficient. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count * 19862306a36Sopenharmony_ci sizeof(struct 19962306a36Sopenharmony_ci acpi_gpe_event_info)); 20062306a36Sopenharmony_ci if (!gpe_event_info) { 20162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 20262306a36Sopenharmony_ci "Could not allocate the GpeEventInfo table")); 20362306a36Sopenharmony_ci status = AE_NO_MEMORY; 20462306a36Sopenharmony_ci goto error_exit; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Save the new Info arrays in the GPE block */ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci gpe_block->register_info = gpe_register_info; 21062306a36Sopenharmony_ci gpe_block->event_info = gpe_event_info; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * Initialize the GPE Register and Event structures. A goal of these 21462306a36Sopenharmony_ci * tables is to hide the fact that there are two separate GPE register 21562306a36Sopenharmony_ci * sets in a given GPE hardware block, the status registers occupy the 21662306a36Sopenharmony_ci * first half, and the enable registers occupy the second half. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci this_register = gpe_register_info; 21962306a36Sopenharmony_ci this_event = gpe_event_info; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci for (i = 0; i < gpe_block->register_count; i++) { 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Init the register_info for this GPE register (8 GPEs) */ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci this_register->base_gpe_number = (u16) 22662306a36Sopenharmony_ci (gpe_block->block_base_number + 22762306a36Sopenharmony_ci (i * ACPI_GPE_REGISTER_WIDTH)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci this_register->status_address.address = gpe_block->address + i; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci this_register->enable_address.address = 23262306a36Sopenharmony_ci gpe_block->address + i + gpe_block->register_count; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci this_register->status_address.space_id = gpe_block->space_id; 23562306a36Sopenharmony_ci this_register->enable_address.space_id = gpe_block->space_id; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Init the event_info for each GPE within this register */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { 24062306a36Sopenharmony_ci this_event->gpe_number = 24162306a36Sopenharmony_ci (u8) (this_register->base_gpe_number + j); 24262306a36Sopenharmony_ci this_event->register_info = this_register; 24362306a36Sopenharmony_ci this_event++; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Disable all GPEs within this register */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci status = acpi_hw_gpe_write(0x00, &this_register->enable_address); 24962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 25062306a36Sopenharmony_ci goto error_exit; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Clear any pending GPE events within this register */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci status = acpi_hw_gpe_write(0xFF, &this_register->status_address); 25662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 25762306a36Sopenharmony_ci goto error_exit; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci this_register++; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cierror_exit: 26662306a36Sopenharmony_ci if (gpe_register_info) { 26762306a36Sopenharmony_ci ACPI_FREE(gpe_register_info); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci if (gpe_event_info) { 27062306a36Sopenharmony_ci ACPI_FREE(gpe_event_info); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return_ACPI_STATUS(status); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/******************************************************************************* 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * FUNCTION: acpi_ev_create_gpe_block 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * PARAMETERS: gpe_device - Handle to the parent GPE block 28162306a36Sopenharmony_ci * gpe_block_address - Address and space_ID 28262306a36Sopenharmony_ci * register_count - Number of GPE register pairs in the block 28362306a36Sopenharmony_ci * gpe_block_base_number - Starting GPE number for the block 28462306a36Sopenharmony_ci * interrupt_number - H/W interrupt for the block 28562306a36Sopenharmony_ci * return_gpe_block - Where the new block descriptor is returned 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * RETURN: Status 28862306a36Sopenharmony_ci * 28962306a36Sopenharmony_ci * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within 29062306a36Sopenharmony_ci * the block are disabled at exit. 29162306a36Sopenharmony_ci * Note: Assumes namespace is locked. 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci ******************************************************************************/ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciacpi_status 29662306a36Sopenharmony_ciacpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, 29762306a36Sopenharmony_ci u64 address, 29862306a36Sopenharmony_ci u8 space_id, 29962306a36Sopenharmony_ci u32 register_count, 30062306a36Sopenharmony_ci u16 gpe_block_base_number, 30162306a36Sopenharmony_ci u32 interrupt_number, 30262306a36Sopenharmony_ci struct acpi_gpe_block_info **return_gpe_block) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci acpi_status status; 30562306a36Sopenharmony_ci struct acpi_gpe_block_info *gpe_block; 30662306a36Sopenharmony_ci struct acpi_gpe_walk_info walk_info; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_create_gpe_block); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!register_count) { 31162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Validate the space_ID */ 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 31762306a36Sopenharmony_ci (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 31862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 31962306a36Sopenharmony_ci "Unsupported address space: 0x%X", space_id)); 32062306a36Sopenharmony_ci return_ACPI_STATUS(AE_SUPPORT); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) { 32462306a36Sopenharmony_ci status = acpi_hw_validate_io_block(address, 32562306a36Sopenharmony_ci ACPI_GPE_REGISTER_WIDTH, 32662306a36Sopenharmony_ci register_count); 32762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 32862306a36Sopenharmony_ci return_ACPI_STATUS(status); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Allocate a new GPE block */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); 33462306a36Sopenharmony_ci if (!gpe_block) { 33562306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Initialize the new GPE block */ 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci gpe_block->address = address; 34162306a36Sopenharmony_ci gpe_block->space_id = space_id; 34262306a36Sopenharmony_ci gpe_block->node = gpe_device; 34362306a36Sopenharmony_ci gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); 34462306a36Sopenharmony_ci gpe_block->initialized = FALSE; 34562306a36Sopenharmony_ci gpe_block->register_count = register_count; 34662306a36Sopenharmony_ci gpe_block->block_base_number = gpe_block_base_number; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * Create the register_info and event_info sub-structures 35062306a36Sopenharmony_ci * Note: disables and clears all GPEs in the block 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci status = acpi_ev_create_gpe_info_blocks(gpe_block); 35362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 35462306a36Sopenharmony_ci ACPI_FREE(gpe_block); 35562306a36Sopenharmony_ci return_ACPI_STATUS(status); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Install the new block in the global lists */ 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci status = acpi_ev_install_gpe_block(gpe_block, interrupt_number); 36162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 36262306a36Sopenharmony_ci ACPI_FREE(gpe_block->register_info); 36362306a36Sopenharmony_ci ACPI_FREE(gpe_block->event_info); 36462306a36Sopenharmony_ci ACPI_FREE(gpe_block); 36562306a36Sopenharmony_ci return_ACPI_STATUS(status); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci acpi_gbl_all_gpes_initialized = FALSE; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Find all GPE methods (_Lxx or_Exx) for this block */ 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci walk_info.gpe_block = gpe_block; 37362306a36Sopenharmony_ci walk_info.gpe_device = gpe_device; 37462306a36Sopenharmony_ci walk_info.execute_by_owner_id = FALSE; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci (void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device, 37762306a36Sopenharmony_ci ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, 37862306a36Sopenharmony_ci acpi_ev_match_gpe_method, NULL, &walk_info, 37962306a36Sopenharmony_ci NULL); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Return the new block */ 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (return_gpe_block) { 38462306a36Sopenharmony_ci (*return_gpe_block) = gpe_block; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 38862306a36Sopenharmony_ci " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", 38962306a36Sopenharmony_ci (u32)gpe_block->block_base_number, 39062306a36Sopenharmony_ci (u32)(gpe_block->block_base_number + 39162306a36Sopenharmony_ci (gpe_block->gpe_count - 1)), 39262306a36Sopenharmony_ci gpe_device->name.ascii, gpe_block->register_count, 39362306a36Sopenharmony_ci interrupt_number, 39462306a36Sopenharmony_ci interrupt_number == 39562306a36Sopenharmony_ci acpi_gbl_FADT.sci_interrupt ? " (SCI)" : "")); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Update global count of currently available GPEs */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci acpi_current_gpe_count += gpe_block->gpe_count; 40062306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/******************************************************************************* 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * FUNCTION: acpi_ev_initialize_gpe_block 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * PARAMETERS: acpi_gpe_callback 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * RETURN: Status 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have 41262306a36Sopenharmony_ci * associated methods. 41362306a36Sopenharmony_ci * Note: Assumes namespace is locked. 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci ******************************************************************************/ 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciacpi_status 41862306a36Sopenharmony_ciacpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 41962306a36Sopenharmony_ci struct acpi_gpe_block_info *gpe_block, 42062306a36Sopenharmony_ci void *context) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci acpi_status status; 42362306a36Sopenharmony_ci struct acpi_gpe_event_info *gpe_event_info; 42462306a36Sopenharmony_ci u32 gpe_enabled_count; 42562306a36Sopenharmony_ci u32 gpe_index; 42662306a36Sopenharmony_ci u32 i; 42762306a36Sopenharmony_ci u32 j; 42862306a36Sopenharmony_ci u8 *is_polling_needed = context; 42962306a36Sopenharmony_ci ACPI_ERROR_ONLY(u32 gpe_number); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * Ignore a null GPE block (e.g., if no GPE block 1 exists), and 43562306a36Sopenharmony_ci * any GPE blocks that have been initialized already. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci if (!gpe_block || gpe_block->initialized) { 43862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * Enable all GPEs that have a corresponding method and have the 44362306a36Sopenharmony_ci * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block 44462306a36Sopenharmony_ci * must be enabled via the acpi_enable_gpe() interface. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_ci gpe_enabled_count = 0; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (i = 0; i < gpe_block->register_count; i++) { 44962306a36Sopenharmony_ci for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* Get the info block for this particular GPE */ 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j; 45462306a36Sopenharmony_ci gpe_event_info = &gpe_block->event_info[gpe_index]; 45562306a36Sopenharmony_ci ACPI_ERROR_ONLY(gpe_number = 45662306a36Sopenharmony_ci gpe_block->block_base_number + 45762306a36Sopenharmony_ci gpe_index); 45862306a36Sopenharmony_ci gpe_event_info->flags |= ACPI_GPE_INITIALIZED; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * Ignore GPEs that have no corresponding _Lxx/_Exx method 46262306a36Sopenharmony_ci * and GPEs that are used for wakeup 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != 46562306a36Sopenharmony_ci ACPI_GPE_DISPATCH_METHOD) 46662306a36Sopenharmony_ci || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { 46762306a36Sopenharmony_ci continue; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE); 47162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 47262306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 47362306a36Sopenharmony_ci "Could not enable GPE 0x%02X", 47462306a36Sopenharmony_ci gpe_number)); 47562306a36Sopenharmony_ci continue; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (is_polling_needed && 48162306a36Sopenharmony_ci ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) { 48262306a36Sopenharmony_ci *is_polling_needed = TRUE; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci gpe_enabled_count++; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (gpe_enabled_count) { 49062306a36Sopenharmony_ci ACPI_INFO(("Enabled %u GPEs in block %02X to %02X", 49162306a36Sopenharmony_ci gpe_enabled_count, (u32)gpe_block->block_base_number, 49262306a36Sopenharmony_ci (u32)(gpe_block->block_base_number + 49362306a36Sopenharmony_ci (gpe_block->gpe_count - 1)))); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci gpe_block->initialized = TRUE; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci#endif /* !ACPI_REDUCED_HARDWARE */ 502