1207340Sjkim/****************************************************************************** 2207340Sjkim * 3207340Sjkim * Module Name: evgpeutil - GPE utilities 4207340Sjkim * 5207340Sjkim *****************************************************************************/ 6207340Sjkim 7217365Sjkim/* 8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp. 9207340Sjkim * All rights reserved. 10207340Sjkim * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 25207340Sjkim * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 29207340Sjkim * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 43207340Sjkim 44207344Sjkim#include <contrib/dev/acpica/include/acpi.h> 45207344Sjkim#include <contrib/dev/acpica/include/accommon.h> 46207344Sjkim#include <contrib/dev/acpica/include/acevents.h> 47207340Sjkim 48207340Sjkim#define _COMPONENT ACPI_EVENTS 49207340Sjkim ACPI_MODULE_NAME ("evgpeutil") 50207340Sjkim 51207340Sjkim 52231844Sjkim#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53207340Sjkim/******************************************************************************* 54207340Sjkim * 55207340Sjkim * FUNCTION: AcpiEvWalkGpeList 56207340Sjkim * 57207340Sjkim * PARAMETERS: GpeWalkCallback - Routine called for each GPE block 58207340Sjkim * Context - Value passed to callback 59207340Sjkim * 60207340Sjkim * RETURN: Status 61207340Sjkim * 62207340Sjkim * DESCRIPTION: Walk the GPE lists. 63207340Sjkim * 64207340Sjkim ******************************************************************************/ 65207340Sjkim 66207340SjkimACPI_STATUS 67207340SjkimAcpiEvWalkGpeList ( 68207340Sjkim ACPI_GPE_CALLBACK GpeWalkCallback, 69207340Sjkim void *Context) 70207340Sjkim{ 71207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock; 72207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptInfo; 73207340Sjkim ACPI_STATUS Status = AE_OK; 74207340Sjkim ACPI_CPU_FLAGS Flags; 75207340Sjkim 76207340Sjkim 77207340Sjkim ACPI_FUNCTION_TRACE (EvWalkGpeList); 78207340Sjkim 79207340Sjkim 80207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 81207340Sjkim 82207340Sjkim /* Walk the interrupt level descriptor list */ 83207340Sjkim 84207340Sjkim GpeXruptInfo = AcpiGbl_GpeXruptListHead; 85207340Sjkim while (GpeXruptInfo) 86207340Sjkim { 87207340Sjkim /* Walk all Gpe Blocks attached to this interrupt level */ 88207340Sjkim 89207340Sjkim GpeBlock = GpeXruptInfo->GpeBlockListHead; 90207340Sjkim while (GpeBlock) 91207340Sjkim { 92207340Sjkim /* One callback per GPE block */ 93207340Sjkim 94207340Sjkim Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context); 95207340Sjkim if (ACPI_FAILURE (Status)) 96207340Sjkim { 97207340Sjkim if (Status == AE_CTRL_END) /* Callback abort */ 98207340Sjkim { 99207340Sjkim Status = AE_OK; 100207340Sjkim } 101207340Sjkim goto UnlockAndExit; 102207340Sjkim } 103207340Sjkim 104207340Sjkim GpeBlock = GpeBlock->Next; 105207340Sjkim } 106207340Sjkim 107207340Sjkim GpeXruptInfo = GpeXruptInfo->Next; 108207340Sjkim } 109207340Sjkim 110207340SjkimUnlockAndExit: 111207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 112207340Sjkim return_ACPI_STATUS (Status); 113207340Sjkim} 114207340Sjkim 115207340Sjkim 116207340Sjkim/******************************************************************************* 117207340Sjkim * 118207340Sjkim * FUNCTION: AcpiEvValidGpeEvent 119207340Sjkim * 120207340Sjkim * PARAMETERS: GpeEventInfo - Info for this GPE 121207340Sjkim * 122207340Sjkim * RETURN: TRUE if the GpeEvent is valid 123207340Sjkim * 124207340Sjkim * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. 125207340Sjkim * Should be called only when the GPE lists are semaphore locked 126207340Sjkim * and not subject to change. 127207340Sjkim * 128207340Sjkim ******************************************************************************/ 129207340Sjkim 130207340SjkimBOOLEAN 131207340SjkimAcpiEvValidGpeEvent ( 132207340Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 133207340Sjkim{ 134207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 135207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock; 136207340Sjkim 137207340Sjkim 138207340Sjkim ACPI_FUNCTION_ENTRY (); 139207340Sjkim 140207340Sjkim 141207340Sjkim /* No need for spin lock since we are not changing any list elements */ 142207340Sjkim 143207340Sjkim /* Walk the GPE interrupt levels */ 144207340Sjkim 145207340Sjkim GpeXruptBlock = AcpiGbl_GpeXruptListHead; 146207340Sjkim while (GpeXruptBlock) 147207340Sjkim { 148207340Sjkim GpeBlock = GpeXruptBlock->GpeBlockListHead; 149207340Sjkim 150207340Sjkim /* Walk the GPE blocks on this interrupt level */ 151207340Sjkim 152207340Sjkim while (GpeBlock) 153207340Sjkim { 154207340Sjkim if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) && 155207340Sjkim (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo)) 156207340Sjkim { 157207340Sjkim return (TRUE); 158207340Sjkim } 159207340Sjkim 160207340Sjkim GpeBlock = GpeBlock->Next; 161207340Sjkim } 162207340Sjkim 163207340Sjkim GpeXruptBlock = GpeXruptBlock->Next; 164207340Sjkim } 165207340Sjkim 166207340Sjkim return (FALSE); 167207340Sjkim} 168207340Sjkim 169207340Sjkim 170207340Sjkim/******************************************************************************* 171207340Sjkim * 172216471Sjkim * FUNCTION: AcpiEvGetGpeDevice 173216471Sjkim * 174216471Sjkim * PARAMETERS: GPE_WALK_CALLBACK 175216471Sjkim * 176216471Sjkim * RETURN: Status 177216471Sjkim * 178216471Sjkim * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE 179216471Sjkim * block device. NULL if the GPE is one of the FADT-defined GPEs. 180216471Sjkim * 181216471Sjkim ******************************************************************************/ 182216471Sjkim 183216471SjkimACPI_STATUS 184216471SjkimAcpiEvGetGpeDevice ( 185216471Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 186216471Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock, 187216471Sjkim void *Context) 188216471Sjkim{ 189216471Sjkim ACPI_GPE_DEVICE_INFO *Info = Context; 190216471Sjkim 191216471Sjkim 192216471Sjkim /* Increment Index by the number of GPEs in this block */ 193216471Sjkim 194216471Sjkim Info->NextBlockBaseIndex += GpeBlock->GpeCount; 195216471Sjkim 196216471Sjkim if (Info->Index < Info->NextBlockBaseIndex) 197216471Sjkim { 198216471Sjkim /* 199216471Sjkim * The GPE index is within this block, get the node. Leave the node 200216471Sjkim * NULL for the FADT-defined GPEs 201216471Sjkim */ 202216471Sjkim if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE) 203216471Sjkim { 204216471Sjkim Info->GpeDevice = GpeBlock->Node; 205216471Sjkim } 206216471Sjkim 207216471Sjkim Info->Status = AE_OK; 208216471Sjkim return (AE_CTRL_END); 209216471Sjkim } 210216471Sjkim 211216471Sjkim return (AE_OK); 212216471Sjkim} 213216471Sjkim 214216471Sjkim 215216471Sjkim/******************************************************************************* 216216471Sjkim * 217207340Sjkim * FUNCTION: AcpiEvGetGpeXruptBlock 218207340Sjkim * 219254745Sjkim * PARAMETERS: InterruptNumber - Interrupt for a GPE block 220207340Sjkim * 221207340Sjkim * RETURN: A GPE interrupt block 222207340Sjkim * 223207340Sjkim * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 224207340Sjkim * block per unique interrupt level used for GPEs. Should be 225207340Sjkim * called only when the GPE lists are semaphore locked and not 226207340Sjkim * subject to change. 227207340Sjkim * 228207340Sjkim ******************************************************************************/ 229207340Sjkim 230207340SjkimACPI_GPE_XRUPT_INFO * 231207340SjkimAcpiEvGetGpeXruptBlock ( 232207340Sjkim UINT32 InterruptNumber) 233207340Sjkim{ 234207340Sjkim ACPI_GPE_XRUPT_INFO *NextGpeXrupt; 235207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXrupt; 236207340Sjkim ACPI_STATUS Status; 237207340Sjkim ACPI_CPU_FLAGS Flags; 238207340Sjkim 239207340Sjkim 240207340Sjkim ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); 241207340Sjkim 242207340Sjkim 243207340Sjkim /* No need for lock since we are not changing any list elements here */ 244207340Sjkim 245207340Sjkim NextGpeXrupt = AcpiGbl_GpeXruptListHead; 246207340Sjkim while (NextGpeXrupt) 247207340Sjkim { 248207340Sjkim if (NextGpeXrupt->InterruptNumber == InterruptNumber) 249207340Sjkim { 250207340Sjkim return_PTR (NextGpeXrupt); 251207340Sjkim } 252207340Sjkim 253207340Sjkim NextGpeXrupt = NextGpeXrupt->Next; 254207340Sjkim } 255207340Sjkim 256207340Sjkim /* Not found, must allocate a new xrupt descriptor */ 257207340Sjkim 258207340Sjkim GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); 259207340Sjkim if (!GpeXrupt) 260207340Sjkim { 261207340Sjkim return_PTR (NULL); 262207340Sjkim } 263207340Sjkim 264207340Sjkim GpeXrupt->InterruptNumber = InterruptNumber; 265207340Sjkim 266207340Sjkim /* Install new interrupt descriptor with spin lock */ 267207340Sjkim 268207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 269207340Sjkim if (AcpiGbl_GpeXruptListHead) 270207340Sjkim { 271207340Sjkim NextGpeXrupt = AcpiGbl_GpeXruptListHead; 272207340Sjkim while (NextGpeXrupt->Next) 273207340Sjkim { 274207340Sjkim NextGpeXrupt = NextGpeXrupt->Next; 275207340Sjkim } 276207340Sjkim 277207340Sjkim NextGpeXrupt->Next = GpeXrupt; 278207340Sjkim GpeXrupt->Previous = NextGpeXrupt; 279207340Sjkim } 280207340Sjkim else 281207340Sjkim { 282207340Sjkim AcpiGbl_GpeXruptListHead = GpeXrupt; 283207340Sjkim } 284207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 285207340Sjkim 286207340Sjkim /* Install new interrupt handler if not SCI_INT */ 287207340Sjkim 288207340Sjkim if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) 289207340Sjkim { 290207340Sjkim Status = AcpiOsInstallInterruptHandler (InterruptNumber, 291207340Sjkim AcpiEvGpeXruptHandler, GpeXrupt); 292207340Sjkim if (ACPI_FAILURE (Status)) 293207340Sjkim { 294207340Sjkim ACPI_ERROR ((AE_INFO, 295207340Sjkim "Could not install GPE interrupt handler at level 0x%X", 296207340Sjkim InterruptNumber)); 297207340Sjkim return_PTR (NULL); 298207340Sjkim } 299207340Sjkim } 300207340Sjkim 301207340Sjkim return_PTR (GpeXrupt); 302207340Sjkim} 303207340Sjkim 304207340Sjkim 305207340Sjkim/******************************************************************************* 306207340Sjkim * 307207340Sjkim * FUNCTION: AcpiEvDeleteGpeXrupt 308207340Sjkim * 309207340Sjkim * PARAMETERS: GpeXrupt - A GPE interrupt info block 310207340Sjkim * 311207340Sjkim * RETURN: Status 312207340Sjkim * 313207340Sjkim * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated 314207340Sjkim * interrupt handler if not the SCI interrupt. 315207340Sjkim * 316207340Sjkim ******************************************************************************/ 317207340Sjkim 318207340SjkimACPI_STATUS 319207340SjkimAcpiEvDeleteGpeXrupt ( 320207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXrupt) 321207340Sjkim{ 322207340Sjkim ACPI_STATUS Status; 323207340Sjkim ACPI_CPU_FLAGS Flags; 324207340Sjkim 325207340Sjkim 326207340Sjkim ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); 327207340Sjkim 328207340Sjkim 329207340Sjkim /* We never want to remove the SCI interrupt handler */ 330207340Sjkim 331207340Sjkim if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) 332207340Sjkim { 333207340Sjkim GpeXrupt->GpeBlockListHead = NULL; 334207340Sjkim return_ACPI_STATUS (AE_OK); 335207340Sjkim } 336207340Sjkim 337207340Sjkim /* Disable this interrupt */ 338207340Sjkim 339207340Sjkim Status = AcpiOsRemoveInterruptHandler ( 340207340Sjkim GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); 341207340Sjkim if (ACPI_FAILURE (Status)) 342207340Sjkim { 343207340Sjkim return_ACPI_STATUS (Status); 344207340Sjkim } 345207340Sjkim 346207340Sjkim /* Unlink the interrupt block with lock */ 347207340Sjkim 348207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 349207340Sjkim if (GpeXrupt->Previous) 350207340Sjkim { 351207340Sjkim GpeXrupt->Previous->Next = GpeXrupt->Next; 352207340Sjkim } 353207340Sjkim else 354207340Sjkim { 355207340Sjkim /* No previous, update list head */ 356207340Sjkim 357207340Sjkim AcpiGbl_GpeXruptListHead = GpeXrupt->Next; 358207340Sjkim } 359207340Sjkim 360207340Sjkim if (GpeXrupt->Next) 361207340Sjkim { 362207340Sjkim GpeXrupt->Next->Previous = GpeXrupt->Previous; 363207340Sjkim } 364207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 365207340Sjkim 366207340Sjkim /* Free the block */ 367207340Sjkim 368207340Sjkim ACPI_FREE (GpeXrupt); 369207340Sjkim return_ACPI_STATUS (AE_OK); 370207340Sjkim} 371207340Sjkim 372207340Sjkim 373207340Sjkim/******************************************************************************* 374207340Sjkim * 375207340Sjkim * FUNCTION: AcpiEvDeleteGpeHandlers 376207340Sjkim * 377207340Sjkim * PARAMETERS: GpeXruptInfo - GPE Interrupt info 378207340Sjkim * GpeBlock - Gpe Block info 379207340Sjkim * 380207340Sjkim * RETURN: Status 381207340Sjkim * 382207340Sjkim * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 383207340Sjkim * Used only prior to termination. 384207340Sjkim * 385207340Sjkim ******************************************************************************/ 386207340Sjkim 387207340SjkimACPI_STATUS 388207340SjkimAcpiEvDeleteGpeHandlers ( 389207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 390207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock, 391207340Sjkim void *Context) 392207340Sjkim{ 393207340Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo; 394237412Sjkim ACPI_GPE_NOTIFY_INFO *Notify; 395237412Sjkim ACPI_GPE_NOTIFY_INFO *Next; 396207340Sjkim UINT32 i; 397207340Sjkim UINT32 j; 398207340Sjkim 399207340Sjkim 400207340Sjkim ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); 401207340Sjkim 402207340Sjkim 403207340Sjkim /* Examine each GPE Register within the block */ 404207340Sjkim 405207340Sjkim for (i = 0; i < GpeBlock->RegisterCount; i++) 406207340Sjkim { 407207340Sjkim /* Now look at the individual GPEs in this byte register */ 408207340Sjkim 409207340Sjkim for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 410207340Sjkim { 411207340Sjkim GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 412207340Sjkim ACPI_GPE_REGISTER_WIDTH) + j]; 413207340Sjkim 414207340Sjkim if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 415207340Sjkim ACPI_GPE_DISPATCH_HANDLER) 416207340Sjkim { 417237412Sjkim /* Delete an installed handler block */ 418237412Sjkim 419207340Sjkim ACPI_FREE (GpeEventInfo->Dispatch.Handler); 420207340Sjkim GpeEventInfo->Dispatch.Handler = NULL; 421207340Sjkim GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 422207340Sjkim } 423237412Sjkim else if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 424237412Sjkim ACPI_GPE_DISPATCH_NOTIFY) 425237412Sjkim { 426237412Sjkim /* Delete the implicit notification device list */ 427237412Sjkim 428237412Sjkim Notify = GpeEventInfo->Dispatch.NotifyList; 429237412Sjkim while (Notify) 430237412Sjkim { 431237412Sjkim Next = Notify->Next; 432237412Sjkim ACPI_FREE (Notify); 433237412Sjkim Notify = Next; 434237412Sjkim } 435237412Sjkim GpeEventInfo->Dispatch.NotifyList = NULL; 436237412Sjkim GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 437237412Sjkim } 438207340Sjkim } 439207340Sjkim } 440207340Sjkim 441207340Sjkim return_ACPI_STATUS (AE_OK); 442207340Sjkim} 443207340Sjkim 444231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 445