1 /****************************************************************************** 2 * 3 * Module Name: evgpeblk - GPE block creation and initialization. 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpi.h" 45 #include "accommon.h" 46 #include "acevents.h" 47 #include "acnamesp.h" 48 49 #define _COMPONENT ACPI_EVENTS 50 ACPI_MODULE_NAME ("evgpeblk") 51 52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53 54 /* Local prototypes */ 55 56 static ACPI_STATUS 57 AcpiEvInstallGpeBlock ( 58 ACPI_GPE_BLOCK_INFO *GpeBlock, 59 UINT32 InterruptNumber); 60 61 static ACPI_STATUS 62 AcpiEvCreateGpeInfoBlocks ( 63 ACPI_GPE_BLOCK_INFO *GpeBlock); 64 65 66 /******************************************************************************* 67 * 68 * FUNCTION: AcpiEvInstallGpeBlock 69 * 70 * PARAMETERS: GpeBlock - New GPE block 71 * InterruptNumber - Xrupt to be associated with this 72 * GPE block 73 * 74 * RETURN: Status 75 * 76 * DESCRIPTION: Install new GPE block with mutex support 77 * 78 ******************************************************************************/ 79 80 static ACPI_STATUS 81 AcpiEvInstallGpeBlock ( 82 ACPI_GPE_BLOCK_INFO *GpeBlock, 83 UINT32 InterruptNumber) 84 { 85 ACPI_GPE_BLOCK_INFO *NextGpeBlock; 86 ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 87 ACPI_STATUS Status; 88 ACPI_CPU_FLAGS Flags; 89 90 91 ACPI_FUNCTION_TRACE (EvInstallGpeBlock); 92 93 94 Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); 95 if (ACPI_FAILURE (Status)) 96 { 97 return_ACPI_STATUS (Status); 98 } 99 100 Status = AcpiEvGetGpeXruptBlock (InterruptNumber, &GpeXruptBlock); 101 if (ACPI_FAILURE (Status)) 102 { 103 goto UnlockAndExit; 104 } 105 106 /* Install the new block at the end of the list with lock */ 107 108 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 109 if (GpeXruptBlock->GpeBlockListHead) 110 { 111 NextGpeBlock = GpeXruptBlock->GpeBlockListHead; 112 while (NextGpeBlock->Next) 113 { 114 NextGpeBlock = NextGpeBlock->Next; 115 } 116 117 NextGpeBlock->Next = GpeBlock; 118 GpeBlock->Previous = NextGpeBlock; 119 } 120 else 121 { 122 GpeXruptBlock->GpeBlockListHead = GpeBlock; 123 } 124 125 GpeBlock->XruptBlock = GpeXruptBlock; 126 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 127 128 129 UnlockAndExit: 130 (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); 131 return_ACPI_STATUS (Status); 132 } 133 134 135 /******************************************************************************* 136 * 137 * FUNCTION: AcpiEvDeleteGpeBlock 138 * 139 * PARAMETERS: GpeBlock - Existing GPE block 140 * 141 * RETURN: Status 142 * 143 * DESCRIPTION: Remove a GPE block 144 * 145 ******************************************************************************/ 146 147 ACPI_STATUS 148 AcpiEvDeleteGpeBlock ( 149 ACPI_GPE_BLOCK_INFO *GpeBlock) 150 { 151 ACPI_STATUS Status; 152 ACPI_CPU_FLAGS Flags; 153 154 155 ACPI_FUNCTION_TRACE (EvInstallGpeBlock); 156 157 158 Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); 159 if (ACPI_FAILURE (Status)) 160 { 161 return_ACPI_STATUS (Status); 162 } 163 164 /* Disable all GPEs in this block */ 165 166 Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL); 167 if (ACPI_FAILURE (Status)) 168 { 169 return_ACPI_STATUS (Status); 170 } 171 172 if (!GpeBlock->Previous && !GpeBlock->Next) 173 { 174 /* This is the last GpeBlock on this interrupt */ 175 176 Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock); 177 if (ACPI_FAILURE (Status)) 178 { 179 goto UnlockAndExit; 180 } 181 } 182 else 183 { 184 /* Remove the block on this interrupt with lock */ 185 186 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 187 if (GpeBlock->Previous) 188 { 189 GpeBlock->Previous->Next = GpeBlock->Next; 190 } 191 else 192 { 193 GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next; 194 } 195 196 if (GpeBlock->Next) 197 { 198 GpeBlock->Next->Previous = GpeBlock->Previous; 199 } 200 201 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 202 } 203 204 AcpiCurrentGpeCount -= GpeBlock->GpeCount; 205 206 /* Free the GpeBlock */ 207 208 ACPI_FREE (GpeBlock->RegisterInfo); 209 ACPI_FREE (GpeBlock->EventInfo); 210 ACPI_FREE (GpeBlock); 211 212 UnlockAndExit: 213 Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); 214 return_ACPI_STATUS (Status); 215 } 216 217 218 /******************************************************************************* 219 * 220 * FUNCTION: AcpiEvCreateGpeInfoBlocks 221 * 222 * PARAMETERS: GpeBlock - New GPE block 223 * 224 * RETURN: Status 225 * 226 * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block 227 * 228 ******************************************************************************/ 229 230 static ACPI_STATUS 231 AcpiEvCreateGpeInfoBlocks ( 232 ACPI_GPE_BLOCK_INFO *GpeBlock) 233 { 234 ACPI_GPE_REGISTER_INFO *GpeRegisterInfo = NULL; 235 ACPI_GPE_EVENT_INFO *GpeEventInfo = NULL; 236 ACPI_GPE_EVENT_INFO *ThisEvent; 237 ACPI_GPE_REGISTER_INFO *ThisRegister; 238 UINT32 i; 239 UINT32 j; 240 ACPI_STATUS Status; 241 242 243 ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks); 244 245 246 /* Allocate the GPE register information block */ 247 248 GpeRegisterInfo = ACPI_ALLOCATE_ZEROED ( 249 (ACPI_SIZE) GpeBlock->RegisterCount * 250 sizeof (ACPI_GPE_REGISTER_INFO)); 251 if (!GpeRegisterInfo) 252 { 253 ACPI_ERROR ((AE_INFO, 254 "Could not allocate the GpeRegisterInfo table")); 255 return_ACPI_STATUS (AE_NO_MEMORY); 256 } 257 258 /* 259 * Allocate the GPE EventInfo block. There are eight distinct GPEs 260 * per register. Initialization to zeros is sufficient. 261 */ 262 GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount * 263 sizeof (ACPI_GPE_EVENT_INFO)); 264 if (!GpeEventInfo) 265 { 266 ACPI_ERROR ((AE_INFO, 267 "Could not allocate the GpeEventInfo table")); 268 Status = AE_NO_MEMORY; 269 goto ErrorExit; 270 } 271 272 /* Save the new Info arrays in the GPE block */ 273 274 GpeBlock->RegisterInfo = GpeRegisterInfo; 275 GpeBlock->EventInfo = GpeEventInfo; 276 277 /* 278 * Initialize the GPE Register and Event structures. A goal of these 279 * tables is to hide the fact that there are two separate GPE register 280 * sets in a given GPE hardware block, the status registers occupy the 281 * first half, and the enable registers occupy the second half. 282 */ 283 ThisRegister = GpeRegisterInfo; 284 ThisEvent = GpeEventInfo; 285 286 for (i = 0; i < GpeBlock->RegisterCount; i++) 287 { 288 /* Init the RegisterInfo for this GPE register (8 GPEs) */ 289 290 ThisRegister->BaseGpeNumber = (UINT16) 291 (GpeBlock->BlockBaseNumber + (i * ACPI_GPE_REGISTER_WIDTH)); 292 293 ThisRegister->StatusAddress.Address = 294 GpeBlock->Address + i; 295 296 ThisRegister->EnableAddress.Address = 297 GpeBlock->Address + i + GpeBlock->RegisterCount; 298 299 ThisRegister->StatusAddress.SpaceId = GpeBlock->SpaceId; 300 ThisRegister->EnableAddress.SpaceId = GpeBlock->SpaceId; 301 ThisRegister->StatusAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 302 ThisRegister->EnableAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 303 ThisRegister->StatusAddress.BitOffset = 0; 304 ThisRegister->EnableAddress.BitOffset = 0; 305 306 /* Init the EventInfo for each GPE within this register */ 307 308 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 309 { 310 ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j); 311 ThisEvent->RegisterInfo = ThisRegister; 312 ThisEvent++; 313 } 314 315 /* Disable all GPEs within this register */ 316 317 Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress); 318 if (ACPI_FAILURE (Status)) 319 { 320 goto ErrorExit; 321 } 322 323 /* Clear any pending GPE events within this register */ 324 325 Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress); 326 if (ACPI_FAILURE (Status)) 327 { 328 goto ErrorExit; 329 } 330 331 ThisRegister++; 332 } 333 334 return_ACPI_STATUS (AE_OK); 335 336 337 ErrorExit: 338 if (GpeRegisterInfo) 339 { 340 ACPI_FREE (GpeRegisterInfo); 341 } 342 if (GpeEventInfo) 343 { 344 ACPI_FREE (GpeEventInfo); 345 } 346 347 return_ACPI_STATUS (Status); 348 } 349 350 351 /******************************************************************************* 352 * 353 * FUNCTION: AcpiEvCreateGpeBlock 354 * 355 * PARAMETERS: GpeDevice - Handle to the parent GPE block 356 * GpeBlockAddress - Address and SpaceID 357 * RegisterCount - Number of GPE register pairs in the block 358 * GpeBlockBaseNumber - Starting GPE number for the block 359 * InterruptNumber - H/W interrupt for the block 360 * ReturnGpeBlock - Where the new block descriptor is returned 361 * 362 * RETURN: Status 363 * 364 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within 365 * the block are disabled at exit. 366 * Note: Assumes namespace is locked. 367 * 368 ******************************************************************************/ 369 370 ACPI_STATUS 371 AcpiEvCreateGpeBlock ( 372 ACPI_NAMESPACE_NODE *GpeDevice, 373 UINT64 Address, 374 UINT8 SpaceId, 375 UINT32 RegisterCount, 376 UINT16 GpeBlockBaseNumber, 377 UINT32 InterruptNumber, 378 ACPI_GPE_BLOCK_INFO **ReturnGpeBlock) 379 { 380 ACPI_STATUS Status; 381 ACPI_GPE_BLOCK_INFO *GpeBlock; 382 ACPI_GPE_WALK_INFO WalkInfo; 383 384 385 ACPI_FUNCTION_TRACE (EvCreateGpeBlock); 386 387 388 if (!RegisterCount) 389 { 390 return_ACPI_STATUS (AE_OK); 391 } 392 393 /* Allocate a new GPE block */ 394 395 GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO)); 396 if (!GpeBlock) 397 { 398 return_ACPI_STATUS (AE_NO_MEMORY); 399 } 400 401 /* Initialize the new GPE block */ 402 403 GpeBlock->Address = Address; 404 GpeBlock->SpaceId = SpaceId; 405 GpeBlock->Node = GpeDevice; 406 GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH); 407 GpeBlock->Initialized = FALSE; 408 GpeBlock->RegisterCount = RegisterCount; 409 GpeBlock->BlockBaseNumber = GpeBlockBaseNumber; 410 411 /* 412 * Create the RegisterInfo and EventInfo sub-structures 413 * Note: disables and clears all GPEs in the block 414 */ 415 Status = AcpiEvCreateGpeInfoBlocks (GpeBlock); 416 if (ACPI_FAILURE (Status)) 417 { 418 ACPI_FREE (GpeBlock); 419 return_ACPI_STATUS (Status); 420 } 421 422 /* Install the new block in the global lists */ 423 424 Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber); 425 if (ACPI_FAILURE (Status)) 426 { 427 ACPI_FREE (GpeBlock->RegisterInfo); 428 ACPI_FREE (GpeBlock->EventInfo); 429 ACPI_FREE (GpeBlock); 430 return_ACPI_STATUS (Status); 431 } 432 433 AcpiGbl_AllGpesInitialized = FALSE; 434 435 /* Find all GPE methods (_Lxx or_Exx) for this block */ 436 437 WalkInfo.GpeBlock = GpeBlock; 438 WalkInfo.GpeDevice = GpeDevice; 439 WalkInfo.ExecuteByOwnerId = FALSE; 440 441 (void) AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice, 442 ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, 443 AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL); 444 445 /* Return the new block */ 446 447 if (ReturnGpeBlock) 448 { 449 (*ReturnGpeBlock) = GpeBlock; 450 } 451 452 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, 453 " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n", 454 (UINT32) GpeBlock->BlockBaseNumber, 455 (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)), 456 GpeDevice->Name.Ascii, GpeBlock->RegisterCount, InterruptNumber, 457 InterruptNumber == AcpiGbl_FADT.SciInterrupt ? " (SCI)" : "")); 458 459 /* Update global count of currently available GPEs */ 460 461 AcpiCurrentGpeCount += GpeBlock->GpeCount; 462 return_ACPI_STATUS (AE_OK); 463 } 464 465 466 /******************************************************************************* 467 * 468 * FUNCTION: AcpiEvInitializeGpeBlock 469 * 470 * PARAMETERS: ACPI_GPE_CALLBACK 471 * 472 * RETURN: Status 473 * 474 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have 475 * associated methods. 476 * Note: Assumes namespace is locked. 477 * 478 ******************************************************************************/ 479 480 ACPI_STATUS 481 AcpiEvInitializeGpeBlock ( 482 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 483 ACPI_GPE_BLOCK_INFO *GpeBlock, 484 void *Context) 485 { 486 ACPI_STATUS Status; 487 ACPI_GPE_EVENT_INFO *GpeEventInfo; 488 UINT32 GpeEnabledCount; 489 UINT32 GpeIndex; 490 UINT32 i; 491 UINT32 j; 492 BOOLEAN *IsPollingNeeded = Context; 493 ACPI_ERROR_ONLY (UINT32 GpeNumber); 494 495 496 ACPI_FUNCTION_TRACE (EvInitializeGpeBlock); 497 498 499 /* 500 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and 501 * any GPE blocks that have been initialized already. 502 */ 503 if (!GpeBlock || GpeBlock->Initialized) 504 { 505 return_ACPI_STATUS (AE_OK); 506 } 507 508 /* 509 * Enable all GPEs that have a corresponding method and have the 510 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block 511 * must be enabled via the acpi_enable_gpe() interface. 512 */ 513 GpeEnabledCount = 0; 514 515 for (i = 0; i < GpeBlock->RegisterCount; i++) 516 { 517 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 518 { 519 /* Get the info block for this particular GPE */ 520 521 GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j; 522 GpeEventInfo = &GpeBlock->EventInfo[GpeIndex]; 523 ACPI_ERROR_ONLY(GpeNumber = GpeBlock->BlockBaseNumber + GpeIndex); 524 GpeEventInfo->Flags |= ACPI_GPE_INITIALIZED; 525 526 /* 527 * Ignore GPEs that have no corresponding _Lxx/_Exx method 528 * and GPEs that are used to wake the system 529 */ 530 if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != ACPI_GPE_DISPATCH_METHOD) || 531 (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) 532 { 533 continue; 534 } 535 536 Status = AcpiEvAddGpeReference (GpeEventInfo, FALSE); 537 if (ACPI_FAILURE (Status)) 538 { 539 ACPI_EXCEPTION ((AE_INFO, Status, 540 "Could not enable GPE 0x%02X", 541 GpeNumber)); 542 continue; 543 } 544 545 GpeEventInfo->Flags |= ACPI_GPE_AUTO_ENABLED; 546 547 if (IsPollingNeeded && 548 ACPI_GPE_IS_POLLING_NEEDED (GpeEventInfo)) 549 { 550 *IsPollingNeeded = TRUE; 551 } 552 553 GpeEnabledCount++; 554 } 555 } 556 557 if (GpeEnabledCount) 558 { 559 ACPI_INFO (( 560 "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount, 561 (UINT32) GpeBlock->BlockBaseNumber, 562 (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)))); 563 } 564 565 GpeBlock->Initialized = TRUE; 566 return_ACPI_STATUS (AE_OK); 567 } 568 569 #endif /* !ACPI_REDUCED_HARDWARE */ 570