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