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