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 - 2020, 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 16 ACPI_MODULE_NAME("evgpeblk") 17 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 18 /* Local prototypes */ 19 static acpi_status 20 acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, 21 u32 interrupt_number); 22 23 static acpi_status 24 acpi_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 40 static acpi_status 41 acpi_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 80 unlock_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 97 acpi_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 151 unlock_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 168 static acpi_status 169 acpi_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 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; 242 243 /* Init the event_info for each GPE within this register */ 244 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; 249 this_event++; 250 } 251 252 /* Disable all GPEs within this register */ 253 254 status = acpi_hw_write(0x00, &this_register->enable_address); 255 if (ACPI_FAILURE(status)) { 256 goto error_exit; 257 } 258 259 /* Clear any pending GPE events within this register */ 260 261 status = acpi_hw_write(0xFF, &this_register->status_address); 262 if (ACPI_FAILURE(status)) { 263 goto error_exit; 264 } 265 266 this_register++; 267 } 268 269 return_ACPI_STATUS(AE_OK); 270 271 error_exit: 272 if (gpe_register_info) { 273 ACPI_FREE(gpe_register_info); 274 } 275 if (gpe_event_info) { 276 ACPI_FREE(gpe_event_info); 277 } 278 279 return_ACPI_STATUS(status); 280 } 281 282 /******************************************************************************* 283 * 284 * FUNCTION: acpi_ev_create_gpe_block 285 * 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 292 * 293 * RETURN: Status 294 * 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. 298 * 299 ******************************************************************************/ 300 301 acpi_status 302 acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, 303 u64 address, 304 u8 space_id, 305 u32 register_count, 306 u16 gpe_block_base_number, 307 u32 interrupt_number, 308 struct acpi_gpe_block_info **return_gpe_block) 309 { 310 acpi_status status; 311 struct acpi_gpe_block_info *gpe_block; 312 struct acpi_gpe_walk_info walk_info; 313 314 ACPI_FUNCTION_TRACE(ev_create_gpe_block); 315 316 if (!register_count) { 317 return_ACPI_STATUS(AE_OK); 318 } 319 320 /* Allocate a new GPE block */ 321 322 gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); 323 if (!gpe_block) { 324 return_ACPI_STATUS(AE_NO_MEMORY); 325 } 326 327 /* Initialize the new GPE block */ 328 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; 336 337 /* 338 * Create the register_info and event_info sub-structures 339 * Note: disables and clears all GPEs in the block 340 */ 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); 345 } 346 347 /* Install the new block in the global lists */ 348 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); 355 } 356 357 acpi_gbl_all_gpes_initialized = FALSE; 358 359 /* Find all GPE methods (_Lxx or_Exx) for this block */ 360 361 walk_info.gpe_block = gpe_block; 362 walk_info.gpe_device = gpe_device; 363 walk_info.execute_by_owner_id = FALSE; 364 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, 368 NULL); 369 370 /* Return the new block */ 371 372 if (return_gpe_block) { 373 (*return_gpe_block) = gpe_block; 374 } 375 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, 382 interrupt_number, 383 interrupt_number == 384 acpi_gbl_FADT.sci_interrupt ? " (SCI)" : "")); 385 386 /* Update global count of currently available GPEs */ 387 388 acpi_current_gpe_count += gpe_block->gpe_count; 389 return_ACPI_STATUS(AE_OK); 390 } 391 392 /******************************************************************************* 393 * 394 * FUNCTION: acpi_ev_initialize_gpe_block 395 * 396 * PARAMETERS: acpi_gpe_callback 397 * 398 * RETURN: Status 399 * 400 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have 401 * associated methods. 402 * Note: Assumes namespace is locked. 403 * 404 ******************************************************************************/ 405 406 acpi_status 407 acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 408 struct acpi_gpe_block_info *gpe_block, 409 void *context) 410 { 411 acpi_status status; 412 struct acpi_gpe_event_info *gpe_event_info; 413 u32 gpe_enabled_count; 414 u32 gpe_index; 415 u32 i; 416 u32 j; 417 u8 *is_polling_needed = context; 418 ACPI_ERROR_ONLY(u32 gpe_number); 419 420 ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); 421 422 /* 423 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and 424 * any GPE blocks that have been initialized already. 425 */ 426 if (!gpe_block || gpe_block->initialized) { 427 return_ACPI_STATUS(AE_OK); 428 } 429 430 /* 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. 434 */ 435 gpe_enabled_count = 0; 436 437 for (i = 0; i < gpe_block->register_count; i++) { 438 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { 439 440 /* Get the info block for this particular GPE */ 441 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 + 446 gpe_index); 447 gpe_event_info->flags |= ACPI_GPE_INITIALIZED; 448 449 /* 450 * Ignore GPEs that have no corresponding _Lxx/_Exx method 451 * and GPEs that are used for wakeup 452 */ 453 if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != 454 ACPI_GPE_DISPATCH_METHOD) 455 || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { 456 continue; 457 } 458 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", 463 gpe_number)); 464 continue; 465 } 466 467 gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED; 468 469 if (is_polling_needed && 470 ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) { 471 *is_polling_needed = TRUE; 472 } 473 474 gpe_enabled_count++; 475 } 476 } 477 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)))); 483 } 484 485 gpe_block->initialized = TRUE; 486 487 return_ACPI_STATUS(AE_OK); 488 } 489 490 #endif /* !ACPI_REDUCED_HARDWARE */ 491