1 /****************************************************************************** 2 * 3 * Module Name: evgpeblk - GPE block creation and initialization. 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 168 if (!GpeBlock->Previous && !GpeBlock->Next) 169 { 170 /* This is the last GpeBlock on this interrupt */ 171 172 Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock); 173 if (ACPI_FAILURE (Status)) 174 { 175 goto UnlockAndExit; 176 } 177 } 178 else 179 { 180 /* Remove the block on this interrupt with lock */ 181 182 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 183 if (GpeBlock->Previous) 184 { 185 GpeBlock->Previous->Next = GpeBlock->Next; 186 } 187 else 188 { 189 GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next; 190 } 191 192 if (GpeBlock->Next) 193 { 194 GpeBlock->Next->Previous = GpeBlock->Previous; 195 } 196 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 197 } 198 199 AcpiCurrentGpeCount -= GpeBlock->GpeCount; 200 201 /* Free the GpeBlock */ 202 203 ACPI_FREE (GpeBlock->RegisterInfo); 204 ACPI_FREE (GpeBlock->EventInfo); 205 ACPI_FREE (GpeBlock); 206 207 UnlockAndExit: 208 Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); 209 return_ACPI_STATUS (Status); 210 } 211 212 213 /******************************************************************************* 214 * 215 * FUNCTION: AcpiEvCreateGpeInfoBlocks 216 * 217 * PARAMETERS: GpeBlock - New GPE block 218 * 219 * RETURN: Status 220 * 221 * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block 222 * 223 ******************************************************************************/ 224 225 static ACPI_STATUS 226 AcpiEvCreateGpeInfoBlocks ( 227 ACPI_GPE_BLOCK_INFO *GpeBlock) 228 { 229 ACPI_GPE_REGISTER_INFO *GpeRegisterInfo = NULL; 230 ACPI_GPE_EVENT_INFO *GpeEventInfo = NULL; 231 ACPI_GPE_EVENT_INFO *ThisEvent; 232 ACPI_GPE_REGISTER_INFO *ThisRegister; 233 UINT32 i; 234 UINT32 j; 235 ACPI_STATUS Status; 236 237 238 ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks); 239 240 241 /* Allocate the GPE register information block */ 242 243 GpeRegisterInfo = ACPI_ALLOCATE_ZEROED ( 244 (ACPI_SIZE) GpeBlock->RegisterCount * 245 sizeof (ACPI_GPE_REGISTER_INFO)); 246 if (!GpeRegisterInfo) 247 { 248 ACPI_ERROR ((AE_INFO, 249 "Could not allocate the GpeRegisterInfo table")); 250 return_ACPI_STATUS (AE_NO_MEMORY); 251 } 252 253 /* 254 * Allocate the GPE EventInfo block. There are eight distinct GPEs 255 * per register. Initialization to zeros is sufficient. 256 */ 257 GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount * 258 sizeof (ACPI_GPE_EVENT_INFO)); 259 if (!GpeEventInfo) 260 { 261 ACPI_ERROR ((AE_INFO, 262 "Could not allocate the GpeEventInfo table")); 263 Status = AE_NO_MEMORY; 264 goto ErrorExit; 265 } 266 267 /* Save the new Info arrays in the GPE block */ 268 269 GpeBlock->RegisterInfo = GpeRegisterInfo; 270 GpeBlock->EventInfo = GpeEventInfo; 271 272 /* 273 * Initialize the GPE Register and Event structures. A goal of these 274 * tables is to hide the fact that there are two separate GPE register 275 * sets in a given GPE hardware block, the status registers occupy the 276 * first half, and the enable registers occupy the second half. 277 */ 278 ThisRegister = GpeRegisterInfo; 279 ThisEvent = GpeEventInfo; 280 281 for (i = 0; i < GpeBlock->RegisterCount; i++) 282 { 283 /* Init the RegisterInfo for this GPE register (8 GPEs) */ 284 285 ThisRegister->BaseGpeNumber = (UINT8) (GpeBlock->BlockBaseNumber + 286 (i * ACPI_GPE_REGISTER_WIDTH)); 287 288 ThisRegister->StatusAddress.Address = 289 GpeBlock->BlockAddress.Address + i; 290 291 ThisRegister->EnableAddress.Address = 292 GpeBlock->BlockAddress.Address + i + GpeBlock->RegisterCount; 293 294 ThisRegister->StatusAddress.SpaceId = GpeBlock->BlockAddress.SpaceId; 295 ThisRegister->EnableAddress.SpaceId = GpeBlock->BlockAddress.SpaceId; 296 ThisRegister->StatusAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 297 ThisRegister->EnableAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 298 ThisRegister->StatusAddress.BitOffset = 0; 299 ThisRegister->EnableAddress.BitOffset = 0; 300 301 /* Init the EventInfo for each GPE within this register */ 302 303 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 304 { 305 ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j); 306 ThisEvent->RegisterInfo = ThisRegister; 307 ThisEvent++; 308 } 309 310 /* Disable all GPEs within this register */ 311 312 Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress); 313 if (ACPI_FAILURE (Status)) 314 { 315 goto ErrorExit; 316 } 317 318 /* Clear any pending GPE events within this register */ 319 320 Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress); 321 if (ACPI_FAILURE (Status)) 322 { 323 goto ErrorExit; 324 } 325 326 ThisRegister++; 327 } 328 329 return_ACPI_STATUS (AE_OK); 330 331 332 ErrorExit: 333 if (GpeRegisterInfo) 334 { 335 ACPI_FREE (GpeRegisterInfo); 336 } 337 if (GpeEventInfo) 338 { 339 ACPI_FREE (GpeEventInfo); 340 } 341 342 return_ACPI_STATUS (Status); 343 } 344 345 346 /******************************************************************************* 347 * 348 * FUNCTION: AcpiEvCreateGpeBlock 349 * 350 * PARAMETERS: GpeDevice - Handle to the parent GPE block 351 * GpeBlockAddress - Address and SpaceID 352 * RegisterCount - Number of GPE register pairs in the block 353 * GpeBlockBaseNumber - Starting GPE number for the block 354 * InterruptNumber - H/W interrupt for the block 355 * ReturnGpeBlock - Where the new block descriptor is returned 356 * 357 * RETURN: Status 358 * 359 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within 360 * the block are disabled at exit. 361 * Note: Assumes namespace is locked. 362 * 363 ******************************************************************************/ 364 365 ACPI_STATUS 366 AcpiEvCreateGpeBlock ( 367 ACPI_NAMESPACE_NODE *GpeDevice, 368 ACPI_GENERIC_ADDRESS *GpeBlockAddress, 369 UINT32 RegisterCount, 370 UINT8 GpeBlockBaseNumber, 371 UINT32 InterruptNumber, 372 ACPI_GPE_BLOCK_INFO **ReturnGpeBlock) 373 { 374 ACPI_STATUS Status; 375 ACPI_GPE_BLOCK_INFO *GpeBlock; 376 ACPI_GPE_WALK_INFO WalkInfo; 377 378 379 ACPI_FUNCTION_TRACE (EvCreateGpeBlock); 380 381 382 if (!RegisterCount) 383 { 384 return_ACPI_STATUS (AE_OK); 385 } 386 387 /* Allocate a new GPE block */ 388 389 GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO)); 390 if (!GpeBlock) 391 { 392 return_ACPI_STATUS (AE_NO_MEMORY); 393 } 394 395 /* Initialize the new GPE block */ 396 397 GpeBlock->Node = GpeDevice; 398 GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH); 399 GpeBlock->Initialized = FALSE; 400 GpeBlock->RegisterCount = RegisterCount; 401 GpeBlock->BlockBaseNumber = GpeBlockBaseNumber; 402 403 ACPI_MEMCPY (&GpeBlock->BlockAddress, GpeBlockAddress, 404 sizeof (ACPI_GENERIC_ADDRESS)); 405 406 /* 407 * Create the RegisterInfo and EventInfo sub-structures 408 * Note: disables and clears all GPEs in the block 409 */ 410 Status = AcpiEvCreateGpeInfoBlocks (GpeBlock); 411 if (ACPI_FAILURE (Status)) 412 { 413 ACPI_FREE (GpeBlock); 414 return_ACPI_STATUS (Status); 415 } 416 417 /* Install the new block in the global lists */ 418 419 Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber); 420 if (ACPI_FAILURE (Status)) 421 { 422 ACPI_FREE (GpeBlock->RegisterInfo); 423 ACPI_FREE (GpeBlock->EventInfo); 424 ACPI_FREE (GpeBlock); 425 return_ACPI_STATUS (Status); 426 } 427 428 AcpiGbl_AllGpesInitialized = FALSE; 429 430 /* Find all GPE methods (_Lxx or_Exx) for this block */ 431 432 WalkInfo.GpeBlock = GpeBlock; 433 WalkInfo.GpeDevice = GpeDevice; 434 WalkInfo.ExecuteByOwnerId = FALSE; 435 436 Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice, 437 ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, 438 AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL); 439 440 /* Return the new block */ 441 442 if (ReturnGpeBlock) 443 { 444 (*ReturnGpeBlock) = GpeBlock; 445 } 446 447 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, 448 " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n", 449 (UINT32) GpeBlock->BlockBaseNumber, 450 (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)), 451 GpeDevice->Name.Ascii, GpeBlock->RegisterCount, 452 InterruptNumber)); 453 454 /* Update global count of currently available GPEs */ 455 456 AcpiCurrentGpeCount += GpeBlock->GpeCount; 457 return_ACPI_STATUS (AE_OK); 458 } 459 460 461 /******************************************************************************* 462 * 463 * FUNCTION: AcpiEvInitializeGpeBlock 464 * 465 * PARAMETERS: ACPI_GPE_CALLBACK 466 * 467 * RETURN: Status 468 * 469 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have 470 * associated methods. 471 * Note: Assumes namespace is locked. 472 * 473 ******************************************************************************/ 474 475 ACPI_STATUS 476 AcpiEvInitializeGpeBlock ( 477 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 478 ACPI_GPE_BLOCK_INFO *GpeBlock, 479 void *Ignored) 480 { 481 ACPI_STATUS Status; 482 ACPI_GPE_EVENT_INFO *GpeEventInfo; 483 UINT32 GpeEnabledCount; 484 UINT32 GpeIndex; 485 UINT32 i; 486 UINT32 j; 487 488 489 ACPI_FUNCTION_TRACE (EvInitializeGpeBlock); 490 491 492 /* 493 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and 494 * any GPE blocks that have been initialized already. 495 */ 496 if (!GpeBlock || GpeBlock->Initialized) 497 { 498 return_ACPI_STATUS (AE_OK); 499 } 500 501 /* 502 * Enable all GPEs that have a corresponding method and have the 503 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block 504 * must be enabled via the acpi_enable_gpe() interface. 505 */ 506 GpeEnabledCount = 0; 507 508 for (i = 0; i < GpeBlock->RegisterCount; i++) 509 { 510 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 511 { 512 /* Get the info block for this particular GPE */ 513 514 GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j; 515 GpeEventInfo = &GpeBlock->EventInfo[GpeIndex]; 516 517 /* 518 * Ignore GPEs that have no corresponding _Lxx/_Exx method 519 * and GPEs that are used to wake the system 520 */ 521 if (((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NONE) || 522 ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) || 523 (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) 524 { 525 continue; 526 } 527 528 Status = AcpiEvAddGpeReference (GpeEventInfo); 529 if (ACPI_FAILURE (Status)) 530 { 531 ACPI_EXCEPTION ((AE_INFO, Status, 532 "Could not enable GPE 0x%02X", 533 GpeIndex + GpeBlock->BlockBaseNumber)); 534 continue; 535 } 536 537 GpeEnabledCount++; 538 } 539 } 540 541 if (GpeEnabledCount) 542 { 543 ACPI_INFO ((AE_INFO, 544 "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount, 545 (UINT32) GpeBlock->BlockBaseNumber, 546 (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)))); 547 } 548 549 GpeBlock->Initialized = TRUE; 550 return_ACPI_STATUS (AE_OK); 551 } 552 553 #endif /* !ACPI_REDUCED_HARDWARE */