1 /******************************************************************************
   2  *
   3  * Module Name: evgpeutil - GPE utilities
   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 
  45 #include "acpi.h"
  46 #include "accommon.h"
  47 #include "acevents.h"
  48 
  49 #define _COMPONENT          ACPI_EVENTS
  50         ACPI_MODULE_NAME    ("evgpeutil")
  51 
  52 
  53 /*******************************************************************************
  54  *
  55  * FUNCTION:    AcpiEvWalkGpeList
  56  *
  57  * PARAMETERS:  GpeWalkCallback     - Routine called for each GPE block
  58  *              Context             - Value passed to callback
  59  *
  60  * RETURN:      Status
  61  *
  62  * DESCRIPTION: Walk the GPE lists.
  63  *
  64  ******************************************************************************/
  65 
  66 ACPI_STATUS
  67 AcpiEvWalkGpeList (
  68     ACPI_GPE_CALLBACK       GpeWalkCallback,
  69     void                    *Context)
  70 {
  71     ACPI_GPE_BLOCK_INFO     *GpeBlock;
  72     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo;
  73     ACPI_STATUS             Status = AE_OK;
  74     ACPI_CPU_FLAGS          Flags;
  75 
  76 
  77     ACPI_FUNCTION_TRACE (EvWalkGpeList);
  78 
  79 
  80     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
  81 
  82     /* Walk the interrupt level descriptor list */
  83 
  84     GpeXruptInfo = AcpiGbl_GpeXruptListHead;
  85     while (GpeXruptInfo)
  86     {
  87         /* Walk all Gpe Blocks attached to this interrupt level */
  88 
  89         GpeBlock = GpeXruptInfo->GpeBlockListHead;
  90         while (GpeBlock)
  91         {
  92             /* One callback per GPE block */
  93 
  94             Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context);
  95             if (ACPI_FAILURE (Status))
  96             {
  97                 if (Status == AE_CTRL_END) /* Callback abort */
  98                 {
  99                     Status = AE_OK;
 100                 }
 101                 goto UnlockAndExit;
 102             }
 103 
 104             GpeBlock = GpeBlock->Next;
 105         }
 106 
 107         GpeXruptInfo = GpeXruptInfo->Next;
 108     }
 109 
 110 UnlockAndExit:
 111     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
 112     return_ACPI_STATUS (Status);
 113 }
 114 
 115 
 116 /*******************************************************************************
 117  *
 118  * FUNCTION:    AcpiEvValidGpeEvent
 119  *
 120  * PARAMETERS:  GpeEventInfo                - Info for this GPE
 121  *
 122  * RETURN:      TRUE if the GpeEvent is valid
 123  *
 124  * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.
 125  *              Should be called only when the GPE lists are semaphore locked
 126  *              and not subject to change.
 127  *
 128  ******************************************************************************/
 129 
 130 BOOLEAN
 131 AcpiEvValidGpeEvent (
 132     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
 133 {
 134     ACPI_GPE_XRUPT_INFO     *GpeXruptBlock;
 135     ACPI_GPE_BLOCK_INFO     *GpeBlock;
 136 
 137 
 138     ACPI_FUNCTION_ENTRY ();
 139 
 140 
 141     /* No need for spin lock since we are not changing any list elements */
 142 
 143     /* Walk the GPE interrupt levels */
 144 
 145     GpeXruptBlock = AcpiGbl_GpeXruptListHead;
 146     while (GpeXruptBlock)
 147     {
 148         GpeBlock = GpeXruptBlock->GpeBlockListHead;
 149 
 150         /* Walk the GPE blocks on this interrupt level */
 151 
 152         while (GpeBlock)
 153         {
 154             if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) &&
 155                 (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo))
 156             {
 157                 return (TRUE);
 158             }
 159 
 160             GpeBlock = GpeBlock->Next;
 161         }
 162 
 163         GpeXruptBlock = GpeXruptBlock->Next;
 164     }
 165 
 166     return (FALSE);
 167 }
 168 
 169 
 170 /*******************************************************************************
 171  *
 172  * FUNCTION:    AcpiEvGetGpeDevice
 173  *
 174  * PARAMETERS:  GPE_WALK_CALLBACK
 175  *
 176  * RETURN:      Status
 177  *
 178  * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE
 179  *              block device. NULL if the GPE is one of the FADT-defined GPEs.
 180  *
 181  ******************************************************************************/
 182 
 183 ACPI_STATUS
 184 AcpiEvGetGpeDevice (
 185     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
 186     ACPI_GPE_BLOCK_INFO     *GpeBlock,
 187     void                    *Context)
 188 {
 189     ACPI_GPE_DEVICE_INFO    *Info = Context;
 190 
 191 
 192     /* Increment Index by the number of GPEs in this block */
 193 
 194     Info->NextBlockBaseIndex += GpeBlock->GpeCount;
 195 
 196     if (Info->Index < Info->NextBlockBaseIndex)
 197     {
 198         /*
 199          * The GPE index is within this block, get the node. Leave the node
 200          * NULL for the FADT-defined GPEs
 201          */
 202         if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE)
 203         {
 204             Info->GpeDevice = GpeBlock->Node;
 205         }
 206 
 207         Info->Status = AE_OK;
 208         return (AE_CTRL_END);
 209     }
 210 
 211     return (AE_OK);
 212 }
 213 
 214 
 215 /*******************************************************************************
 216  *
 217  * FUNCTION:    AcpiEvGetGpeXruptBlock
 218  *
 219  * PARAMETERS:  InterruptNumber      - Interrupt for a GPE block
 220  *
 221  * RETURN:      A GPE interrupt block
 222  *
 223  * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
 224  *              block per unique interrupt level used for GPEs. Should be
 225  *              called only when the GPE lists are semaphore locked and not
 226  *              subject to change.
 227  *
 228  ******************************************************************************/
 229 
 230 ACPI_GPE_XRUPT_INFO *
 231 AcpiEvGetGpeXruptBlock (
 232     UINT32                  InterruptNumber)
 233 {
 234     ACPI_GPE_XRUPT_INFO     *NextGpeXrupt;
 235     ACPI_GPE_XRUPT_INFO     *GpeXrupt;
 236     ACPI_STATUS             Status;
 237     ACPI_CPU_FLAGS          Flags;
 238 
 239 
 240     ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock);
 241 
 242 
 243     /* No need for lock since we are not changing any list elements here */
 244 
 245     NextGpeXrupt = AcpiGbl_GpeXruptListHead;
 246     while (NextGpeXrupt)
 247     {
 248         if (NextGpeXrupt->InterruptNumber == InterruptNumber)
 249         {
 250             return_PTR (NextGpeXrupt);
 251         }
 252 
 253         NextGpeXrupt = NextGpeXrupt->Next;
 254     }
 255 
 256     /* Not found, must allocate a new xrupt descriptor */
 257 
 258     GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO));
 259     if (!GpeXrupt)
 260     {
 261         return_PTR (NULL);
 262     }
 263 
 264     GpeXrupt->InterruptNumber = InterruptNumber;
 265 
 266     /* Install new interrupt descriptor with spin lock */
 267 
 268     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
 269     if (AcpiGbl_GpeXruptListHead)
 270     {
 271         NextGpeXrupt = AcpiGbl_GpeXruptListHead;
 272         while (NextGpeXrupt->Next)
 273         {
 274             NextGpeXrupt = NextGpeXrupt->Next;
 275         }
 276 
 277         NextGpeXrupt->Next = GpeXrupt;
 278         GpeXrupt->Previous = NextGpeXrupt;
 279     }
 280     else
 281     {
 282         AcpiGbl_GpeXruptListHead = GpeXrupt;
 283     }
 284     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
 285 
 286     /* Install new interrupt handler if not SCI_INT */
 287 
 288     if (InterruptNumber != AcpiGbl_FADT.SciInterrupt)
 289     {
 290         Status = AcpiOsInstallInterruptHandler (InterruptNumber,
 291                     AcpiEvGpeXruptHandler, GpeXrupt);
 292         if (ACPI_FAILURE (Status))
 293         {
 294             ACPI_ERROR ((AE_INFO,
 295                 "Could not install GPE interrupt handler at level 0x%X",
 296                 InterruptNumber));
 297             return_PTR (NULL);
 298         }
 299     }
 300 
 301     return_PTR (GpeXrupt);
 302 }
 303 
 304 
 305 /*******************************************************************************
 306  *
 307  * FUNCTION:    AcpiEvDeleteGpeXrupt
 308  *
 309  * PARAMETERS:  GpeXrupt        - A GPE interrupt info block
 310  *
 311  * RETURN:      Status
 312  *
 313  * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
 314  *              interrupt handler if not the SCI interrupt.
 315  *
 316  ******************************************************************************/
 317 
 318 ACPI_STATUS
 319 AcpiEvDeleteGpeXrupt (
 320     ACPI_GPE_XRUPT_INFO     *GpeXrupt)
 321 {
 322     ACPI_STATUS             Status;
 323     ACPI_CPU_FLAGS          Flags;
 324 
 325 
 326     ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt);
 327 
 328 
 329     /* We never want to remove the SCI interrupt handler */
 330 
 331     if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt)
 332     {
 333         GpeXrupt->GpeBlockListHead = NULL;
 334         return_ACPI_STATUS (AE_OK);
 335     }
 336 
 337     /* Disable this interrupt */
 338 
 339     Status = AcpiOsRemoveInterruptHandler (
 340                 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler);
 341     if (ACPI_FAILURE (Status))
 342     {
 343         return_ACPI_STATUS (Status);
 344     }
 345 
 346     /* Unlink the interrupt block with lock */
 347 
 348     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
 349     if (GpeXrupt->Previous)
 350     {
 351         GpeXrupt->Previous->Next = GpeXrupt->Next;
 352     }
 353     else
 354     {
 355         /* No previous, update list head */
 356 
 357         AcpiGbl_GpeXruptListHead = GpeXrupt->Next;
 358     }
 359 
 360     if (GpeXrupt->Next)
 361     {
 362         GpeXrupt->Next->Previous = GpeXrupt->Previous;
 363     }
 364     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
 365 
 366     /* Free the block */
 367 
 368     ACPI_FREE (GpeXrupt);
 369     return_ACPI_STATUS (AE_OK);
 370 }
 371 
 372 
 373 /*******************************************************************************
 374  *
 375  * FUNCTION:    AcpiEvDeleteGpeHandlers
 376  *
 377  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
 378  *              GpeBlock            - Gpe Block info
 379  *
 380  * RETURN:      Status
 381  *
 382  * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
 383  *              Used only prior to termination.
 384  *
 385  ******************************************************************************/
 386 
 387 ACPI_STATUS
 388 AcpiEvDeleteGpeHandlers (
 389     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
 390     ACPI_GPE_BLOCK_INFO     *GpeBlock,
 391     void                    *Context)
 392 {
 393     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
 394     UINT32                  i;
 395     UINT32                  j;
 396 
 397 
 398     ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
 399 
 400 
 401     /* Examine each GPE Register within the block */
 402 
 403     for (i = 0; i < GpeBlock->RegisterCount; i++)
 404     {
 405         /* Now look at the individual GPEs in this byte register */
 406 
 407         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
 408         {
 409             GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
 410                 ACPI_GPE_REGISTER_WIDTH) + j];
 411 
 412             if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
 413                     ACPI_GPE_DISPATCH_HANDLER)
 414             {
 415                 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
 416                 GpeEventInfo->Dispatch.Handler = NULL;
 417                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
 418             }
 419         }
 420     }
 421 
 422     return_ACPI_STATUS (AE_OK);
 423 }
 424