evgpeblk.c (13999B)
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 - 2022, 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 16ACPI_MODULE_NAME("evgpeblk") 17#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 18/* Local prototypes */ 19static acpi_status 20acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, 21 u32 interrupt_number); 22 23static acpi_status 24acpi_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 40static acpi_status 41acpi_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_block 88 * 89 * PARAMETERS: gpe_block - Existing GPE block 90 * 91 * RETURN: Status 92 * 93 * DESCRIPTION: Remove a GPE block 94 * 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_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 168static acpi_status 169acpi_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(struct 186 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 GPEs 195 * per register. Initialization to zeros is sufficient. 196 */ 197 gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count * 198 sizeof(struct 199 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 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 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_block 279 * 280 * PARAMETERS: gpe_device - Handle to the parent GPE block 281 * gpe_block_address - Address and space_ID 282 * register_count - Number of GPE register pairs in the block 283 * gpe_block_base_number - Starting GPE number for the block 284 * interrupt_number - H/W interrupt for the block 285 * return_gpe_block - Where the new block descriptor is returned 286 * 287 * RETURN: Status 288 * 289 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within 290 * the block are disabled at exit. 291 * Note: Assumes namespace is locked. 292 * 293 ******************************************************************************/ 294 295acpi_status 296acpi_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-structures 350 * Note: disables and clears all GPEs in the block 351 */ 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_block 406 * 407 * PARAMETERS: acpi_gpe_callback 408 * 409 * RETURN: Status 410 * 411 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have 412 * associated methods. 413 * Note: Assumes namespace is locked. 414 * 415 ******************************************************************************/ 416 417acpi_status 418acpi_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), and 435 * 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 the 443 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block 444 * 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 method 462 * and GPEs that are used for wakeup 463 */ 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 */