1 /******************************************************************************
   2  *
   3  * Module Name: evgpeblk - GPE block creation and initialization.
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 */