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