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