1 /******************************************************************************
   2  *
   3  * Module Name: evgpeutil - GPE utilities
   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 
  48 #define _COMPONENT          ACPI_EVENTS
  49         ACPI_MODULE_NAME    ("evgpeutil")
  50 
  51 
  52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
  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  *              GpeXruptBlock               - Where the block is returned
 221  *
 222  * RETURN:      Status
 223  *
 224  * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
 225  *              block per unique interrupt level used for GPEs. Should be
 226  *              called only when the GPE lists are semaphore locked and not
 227  *              subject to change.
 228  *
 229  ******************************************************************************/
 230 
 231 ACPI_STATUS
 232 AcpiEvGetGpeXruptBlock (
 233     UINT32                  InterruptNumber,
 234     ACPI_GPE_XRUPT_INFO     **GpeXruptBlock)
 235 {
 236     ACPI_GPE_XRUPT_INFO     *NextGpeXrupt;
 237     ACPI_GPE_XRUPT_INFO     *GpeXrupt;
 238     ACPI_STATUS             Status;
 239     ACPI_CPU_FLAGS          Flags;
 240 
 241 
 242     ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock);
 243 
 244 
 245     /* No need for lock since we are not changing any list elements here */
 246 
 247     NextGpeXrupt = AcpiGbl_GpeXruptListHead;
 248     while (NextGpeXrupt)
 249     {
 250         if (NextGpeXrupt->InterruptNumber == InterruptNumber)
 251         {
 252             *GpeXruptBlock = NextGpeXrupt;
 253             return_ACPI_STATUS (AE_OK);
 254         }
 255 
 256         NextGpeXrupt = NextGpeXrupt->Next;
 257     }
 258 
 259     /* Not found, must allocate a new xrupt descriptor */
 260 
 261     GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO));
 262     if (!GpeXrupt)
 263     {
 264         return_ACPI_STATUS (AE_NO_MEMORY);
 265     }
 266 
 267     GpeXrupt->InterruptNumber = InterruptNumber;
 268 
 269     /* Install new interrupt descriptor with spin lock */
 270 
 271     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
 272     if (AcpiGbl_GpeXruptListHead)
 273     {
 274         NextGpeXrupt = AcpiGbl_GpeXruptListHead;
 275         while (NextGpeXrupt->Next)
 276         {
 277             NextGpeXrupt = NextGpeXrupt->Next;
 278         }
 279 
 280         NextGpeXrupt->Next = GpeXrupt;
 281         GpeXrupt->Previous = NextGpeXrupt;
 282     }
 283     else
 284     {
 285         AcpiGbl_GpeXruptListHead = GpeXrupt;
 286     }
 287 
 288     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
 289 
 290     /* Install new interrupt handler if not SCI_INT */
 291 
 292     if (InterruptNumber != AcpiGbl_FADT.SciInterrupt)
 293     {
 294         Status = AcpiOsInstallInterruptHandler (InterruptNumber,
 295                     AcpiEvGpeXruptHandler, GpeXrupt);
 296         if (ACPI_FAILURE (Status))
 297         {
 298             ACPI_EXCEPTION ((AE_INFO, Status,
 299                 "Could not install GPE interrupt handler at level 0x%X",
 300                 InterruptNumber));
 301             return_ACPI_STATUS (Status);
 302         }
 303     }
 304 
 305     *GpeXruptBlock = GpeXrupt;
 306     return_ACPI_STATUS (AE_OK);
 307 }
 308 
 309 
 310 /*******************************************************************************
 311  *
 312  * FUNCTION:    AcpiEvDeleteGpeXrupt
 313  *
 314  * PARAMETERS:  GpeXrupt        - A GPE interrupt info block
 315  *
 316  * RETURN:      Status
 317  *
 318  * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
 319  *              interrupt handler if not the SCI interrupt.
 320  *
 321  ******************************************************************************/
 322 
 323 ACPI_STATUS
 324 AcpiEvDeleteGpeXrupt (
 325     ACPI_GPE_XRUPT_INFO     *GpeXrupt)
 326 {
 327     ACPI_STATUS             Status;
 328     ACPI_CPU_FLAGS          Flags;
 329 
 330 
 331     ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt);
 332 
 333 
 334     /* We never want to remove the SCI interrupt handler */
 335 
 336     if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt)
 337     {
 338         GpeXrupt->GpeBlockListHead = NULL;
 339         return_ACPI_STATUS (AE_OK);
 340     }
 341 
 342     /* Disable this interrupt */
 343 
 344     Status = AcpiOsRemoveInterruptHandler (
 345                 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler);
 346     if (ACPI_FAILURE (Status))
 347     {
 348         return_ACPI_STATUS (Status);
 349     }
 350 
 351     /* Unlink the interrupt block with lock */
 352 
 353     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
 354     if (GpeXrupt->Previous)
 355     {
 356         GpeXrupt->Previous->Next = GpeXrupt->Next;
 357     }
 358     else
 359     {
 360         /* No previous, update list head */
 361 
 362         AcpiGbl_GpeXruptListHead = GpeXrupt->Next;
 363     }
 364 
 365     if (GpeXrupt->Next)
 366     {
 367         GpeXrupt->Next->Previous = GpeXrupt->Previous;
 368     }
 369     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
 370 
 371     /* Free the block */
 372 
 373     ACPI_FREE (GpeXrupt);
 374     return_ACPI_STATUS (AE_OK);
 375 }
 376 
 377 
 378 /*******************************************************************************
 379  *
 380  * FUNCTION:    AcpiEvDeleteGpeHandlers
 381  *
 382  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
 383  *              GpeBlock            - Gpe Block info
 384  *
 385  * RETURN:      Status
 386  *
 387  * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
 388  *              Used only prior to termination.
 389  *
 390  ******************************************************************************/
 391 
 392 ACPI_STATUS
 393 AcpiEvDeleteGpeHandlers (
 394     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
 395     ACPI_GPE_BLOCK_INFO     *GpeBlock,
 396     void                    *Context)
 397 {
 398     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
 399     ACPI_GPE_NOTIFY_INFO    *Notify;
 400     ACPI_GPE_NOTIFY_INFO    *Next;
 401     UINT32                  i;
 402     UINT32                  j;
 403 
 404 
 405     ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
 406 
 407 
 408     /* Examine each GPE Register within the block */
 409 
 410     for (i = 0; i < GpeBlock->RegisterCount; i++)
 411     {
 412         /* Now look at the individual GPEs in this byte register */
 413 
 414         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
 415         {
 416             GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
 417                 ACPI_GPE_REGISTER_WIDTH) + j];
 418 
 419             if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
 420                     ACPI_GPE_DISPATCH_HANDLER)
 421             {
 422                 /* Delete an installed handler block */
 423 
 424                 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
 425                 GpeEventInfo->Dispatch.Handler = NULL;
 426                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
 427             }
 428             else if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
 429                     ACPI_GPE_DISPATCH_NOTIFY)
 430             {
 431                 /* Delete the implicit notification device list */
 432 
 433                 Notify = GpeEventInfo->Dispatch.NotifyList;
 434                 while (Notify)
 435                 {
 436                     Next = Notify->Next;
 437                     ACPI_FREE (Notify);
 438                     Notify = Next;
 439                 }
 440                 GpeEventInfo->Dispatch.NotifyList = NULL;
 441                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
 442             }
 443         }
 444     }
 445 
 446     return_ACPI_STATUS (AE_OK);
 447 }
 448 
 449 #endif /* !ACPI_REDUCED_HARDWARE */