evgpeutil.c revision 207344
1207340Sjkim/****************************************************************************** 2207340Sjkim * 3207340Sjkim * Module Name: evgpeutil - GPE utilities 4207340Sjkim * 5207340Sjkim *****************************************************************************/ 6207340Sjkim 7207340Sjkim/****************************************************************************** 8207340Sjkim * 9207340Sjkim * 1. Copyright Notice 10207340Sjkim * 11207340Sjkim * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. 12207340Sjkim * All rights reserved. 13207340Sjkim * 14207340Sjkim * 2. License 15207340Sjkim * 16207340Sjkim * 2.1. This is your license from Intel Corp. under its intellectual property 17207340Sjkim * rights. You may have additional license terms from the party that provided 18207340Sjkim * you this software, covering your right to use that party's intellectual 19207340Sjkim * property rights. 20207340Sjkim * 21207340Sjkim * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22207340Sjkim * copy of the source code appearing in this file ("Covered Code") an 23207340Sjkim * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24207340Sjkim * base code distributed originally by Intel ("Original Intel Code") to copy, 25207340Sjkim * make derivatives, distribute, use and display any portion of the Covered 26207340Sjkim * Code in any form, with the right to sublicense such rights; and 27207340Sjkim * 28207340Sjkim * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29207340Sjkim * license (with the right to sublicense), under only those claims of Intel 30207340Sjkim * patents that are infringed by the Original Intel Code, to make, use, sell, 31207340Sjkim * offer to sell, and import the Covered Code and derivative works thereof 32207340Sjkim * solely to the minimum extent necessary to exercise the above copyright 33207340Sjkim * license, and in no event shall the patent license extend to any additions 34207340Sjkim * to or modifications of the Original Intel Code. No other license or right 35207340Sjkim * is granted directly or by implication, estoppel or otherwise; 36207340Sjkim * 37207340Sjkim * The above copyright and patent license is granted only if the following 38207340Sjkim * conditions are met: 39207340Sjkim * 40207340Sjkim * 3. Conditions 41207340Sjkim * 42207340Sjkim * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43207340Sjkim * Redistribution of source code of any substantial portion of the Covered 44207340Sjkim * Code or modification with rights to further distribute source must include 45207340Sjkim * the above Copyright Notice, the above License, this list of Conditions, 46207340Sjkim * and the following Disclaimer and Export Compliance provision. In addition, 47207340Sjkim * Licensee must cause all Covered Code to which Licensee contributes to 48207340Sjkim * contain a file documenting the changes Licensee made to create that Covered 49207340Sjkim * Code and the date of any change. Licensee must include in that file the 50207340Sjkim * documentation of any changes made by any predecessor Licensee. Licensee 51207340Sjkim * must include a prominent statement that the modification is derived, 52207340Sjkim * directly or indirectly, from Original Intel Code. 53207340Sjkim * 54207340Sjkim * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55207340Sjkim * Redistribution of source code of any substantial portion of the Covered 56207340Sjkim * Code or modification without rights to further distribute source must 57207340Sjkim * include the following Disclaimer and Export Compliance provision in the 58207340Sjkim * documentation and/or other materials provided with distribution. In 59207340Sjkim * addition, Licensee may not authorize further sublicense of source of any 60207340Sjkim * portion of the Covered Code, and must include terms to the effect that the 61207340Sjkim * license from Licensee to its licensee is limited to the intellectual 62207340Sjkim * property embodied in the software Licensee provides to its licensee, and 63207340Sjkim * not to intellectual property embodied in modifications its licensee may 64207340Sjkim * make. 65207340Sjkim * 66207340Sjkim * 3.3. Redistribution of Executable. Redistribution in executable form of any 67207340Sjkim * substantial portion of the Covered Code or modification must reproduce the 68207340Sjkim * above Copyright Notice, and the following Disclaimer and Export Compliance 69207340Sjkim * provision in the documentation and/or other materials provided with the 70207340Sjkim * distribution. 71207340Sjkim * 72207340Sjkim * 3.4. Intel retains all right, title, and interest in and to the Original 73207340Sjkim * Intel Code. 74207340Sjkim * 75207340Sjkim * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76207340Sjkim * Intel shall be used in advertising or otherwise to promote the sale, use or 77207340Sjkim * other dealings in products derived from or relating to the Covered Code 78207340Sjkim * without prior written authorization from Intel. 79207340Sjkim * 80207340Sjkim * 4. Disclaimer and Export Compliance 81207340Sjkim * 82207340Sjkim * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83207340Sjkim * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84207340Sjkim * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85207340Sjkim * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86207340Sjkim * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87207340Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88207340Sjkim * PARTICULAR PURPOSE. 89207340Sjkim * 90207340Sjkim * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91207340Sjkim * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92207340Sjkim * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93207340Sjkim * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94207340Sjkim * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95207340Sjkim * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96207340Sjkim * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97207340Sjkim * LIMITED REMEDY. 98207340Sjkim * 99207340Sjkim * 4.3. Licensee shall not export, either directly or indirectly, any of this 100207340Sjkim * software or system incorporating such software without first obtaining any 101207340Sjkim * required license or other approval from the U. S. Department of Commerce or 102207340Sjkim * any other agency or department of the United States Government. In the 103207340Sjkim * event Licensee exports any such software from the United States or 104207340Sjkim * re-exports any such software from a foreign destination, Licensee shall 105207340Sjkim * ensure that the distribution and export/re-export of the software is in 106207340Sjkim * compliance with all laws, regulations, orders, or other restrictions of the 107207340Sjkim * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108207340Sjkim * any of its subsidiaries will export/re-export any technical data, process, 109207340Sjkim * software, or service, directly or indirectly, to any country for which the 110207340Sjkim * United States government or any agency thereof requires an export license, 111207340Sjkim * other governmental approval, or letter of assurance, without first obtaining 112207340Sjkim * such license, approval or letter. 113207340Sjkim * 114207340Sjkim *****************************************************************************/ 115207340Sjkim 116207340Sjkim 117207340Sjkim 118207344Sjkim#include <contrib/dev/acpica/include/acpi.h> 119207344Sjkim#include <contrib/dev/acpica/include/accommon.h> 120207344Sjkim#include <contrib/dev/acpica/include/acevents.h> 121207340Sjkim 122207340Sjkim#define _COMPONENT ACPI_EVENTS 123207340Sjkim ACPI_MODULE_NAME ("evgpeutil") 124207340Sjkim 125207340Sjkim 126207340Sjkim/******************************************************************************* 127207340Sjkim * 128207340Sjkim * FUNCTION: AcpiEvWalkGpeList 129207340Sjkim * 130207340Sjkim * PARAMETERS: GpeWalkCallback - Routine called for each GPE block 131207340Sjkim * Context - Value passed to callback 132207340Sjkim * 133207340Sjkim * RETURN: Status 134207340Sjkim * 135207340Sjkim * DESCRIPTION: Walk the GPE lists. 136207340Sjkim * 137207340Sjkim ******************************************************************************/ 138207340Sjkim 139207340SjkimACPI_STATUS 140207340SjkimAcpiEvWalkGpeList ( 141207340Sjkim ACPI_GPE_CALLBACK GpeWalkCallback, 142207340Sjkim void *Context) 143207340Sjkim{ 144207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock; 145207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptInfo; 146207340Sjkim ACPI_STATUS Status = AE_OK; 147207340Sjkim ACPI_CPU_FLAGS Flags; 148207340Sjkim 149207340Sjkim 150207340Sjkim ACPI_FUNCTION_TRACE (EvWalkGpeList); 151207340Sjkim 152207340Sjkim 153207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 154207340Sjkim 155207340Sjkim /* Walk the interrupt level descriptor list */ 156207340Sjkim 157207340Sjkim GpeXruptInfo = AcpiGbl_GpeXruptListHead; 158207340Sjkim while (GpeXruptInfo) 159207340Sjkim { 160207340Sjkim /* Walk all Gpe Blocks attached to this interrupt level */ 161207340Sjkim 162207340Sjkim GpeBlock = GpeXruptInfo->GpeBlockListHead; 163207340Sjkim while (GpeBlock) 164207340Sjkim { 165207340Sjkim /* One callback per GPE block */ 166207340Sjkim 167207340Sjkim Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context); 168207340Sjkim if (ACPI_FAILURE (Status)) 169207340Sjkim { 170207340Sjkim if (Status == AE_CTRL_END) /* Callback abort */ 171207340Sjkim { 172207340Sjkim Status = AE_OK; 173207340Sjkim } 174207340Sjkim goto UnlockAndExit; 175207340Sjkim } 176207340Sjkim 177207340Sjkim GpeBlock = GpeBlock->Next; 178207340Sjkim } 179207340Sjkim 180207340Sjkim GpeXruptInfo = GpeXruptInfo->Next; 181207340Sjkim } 182207340Sjkim 183207340SjkimUnlockAndExit: 184207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 185207340Sjkim return_ACPI_STATUS (Status); 186207340Sjkim} 187207340Sjkim 188207340Sjkim 189207340Sjkim/******************************************************************************* 190207340Sjkim * 191207340Sjkim * FUNCTION: AcpiEvValidGpeEvent 192207340Sjkim * 193207340Sjkim * PARAMETERS: GpeEventInfo - Info for this GPE 194207340Sjkim * 195207340Sjkim * RETURN: TRUE if the GpeEvent is valid 196207340Sjkim * 197207340Sjkim * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. 198207340Sjkim * Should be called only when the GPE lists are semaphore locked 199207340Sjkim * and not subject to change. 200207340Sjkim * 201207340Sjkim ******************************************************************************/ 202207340Sjkim 203207340SjkimBOOLEAN 204207340SjkimAcpiEvValidGpeEvent ( 205207340Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 206207340Sjkim{ 207207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 208207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock; 209207340Sjkim 210207340Sjkim 211207340Sjkim ACPI_FUNCTION_ENTRY (); 212207340Sjkim 213207340Sjkim 214207340Sjkim /* No need for spin lock since we are not changing any list elements */ 215207340Sjkim 216207340Sjkim /* Walk the GPE interrupt levels */ 217207340Sjkim 218207340Sjkim GpeXruptBlock = AcpiGbl_GpeXruptListHead; 219207340Sjkim while (GpeXruptBlock) 220207340Sjkim { 221207340Sjkim GpeBlock = GpeXruptBlock->GpeBlockListHead; 222207340Sjkim 223207340Sjkim /* Walk the GPE blocks on this interrupt level */ 224207340Sjkim 225207340Sjkim while (GpeBlock) 226207340Sjkim { 227207340Sjkim if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) && 228207340Sjkim (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo)) 229207340Sjkim { 230207340Sjkim return (TRUE); 231207340Sjkim } 232207340Sjkim 233207340Sjkim GpeBlock = GpeBlock->Next; 234207340Sjkim } 235207340Sjkim 236207340Sjkim GpeXruptBlock = GpeXruptBlock->Next; 237207340Sjkim } 238207340Sjkim 239207340Sjkim return (FALSE); 240207340Sjkim} 241207340Sjkim 242207340Sjkim 243207340Sjkim/******************************************************************************* 244207340Sjkim * 245207340Sjkim * FUNCTION: AcpiEvGetGpeXruptBlock 246207340Sjkim * 247207340Sjkim * PARAMETERS: InterruptNumber - Interrupt for a GPE block 248207340Sjkim * 249207340Sjkim * RETURN: A GPE interrupt block 250207340Sjkim * 251207340Sjkim * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 252207340Sjkim * block per unique interrupt level used for GPEs. Should be 253207340Sjkim * called only when the GPE lists are semaphore locked and not 254207340Sjkim * subject to change. 255207340Sjkim * 256207340Sjkim ******************************************************************************/ 257207340Sjkim 258207340SjkimACPI_GPE_XRUPT_INFO * 259207340SjkimAcpiEvGetGpeXruptBlock ( 260207340Sjkim UINT32 InterruptNumber) 261207340Sjkim{ 262207340Sjkim ACPI_GPE_XRUPT_INFO *NextGpeXrupt; 263207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXrupt; 264207340Sjkim ACPI_STATUS Status; 265207340Sjkim ACPI_CPU_FLAGS Flags; 266207340Sjkim 267207340Sjkim 268207340Sjkim ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); 269207340Sjkim 270207340Sjkim 271207340Sjkim /* No need for lock since we are not changing any list elements here */ 272207340Sjkim 273207340Sjkim NextGpeXrupt = AcpiGbl_GpeXruptListHead; 274207340Sjkim while (NextGpeXrupt) 275207340Sjkim { 276207340Sjkim if (NextGpeXrupt->InterruptNumber == InterruptNumber) 277207340Sjkim { 278207340Sjkim return_PTR (NextGpeXrupt); 279207340Sjkim } 280207340Sjkim 281207340Sjkim NextGpeXrupt = NextGpeXrupt->Next; 282207340Sjkim } 283207340Sjkim 284207340Sjkim /* Not found, must allocate a new xrupt descriptor */ 285207340Sjkim 286207340Sjkim GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); 287207340Sjkim if (!GpeXrupt) 288207340Sjkim { 289207340Sjkim return_PTR (NULL); 290207340Sjkim } 291207340Sjkim 292207340Sjkim GpeXrupt->InterruptNumber = InterruptNumber; 293207340Sjkim 294207340Sjkim /* Install new interrupt descriptor with spin lock */ 295207340Sjkim 296207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 297207340Sjkim if (AcpiGbl_GpeXruptListHead) 298207340Sjkim { 299207340Sjkim NextGpeXrupt = AcpiGbl_GpeXruptListHead; 300207340Sjkim while (NextGpeXrupt->Next) 301207340Sjkim { 302207340Sjkim NextGpeXrupt = NextGpeXrupt->Next; 303207340Sjkim } 304207340Sjkim 305207340Sjkim NextGpeXrupt->Next = GpeXrupt; 306207340Sjkim GpeXrupt->Previous = NextGpeXrupt; 307207340Sjkim } 308207340Sjkim else 309207340Sjkim { 310207340Sjkim AcpiGbl_GpeXruptListHead = GpeXrupt; 311207340Sjkim } 312207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 313207340Sjkim 314207340Sjkim /* Install new interrupt handler if not SCI_INT */ 315207340Sjkim 316207340Sjkim if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) 317207340Sjkim { 318207340Sjkim Status = AcpiOsInstallInterruptHandler (InterruptNumber, 319207340Sjkim AcpiEvGpeXruptHandler, GpeXrupt); 320207340Sjkim if (ACPI_FAILURE (Status)) 321207340Sjkim { 322207340Sjkim ACPI_ERROR ((AE_INFO, 323207340Sjkim "Could not install GPE interrupt handler at level 0x%X", 324207340Sjkim InterruptNumber)); 325207340Sjkim return_PTR (NULL); 326207340Sjkim } 327207340Sjkim } 328207340Sjkim 329207340Sjkim return_PTR (GpeXrupt); 330207340Sjkim} 331207340Sjkim 332207340Sjkim 333207340Sjkim/******************************************************************************* 334207340Sjkim * 335207340Sjkim * FUNCTION: AcpiEvDeleteGpeXrupt 336207340Sjkim * 337207340Sjkim * PARAMETERS: GpeXrupt - A GPE interrupt info block 338207340Sjkim * 339207340Sjkim * RETURN: Status 340207340Sjkim * 341207340Sjkim * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated 342207340Sjkim * interrupt handler if not the SCI interrupt. 343207340Sjkim * 344207340Sjkim ******************************************************************************/ 345207340Sjkim 346207340SjkimACPI_STATUS 347207340SjkimAcpiEvDeleteGpeXrupt ( 348207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXrupt) 349207340Sjkim{ 350207340Sjkim ACPI_STATUS Status; 351207340Sjkim ACPI_CPU_FLAGS Flags; 352207340Sjkim 353207340Sjkim 354207340Sjkim ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); 355207340Sjkim 356207340Sjkim 357207340Sjkim /* We never want to remove the SCI interrupt handler */ 358207340Sjkim 359207340Sjkim if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) 360207340Sjkim { 361207340Sjkim GpeXrupt->GpeBlockListHead = NULL; 362207340Sjkim return_ACPI_STATUS (AE_OK); 363207340Sjkim } 364207340Sjkim 365207340Sjkim /* Disable this interrupt */ 366207340Sjkim 367207340Sjkim Status = AcpiOsRemoveInterruptHandler ( 368207340Sjkim GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); 369207340Sjkim if (ACPI_FAILURE (Status)) 370207340Sjkim { 371207340Sjkim return_ACPI_STATUS (Status); 372207340Sjkim } 373207340Sjkim 374207340Sjkim /* Unlink the interrupt block with lock */ 375207340Sjkim 376207340Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 377207340Sjkim if (GpeXrupt->Previous) 378207340Sjkim { 379207340Sjkim GpeXrupt->Previous->Next = GpeXrupt->Next; 380207340Sjkim } 381207340Sjkim else 382207340Sjkim { 383207340Sjkim /* No previous, update list head */ 384207340Sjkim 385207340Sjkim AcpiGbl_GpeXruptListHead = GpeXrupt->Next; 386207340Sjkim } 387207340Sjkim 388207340Sjkim if (GpeXrupt->Next) 389207340Sjkim { 390207340Sjkim GpeXrupt->Next->Previous = GpeXrupt->Previous; 391207340Sjkim } 392207340Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 393207340Sjkim 394207340Sjkim /* Free the block */ 395207340Sjkim 396207340Sjkim ACPI_FREE (GpeXrupt); 397207340Sjkim return_ACPI_STATUS (AE_OK); 398207340Sjkim} 399207340Sjkim 400207340Sjkim 401207340Sjkim/******************************************************************************* 402207340Sjkim * 403207340Sjkim * FUNCTION: AcpiEvDeleteGpeHandlers 404207340Sjkim * 405207340Sjkim * PARAMETERS: GpeXruptInfo - GPE Interrupt info 406207340Sjkim * GpeBlock - Gpe Block info 407207340Sjkim * 408207340Sjkim * RETURN: Status 409207340Sjkim * 410207340Sjkim * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 411207340Sjkim * Used only prior to termination. 412207340Sjkim * 413207340Sjkim ******************************************************************************/ 414207340Sjkim 415207340SjkimACPI_STATUS 416207340SjkimAcpiEvDeleteGpeHandlers ( 417207340Sjkim ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 418207340Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock, 419207340Sjkim void *Context) 420207340Sjkim{ 421207340Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo; 422207340Sjkim UINT32 i; 423207340Sjkim UINT32 j; 424207340Sjkim 425207340Sjkim 426207340Sjkim ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); 427207340Sjkim 428207340Sjkim 429207340Sjkim /* Examine each GPE Register within the block */ 430207340Sjkim 431207340Sjkim for (i = 0; i < GpeBlock->RegisterCount; i++) 432207340Sjkim { 433207340Sjkim /* Now look at the individual GPEs in this byte register */ 434207340Sjkim 435207340Sjkim for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 436207340Sjkim { 437207340Sjkim GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 438207340Sjkim ACPI_GPE_REGISTER_WIDTH) + j]; 439207340Sjkim 440207340Sjkim if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 441207340Sjkim ACPI_GPE_DISPATCH_HANDLER) 442207340Sjkim { 443207340Sjkim ACPI_FREE (GpeEventInfo->Dispatch.Handler); 444207340Sjkim GpeEventInfo->Dispatch.Handler = NULL; 445207340Sjkim GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 446207340Sjkim } 447207340Sjkim } 448207340Sjkim } 449207340Sjkim 450207340Sjkim return_ACPI_STATUS (AE_OK); 451207340Sjkim} 452207340Sjkim 453