1114239Snjl/****************************************************************************** 2114239Snjl * 3114239Snjl * Module Name: evgpe - General Purpose Event handling and dispatch 4114239Snjl * 5114239Snjl *****************************************************************************/ 6114239Snjl 7217365Sjkim/* 8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp. 9114239Snjl * All rights reserved. 10114239Snjl * 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. 25114239Snjl * 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. 29114239Snjl * 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 */ 43114239Snjl 44193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 45193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 46193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 47193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h> 48114239Snjl 49114239Snjl#define _COMPONENT ACPI_EVENTS 50114239Snjl ACPI_MODULE_NAME ("evgpe") 51114239Snjl 52231844Sjkim#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53231844Sjkim 54151937Sjkim/* Local prototypes */ 55114239Snjl 56193267Sjkimstatic void ACPI_SYSTEM_XFACE 57193267SjkimAcpiEvAsynchExecuteGpeMethod ( 58175256Snjl void *Context); 59175256Snjl 60151937Sjkimstatic void ACPI_SYSTEM_XFACE 61193267SjkimAcpiEvAsynchEnableGpe ( 62151937Sjkim void *Context); 63151937Sjkim 64151937Sjkim 65114239Snjl/******************************************************************************* 66114239Snjl * 67209746Sjkim * FUNCTION: AcpiEvUpdateGpeEnableMask 68129684Snjl * 69129684Snjl * PARAMETERS: GpeEventInfo - GPE to update 70129684Snjl * 71129684Snjl * RETURN: Status 72129684Snjl * 73209746Sjkim * DESCRIPTION: Updates GPE register enable mask based upon whether there are 74209746Sjkim * runtime references to this GPE 75129684Snjl * 76129684Snjl ******************************************************************************/ 77129684Snjl 78129684SnjlACPI_STATUS 79209746SjkimAcpiEvUpdateGpeEnableMask ( 80206117Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 81129684Snjl{ 82129684Snjl ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; 83209746Sjkim UINT32 RegisterBit; 84129684Snjl 85129684Snjl 86209746Sjkim ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMask); 87129684Snjl 88129684Snjl 89129684Snjl GpeRegisterInfo = GpeEventInfo->RegisterInfo; 90129684Snjl if (!GpeRegisterInfo) 91129684Snjl { 92129684Snjl return_ACPI_STATUS (AE_NOT_EXIST); 93129684Snjl } 94193267Sjkim 95239340Sjkim RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); 96129684Snjl 97209746Sjkim /* Clear the run bit up front */ 98129684Snjl 99206117Sjkim ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit); 100206117Sjkim 101209746Sjkim /* Set the mask bit only if there are references to this GPE */ 102206117Sjkim 103206117Sjkim if (GpeEventInfo->RuntimeCount) 104129684Snjl { 105209746Sjkim ACPI_SET_BIT (GpeRegisterInfo->EnableForRun, (UINT8) RegisterBit); 106129684Snjl } 107129684Snjl 108129684Snjl return_ACPI_STATUS (AE_OK); 109129684Snjl} 110129684Snjl 111129684Snjl 112129684Snjl/******************************************************************************* 113129684Snjl * 114129684Snjl * FUNCTION: AcpiEvEnableGpe 115129684Snjl * 116129684Snjl * PARAMETERS: GpeEventInfo - GPE to enable 117129684Snjl * 118129684Snjl * RETURN: Status 119129684Snjl * 120209746Sjkim * DESCRIPTION: Clear a GPE of stale events and enable it. 121129684Snjl * 122129684Snjl ******************************************************************************/ 123129684Snjl 124129684SnjlACPI_STATUS 125129684SnjlAcpiEvEnableGpe ( 126206117Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 127129684Snjl{ 128129684Snjl ACPI_STATUS Status; 129129684Snjl 130129684Snjl 131167802Sjkim ACPI_FUNCTION_TRACE (EvEnableGpe); 132129684Snjl 133129684Snjl 134206117Sjkim /* Clear the GPE (of stale events) */ 135129684Snjl 136206117Sjkim Status = AcpiHwClearGpe (GpeEventInfo); 137206117Sjkim if (ACPI_FAILURE (Status)) 138129684Snjl { 139206117Sjkim return_ACPI_STATUS (Status); 140206117Sjkim } 141131440Smarks 142206117Sjkim /* Enable the requested GPE */ 143129684Snjl 144281075Sdim Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE_SAVE); 145206117Sjkim return_ACPI_STATUS (Status); 146129684Snjl} 147129684Snjl 148129684Snjl 149129684Snjl/******************************************************************************* 150129684Snjl * 151216471Sjkim * FUNCTION: AcpiEvAddGpeReference 152216471Sjkim * 153216471Sjkim * PARAMETERS: GpeEventInfo - Add a reference to this GPE 154216471Sjkim * 155216471Sjkim * RETURN: Status 156216471Sjkim * 157216471Sjkim * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is 158216471Sjkim * hardware-enabled. 159216471Sjkim * 160216471Sjkim ******************************************************************************/ 161216471Sjkim 162216471SjkimACPI_STATUS 163216471SjkimAcpiEvAddGpeReference ( 164216471Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 165216471Sjkim{ 166216471Sjkim ACPI_STATUS Status = AE_OK; 167216471Sjkim 168216471Sjkim 169216471Sjkim ACPI_FUNCTION_TRACE (EvAddGpeReference); 170216471Sjkim 171216471Sjkim 172216471Sjkim if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX) 173216471Sjkim { 174216471Sjkim return_ACPI_STATUS (AE_LIMIT); 175216471Sjkim } 176216471Sjkim 177216471Sjkim GpeEventInfo->RuntimeCount++; 178216471Sjkim if (GpeEventInfo->RuntimeCount == 1) 179216471Sjkim { 180216471Sjkim /* Enable on first reference */ 181216471Sjkim 182216471Sjkim Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); 183216471Sjkim if (ACPI_SUCCESS (Status)) 184216471Sjkim { 185216471Sjkim Status = AcpiEvEnableGpe (GpeEventInfo); 186216471Sjkim } 187216471Sjkim 188216471Sjkim if (ACPI_FAILURE (Status)) 189216471Sjkim { 190216471Sjkim GpeEventInfo->RuntimeCount--; 191216471Sjkim } 192216471Sjkim } 193216471Sjkim 194216471Sjkim return_ACPI_STATUS (Status); 195216471Sjkim} 196216471Sjkim 197216471Sjkim 198216471Sjkim/******************************************************************************* 199216471Sjkim * 200216471Sjkim * FUNCTION: AcpiEvRemoveGpeReference 201216471Sjkim * 202216471Sjkim * PARAMETERS: GpeEventInfo - Remove a reference to this GPE 203216471Sjkim * 204216471Sjkim * RETURN: Status 205216471Sjkim * 206216471Sjkim * DESCRIPTION: Remove a reference to a GPE. When the last reference is 207216471Sjkim * removed, the GPE is hardware-disabled. 208216471Sjkim * 209216471Sjkim ******************************************************************************/ 210216471Sjkim 211216471SjkimACPI_STATUS 212216471SjkimAcpiEvRemoveGpeReference ( 213216471Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 214216471Sjkim{ 215216471Sjkim ACPI_STATUS Status = AE_OK; 216216471Sjkim 217216471Sjkim 218216471Sjkim ACPI_FUNCTION_TRACE (EvRemoveGpeReference); 219216471Sjkim 220216471Sjkim 221216471Sjkim if (!GpeEventInfo->RuntimeCount) 222216471Sjkim { 223216471Sjkim return_ACPI_STATUS (AE_LIMIT); 224216471Sjkim } 225216471Sjkim 226216471Sjkim GpeEventInfo->RuntimeCount--; 227216471Sjkim if (!GpeEventInfo->RuntimeCount) 228216471Sjkim { 229216471Sjkim /* Disable on last reference */ 230216471Sjkim 231216471Sjkim Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); 232216471Sjkim if (ACPI_SUCCESS (Status)) 233216471Sjkim { 234281075Sdim Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE_SAVE); 235216471Sjkim } 236216471Sjkim 237216471Sjkim if (ACPI_FAILURE (Status)) 238216471Sjkim { 239216471Sjkim GpeEventInfo->RuntimeCount++; 240216471Sjkim } 241216471Sjkim } 242216471Sjkim 243216471Sjkim return_ACPI_STATUS (Status); 244216471Sjkim} 245216471Sjkim 246216471Sjkim 247216471Sjkim/******************************************************************************* 248216471Sjkim * 249206117Sjkim * FUNCTION: AcpiEvLowGetGpeInfo 250206117Sjkim * 251206117Sjkim * PARAMETERS: GpeNumber - Raw GPE number 252206117Sjkim * GpeBlock - A GPE info block 253206117Sjkim * 254206117Sjkim * RETURN: A GPE EventInfo struct. NULL if not a valid GPE (The GpeNumber 255206117Sjkim * is not within the specified GPE block) 256206117Sjkim * 257206117Sjkim * DESCRIPTION: Returns the EventInfo struct associated with this GPE. This is 258206117Sjkim * the low-level implementation of EvGetGpeEventInfo. 259206117Sjkim * 260206117Sjkim ******************************************************************************/ 261206117Sjkim 262206117SjkimACPI_GPE_EVENT_INFO * 263206117SjkimAcpiEvLowGetGpeInfo ( 264206117Sjkim UINT32 GpeNumber, 265206117Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock) 266206117Sjkim{ 267206117Sjkim UINT32 GpeIndex; 268206117Sjkim 269206117Sjkim 270206117Sjkim /* 271206117Sjkim * Validate that the GpeNumber is within the specified GpeBlock. 272206117Sjkim * (Two steps) 273206117Sjkim */ 274206117Sjkim if (!GpeBlock || 275206117Sjkim (GpeNumber < GpeBlock->BlockBaseNumber)) 276206117Sjkim { 277206117Sjkim return (NULL); 278206117Sjkim } 279206117Sjkim 280206117Sjkim GpeIndex = GpeNumber - GpeBlock->BlockBaseNumber; 281206117Sjkim if (GpeIndex >= GpeBlock->GpeCount) 282206117Sjkim { 283206117Sjkim return (NULL); 284206117Sjkim } 285206117Sjkim 286206117Sjkim return (&GpeBlock->EventInfo[GpeIndex]); 287206117Sjkim} 288206117Sjkim 289206117Sjkim 290206117Sjkim/******************************************************************************* 291206117Sjkim * 292114239Snjl * FUNCTION: AcpiEvGetGpeEventInfo 293114239Snjl * 294193267Sjkim * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 295117521Snjl * GpeNumber - Raw GPE number 296114239Snjl * 297193267Sjkim * RETURN: A GPE EventInfo struct. NULL if not a valid GPE 298114239Snjl * 299117521Snjl * DESCRIPTION: Returns the EventInfo struct associated with this GPE. 300117521Snjl * Validates the GpeBlock and the GpeNumber 301114239Snjl * 302117521Snjl * Should be called only when the GPE lists are semaphore locked 303117521Snjl * and not subject to change. 304114239Snjl * 305114239Snjl ******************************************************************************/ 306114239Snjl 307114239SnjlACPI_GPE_EVENT_INFO * 308114239SnjlAcpiEvGetGpeEventInfo ( 309117521Snjl ACPI_HANDLE GpeDevice, 310114239Snjl UINT32 GpeNumber) 311114239Snjl{ 312117521Snjl ACPI_OPERAND_OBJECT *ObjDesc; 313206117Sjkim ACPI_GPE_EVENT_INFO *GpeInfo; 314193267Sjkim UINT32 i; 315114239Snjl 316114239Snjl 317117521Snjl ACPI_FUNCTION_ENTRY (); 318114239Snjl 319117521Snjl 320207344Sjkim /* A NULL GpeDevice means use the FADT-defined GPE block(s) */ 321117521Snjl 322117521Snjl if (!GpeDevice) 323114239Snjl { 324117521Snjl /* Examine GPE Block 0 and 1 (These blocks are permanent) */ 325117521Snjl 326117521Snjl for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) 327117521Snjl { 328206117Sjkim GpeInfo = AcpiEvLowGetGpeInfo (GpeNumber, 329206117Sjkim AcpiGbl_GpeFadtBlocks[i]); 330206117Sjkim if (GpeInfo) 331117521Snjl { 332206117Sjkim return (GpeInfo); 333117521Snjl } 334117521Snjl } 335117521Snjl 336117521Snjl /* The GpeNumber was not in the range of either FADT GPE block */ 337117521Snjl 338114239Snjl return (NULL); 339114239Snjl } 340114239Snjl 341128212Snjl /* A Non-NULL GpeDevice means this is a GPE Block Device */ 342128212Snjl 343117521Snjl ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice); 344117521Snjl if (!ObjDesc || 345117521Snjl !ObjDesc->Device.GpeBlock) 346114239Snjl { 347117521Snjl return (NULL); 348114239Snjl } 349114239Snjl 350206117Sjkim return (AcpiEvLowGetGpeInfo (GpeNumber, ObjDesc->Device.GpeBlock)); 351114239Snjl} 352114239Snjl 353117521Snjl 354114239Snjl/******************************************************************************* 355114239Snjl * 356114239Snjl * FUNCTION: AcpiEvGpeDetect 357114239Snjl * 358117521Snjl * PARAMETERS: GpeXruptList - Interrupt block for this interrupt. 359117521Snjl * Can have multiple GPE blocks attached. 360114239Snjl * 361114239Snjl * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED 362114239Snjl * 363193267Sjkim * DESCRIPTION: Detect if any GP events have occurred. This function is 364114239Snjl * executed at interrupt level. 365114239Snjl * 366114239Snjl ******************************************************************************/ 367114239Snjl 368114239SnjlUINT32 369117521SnjlAcpiEvGpeDetect ( 370117521Snjl ACPI_GPE_XRUPT_INFO *GpeXruptList) 371114239Snjl{ 372151937Sjkim ACPI_STATUS Status; 373151937Sjkim ACPI_GPE_BLOCK_INFO *GpeBlock; 374281075Sdim ACPI_NAMESPACE_NODE *GpeDevice; 375151937Sjkim ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; 376281075Sdim ACPI_GPE_EVENT_INFO *GpeEventInfo; 377281075Sdim UINT32 GpeNumber; 378281075Sdim ACPI_GPE_HANDLER_INFO *GpeHandlerInfo; 379114239Snjl UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; 380114239Snjl UINT8 EnabledStatusByte; 381129684Snjl UINT32 StatusReg; 382129684Snjl UINT32 EnableReg; 383167802Sjkim ACPI_CPU_FLAGS Flags; 384193267Sjkim UINT32 i; 385193267Sjkim UINT32 j; 386114239Snjl 387114239Snjl 388167802Sjkim ACPI_FUNCTION_NAME (EvGpeDetect); 389114239Snjl 390127175Snjl /* Check for the case where there are no GPEs */ 391114239Snjl 392127175Snjl if (!GpeXruptList) 393127175Snjl { 394127175Snjl return (IntStatus); 395127175Snjl } 396127175Snjl 397167802Sjkim /* 398167802Sjkim * We need to obtain the GPE lock for both the data structs and registers 399193267Sjkim * Note: Not necessary to obtain the hardware lock, since the GPE 400193267Sjkim * registers are owned by the GpeLock. 401167802Sjkim */ 402167802Sjkim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 403167802Sjkim 404114239Snjl /* Examine all GPE blocks attached to this interrupt level */ 405114239Snjl 406117521Snjl GpeBlock = GpeXruptList->GpeBlockListHead; 407114239Snjl while (GpeBlock) 408114239Snjl { 409281075Sdim GpeDevice = GpeBlock->Node; 410281075Sdim 411114239Snjl /* 412193267Sjkim * Read all of the 8-bit GPE status and enable registers in this GPE 413193267Sjkim * block, saving all of them. Find all currently active GP events. 414114239Snjl */ 415114239Snjl for (i = 0; i < GpeBlock->RegisterCount; i++) 416114239Snjl { 417114239Snjl /* Get the next status/enable pair */ 418114239Snjl 419114239Snjl GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; 420114239Snjl 421218590Sjkim /* 422218590Sjkim * Optimization: If there are no GPEs enabled within this 423218590Sjkim * register, we can safely ignore the entire register. 424218590Sjkim */ 425218590Sjkim if (!(GpeRegisterInfo->EnableForRun | 426218590Sjkim GpeRegisterInfo->EnableForWake)) 427218590Sjkim { 428239340Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, 429281075Sdim "Ignore disabled registers for GPE %02X-%02X: " 430239340Sjkim "RunEnable=%02X, WakeEnable=%02X\n", 431239340Sjkim GpeRegisterInfo->BaseGpeNumber, 432239340Sjkim GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), 433239340Sjkim GpeRegisterInfo->EnableForRun, 434239340Sjkim GpeRegisterInfo->EnableForWake)); 435218590Sjkim continue; 436218590Sjkim } 437218590Sjkim 438117521Snjl /* Read the Status Register */ 439117521Snjl 440197104Sjkim Status = AcpiHwRead (&StatusReg, &GpeRegisterInfo->StatusAddress); 441114239Snjl if (ACPI_FAILURE (Status)) 442114239Snjl { 443117521Snjl goto UnlockAndExit; 444114239Snjl } 445114239Snjl 446117521Snjl /* Read the Enable Register */ 447117521Snjl 448197104Sjkim Status = AcpiHwRead (&EnableReg, &GpeRegisterInfo->EnableAddress); 449114239Snjl if (ACPI_FAILURE (Status)) 450114239Snjl { 451117521Snjl goto UnlockAndExit; 452114239Snjl } 453114239Snjl 454114239Snjl ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, 455281075Sdim "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " 456239340Sjkim "RunEnable=%02X, WakeEnable=%02X\n", 457239340Sjkim GpeRegisterInfo->BaseGpeNumber, 458239340Sjkim GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), 459239340Sjkim StatusReg, EnableReg, 460239340Sjkim GpeRegisterInfo->EnableForRun, 461239340Sjkim GpeRegisterInfo->EnableForWake)); 462114239Snjl 463151937Sjkim /* Check if there is anything active at all in this register */ 464114239Snjl 465129684Snjl EnabledStatusByte = (UINT8) (StatusReg & EnableReg); 466114239Snjl if (!EnabledStatusByte) 467114239Snjl { 468114239Snjl /* No active GPEs in this register, move on */ 469114239Snjl 470114239Snjl continue; 471114239Snjl } 472114239Snjl 473114239Snjl /* Now look at the individual GPEs in this byte register */ 474114239Snjl 475123315Snjl for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 476114239Snjl { 477114239Snjl /* Examine one GPE bit */ 478114239Snjl 479281075Sdim GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 480281075Sdim ACPI_GPE_REGISTER_WIDTH) + j]; 481281075Sdim GpeNumber = j + GpeRegisterInfo->BaseGpeNumber; 482281075Sdim 483167802Sjkim if (EnabledStatusByte & (1 << j)) 484114239Snjl { 485281075Sdim /* Invoke global event handler if present */ 486281075Sdim 487281075Sdim AcpiGpeCount++; 488281075Sdim if (AcpiGbl_GlobalEventHandler) 489281075Sdim { 490281075Sdim AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_GPE, 491281075Sdim GpeDevice, GpeNumber, 492281075Sdim AcpiGbl_GlobalEventHandlerContext); 493281075Sdim } 494281075Sdim 495281075Sdim /* Found an active GPE */ 496281075Sdim 497281075Sdim if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == 498281075Sdim ACPI_GPE_DISPATCH_RAW_HANDLER) 499281075Sdim { 500281075Sdim /* Dispatch the event to a raw handler */ 501281075Sdim 502281075Sdim GpeHandlerInfo = GpeEventInfo->Dispatch.Handler; 503281075Sdim 504281075Sdim /* 505281075Sdim * There is no protection around the namespace node 506281075Sdim * and the GPE handler to ensure a safe destruction 507281075Sdim * because: 508281075Sdim * 1. The namespace node is expected to always 509281075Sdim * exist after loading a table. 510281075Sdim * 2. The GPE handler is expected to be flushed by 511281075Sdim * AcpiOsWaitEventsComplete() before the 512281075Sdim * destruction. 513281075Sdim */ 514281075Sdim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 515281075Sdim IntStatus |= GpeHandlerInfo->Address ( 516281075Sdim GpeDevice, GpeNumber, GpeHandlerInfo->Context); 517281075Sdim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 518281075Sdim } 519281075Sdim else 520281075Sdim { 521281075Sdim /* 522281075Sdim * Dispatch the event to a standard handler or 523281075Sdim * method. 524281075Sdim */ 525281075Sdim IntStatus |= AcpiEvGpeDispatch (GpeDevice, 526281075Sdim GpeEventInfo, GpeNumber); 527281075Sdim } 528114239Snjl } 529114239Snjl } 530114239Snjl } 531114239Snjl 532114239Snjl GpeBlock = GpeBlock->Next; 533114239Snjl } 534114239Snjl 535117521SnjlUnlockAndExit: 536117521Snjl 537151937Sjkim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 538114239Snjl return (IntStatus); 539114239Snjl} 540114239Snjl 541114239Snjl 542114239Snjl/******************************************************************************* 543114239Snjl * 544114239Snjl * FUNCTION: AcpiEvAsynchExecuteGpeMethod 545114239Snjl * 546117521Snjl * PARAMETERS: Context (GpeEventInfo) - Info for this GPE 547114239Snjl * 548114239Snjl * RETURN: None 549114239Snjl * 550167802Sjkim * DESCRIPTION: Perform the actual execution of a GPE control method. This 551167802Sjkim * function is called from an invocation of AcpiOsExecute and 552167802Sjkim * therefore does NOT execute at interrupt level - so that 553114239Snjl * the control method itself is not executed in the context of 554117521Snjl * an interrupt handler. 555114239Snjl * 556114239Snjl ******************************************************************************/ 557114239Snjl 558114239Snjlstatic void ACPI_SYSTEM_XFACE 559114239SnjlAcpiEvAsynchExecuteGpeMethod ( 560114239Snjl void *Context) 561114239Snjl{ 562193267Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; 563281075Sdim ACPI_STATUS Status = AE_OK; 564167802Sjkim ACPI_EVALUATE_INFO *Info; 565237412Sjkim ACPI_GPE_NOTIFY_INFO *Notify; 566114239Snjl 567114239Snjl 568167802Sjkim ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod); 569114239Snjl 570114239Snjl 571216471Sjkim /* Do the correct dispatch - normal method or implicit notify */ 572216471Sjkim 573281075Sdim switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) 574114239Snjl { 575216471Sjkim case ACPI_GPE_DISPATCH_NOTIFY: 576216471Sjkim /* 577216471Sjkim * Implicit notify. 578216471Sjkim * Dispatch a DEVICE_WAKE notify to the appropriate handler. 579216471Sjkim * NOTE: the request is queued for execution after this method 580216471Sjkim * completes. The notify handlers are NOT invoked synchronously 581216471Sjkim * from this thread -- because handlers may in turn run other 582216471Sjkim * control methods. 583237412Sjkim * 584237412Sjkim * June 2012: Expand implicit notify mechanism to support 585237412Sjkim * notifies on multiple device objects. 586216471Sjkim */ 587281075Sdim Notify = GpeEventInfo->Dispatch.NotifyList; 588237412Sjkim while (ACPI_SUCCESS (Status) && Notify) 589237412Sjkim { 590237412Sjkim Status = AcpiEvQueueNotifyRequest (Notify->DeviceNode, 591237412Sjkim ACPI_NOTIFY_DEVICE_WAKE); 592237412Sjkim 593237412Sjkim Notify = Notify->Next; 594237412Sjkim } 595216471Sjkim break; 596216471Sjkim 597216471Sjkim case ACPI_GPE_DISPATCH_METHOD: 598216471Sjkim 599167802Sjkim /* Allocate the evaluation information block */ 600129684Snjl 601167802Sjkim Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 602167802Sjkim if (!Info) 603167802Sjkim { 604167802Sjkim Status = AE_NO_MEMORY; 605167802Sjkim } 606167802Sjkim else 607167802Sjkim { 608167802Sjkim /* 609216471Sjkim * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the 610216471Sjkim * _Lxx/_Exx control method that corresponds to this GPE 611167802Sjkim */ 612281075Sdim Info->PrefixNode = GpeEventInfo->Dispatch.MethodNode; 613167802Sjkim Info->Flags = ACPI_IGNORE_RETURN_VALUE; 614167802Sjkim 615167802Sjkim Status = AcpiNsEvaluate (Info); 616167802Sjkim ACPI_FREE (Info); 617167802Sjkim } 618167802Sjkim 619114239Snjl if (ACPI_FAILURE (Status)) 620114239Snjl { 621167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, 622167802Sjkim "while evaluating GPE method [%4.4s]", 623281075Sdim AcpiUtGetNodeName (GpeEventInfo->Dispatch.MethodNode))); 624114239Snjl } 625216471Sjkim break; 626216471Sjkim 627216471Sjkim default: 628250838Sjkim 629281075Sdim goto ErrorExit; /* Should never happen */ 630114239Snjl } 631114239Snjl 632175256Snjl /* Defer enabling of GPE until all notify handlers are done */ 633193267Sjkim 634193267Sjkim Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, 635281075Sdim AcpiEvAsynchEnableGpe, GpeEventInfo); 636281075Sdim if (ACPI_SUCCESS (Status)) 637193267Sjkim { 638281075Sdim return_VOID; 639193267Sjkim } 640281075Sdim 641281075SdimErrorExit: 642281075Sdim AcpiEvAsynchEnableGpe (GpeEventInfo); 643175256Snjl return_VOID; 644175256Snjl} 645175256Snjl 646193267Sjkim 647193267Sjkim/******************************************************************************* 648193267Sjkim * 649193267Sjkim * FUNCTION: AcpiEvAsynchEnableGpe 650193267Sjkim * 651193267Sjkim * PARAMETERS: Context (GpeEventInfo) - Info for this GPE 652216471Sjkim * Callback from AcpiOsExecute 653193267Sjkim * 654193267Sjkim * RETURN: None 655193267Sjkim * 656193267Sjkim * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to 657193267Sjkim * complete (i.e., finish execution of Notify) 658193267Sjkim * 659193267Sjkim ******************************************************************************/ 660193267Sjkim 661193267Sjkimstatic void ACPI_SYSTEM_XFACE 662175256SnjlAcpiEvAsynchEnableGpe ( 663175256Snjl void *Context) 664175256Snjl{ 665193267Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; 666281075Sdim ACPI_CPU_FLAGS Flags; 667216471Sjkim 668216471Sjkim 669281075Sdim Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 670216471Sjkim (void) AcpiEvFinishGpe (GpeEventInfo); 671281075Sdim AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 672216471Sjkim 673216471Sjkim return; 674216471Sjkim} 675216471Sjkim 676216471Sjkim 677216471Sjkim/******************************************************************************* 678216471Sjkim * 679216471Sjkim * FUNCTION: AcpiEvFinishGpe 680216471Sjkim * 681216471Sjkim * PARAMETERS: GpeEventInfo - Info for this GPE 682216471Sjkim * 683216471Sjkim * RETURN: Status 684216471Sjkim * 685216471Sjkim * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution 686216471Sjkim * of a GPE method or a synchronous or asynchronous GPE handler. 687216471Sjkim * 688216471Sjkim ******************************************************************************/ 689216471Sjkim 690216471SjkimACPI_STATUS 691216471SjkimAcpiEvFinishGpe ( 692216471Sjkim ACPI_GPE_EVENT_INFO *GpeEventInfo) 693216471Sjkim{ 694175256Snjl ACPI_STATUS Status; 695175256Snjl 696193267Sjkim 697175256Snjl if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == 698151937Sjkim ACPI_GPE_LEVEL_TRIGGERED) 699114239Snjl { 700114239Snjl /* 701216471Sjkim * GPE is level-triggered, we clear the GPE status bit after 702216471Sjkim * handling the event. 703114239Snjl */ 704175256Snjl Status = AcpiHwClearGpe (GpeEventInfo); 705114239Snjl if (ACPI_FAILURE (Status)) 706114239Snjl { 707216471Sjkim return (Status); 708114239Snjl } 709114239Snjl } 710114239Snjl 711209746Sjkim /* 712216471Sjkim * Enable this GPE, conditionally. This means that the GPE will 713281075Sdim * only be physically enabled if the EnableMask bit is set 714216471Sjkim * in the EventInfo. 715209746Sjkim */ 716209746Sjkim (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); 717216471Sjkim return (AE_OK); 718114239Snjl} 719114239Snjl 720114239Snjl 721114239Snjl/******************************************************************************* 722114239Snjl * 723114239Snjl * FUNCTION: AcpiEvGpeDispatch 724114239Snjl * 725216471Sjkim * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 726216471Sjkim * GpeEventInfo - Info for this GPE 727216471Sjkim * GpeNumber - Number relative to the parent GPE block 728114239Snjl * 729114239Snjl * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED 730114239Snjl * 731114239Snjl * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) 732117521Snjl * or method (e.g. _Lxx/_Exx) handler. 733114239Snjl * 734117521Snjl * This function executes at interrupt level. 735117521Snjl * 736114239Snjl ******************************************************************************/ 737114239Snjl 738114239SnjlUINT32 739114239SnjlAcpiEvGpeDispatch ( 740216471Sjkim ACPI_NAMESPACE_NODE *GpeDevice, 741117521Snjl ACPI_GPE_EVENT_INFO *GpeEventInfo, 742117521Snjl UINT32 GpeNumber) 743114239Snjl{ 744114239Snjl ACPI_STATUS Status; 745216471Sjkim UINT32 ReturnValue; 746114239Snjl 747114239Snjl 748167802Sjkim ACPI_FUNCTION_TRACE (EvGpeDispatch); 749114239Snjl 750114239Snjl 751281075Sdim /* 752281075Sdim * Always disable the GPE so that it does not keep firing before 753281075Sdim * any asynchronous activity completes (either from the execution 754281075Sdim * of a GPE method or an asynchronous GPE handler.) 755281075Sdim * 756281075Sdim * If there is no handler or method to run, just disable the 757281075Sdim * GPE and leave it disabled permanently to prevent further such 758281075Sdim * pointless events from firing. 759281075Sdim */ 760281075Sdim Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); 761281075Sdim if (ACPI_FAILURE (Status)) 762216471Sjkim { 763281075Sdim ACPI_EXCEPTION ((AE_INFO, Status, 764281075Sdim "Unable to disable GPE %02X", GpeNumber)); 765281075Sdim return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); 766216471Sjkim } 767167802Sjkim 768114239Snjl /* 769193267Sjkim * If edge-triggered, clear the GPE status bit now. Note that 770114239Snjl * level-triggered events are cleared after the GPE is serviced. 771114239Snjl */ 772151937Sjkim if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == 773151937Sjkim ACPI_GPE_EDGE_TRIGGERED) 774114239Snjl { 775114239Snjl Status = AcpiHwClearGpe (GpeEventInfo); 776114239Snjl if (ACPI_FAILURE (Status)) 777114239Snjl { 778167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, 779281075Sdim "Unable to clear GPE %02X", GpeNumber)); 780281075Sdim (void) AcpiHwLowSetGpe (GpeEventInfo, 781281075Sdim ACPI_GPE_CONDITIONAL_ENABLE); 782246849Sjkim return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); 783114239Snjl } 784114239Snjl } 785114239Snjl 786114239Snjl /* 787216471Sjkim * Dispatch the GPE to either an installed handler or the control 788216471Sjkim * method associated with this GPE (_Lxx or _Exx). If a handler 789216471Sjkim * exists, we invoke it and do not attempt to run the method. 790216471Sjkim * If there is neither a handler nor a method, leave the GPE 791216471Sjkim * disabled. 792216471Sjkim */ 793281075Sdim switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) 794114239Snjl { 795129684Snjl case ACPI_GPE_DISPATCH_HANDLER: 796129684Snjl 797216471Sjkim /* Invoke the installed handler (at interrupt level) */ 798123315Snjl 799216471Sjkim ReturnValue = GpeEventInfo->Dispatch.Handler->Address ( 800216471Sjkim GpeDevice, GpeNumber, 801216471Sjkim GpeEventInfo->Dispatch.Handler->Context); 802123315Snjl 803216471Sjkim /* If requested, clear (if level-triggered) and reenable the GPE */ 804216471Sjkim 805216471Sjkim if (ReturnValue & ACPI_REENABLE_GPE) 806123315Snjl { 807216471Sjkim (void) AcpiEvFinishGpe (GpeEventInfo); 808123315Snjl } 809129684Snjl break; 810129684Snjl 811129684Snjl case ACPI_GPE_DISPATCH_METHOD: 812216471Sjkim case ACPI_GPE_DISPATCH_NOTIFY: 813114239Snjl /* 814123315Snjl * Execute the method associated with the GPE 815123315Snjl * NOTE: Level-triggered GPEs are cleared after the method completes. 816123315Snjl */ 817167802Sjkim Status = AcpiOsExecute (OSL_GPE_HANDLER, 818151937Sjkim AcpiEvAsynchExecuteGpeMethod, GpeEventInfo); 819151937Sjkim if (ACPI_FAILURE (Status)) 820114239Snjl { 821167802Sjkim ACPI_EXCEPTION ((AE_INFO, Status, 822281075Sdim "Unable to queue handler for GPE %02X - event disabled", 823167802Sjkim GpeNumber)); 824114239Snjl } 825129684Snjl break; 826129684Snjl 827129684Snjl default: 828206117Sjkim /* 829206117Sjkim * No handler or method to run! 830206117Sjkim * 03/2010: This case should no longer be possible. We will not allow 831206117Sjkim * a GPE to be enabled if it has no handler or method. 832206117Sjkim */ 833167802Sjkim ACPI_ERROR ((AE_INFO, 834281075Sdim "No handler or method for GPE %02X, disabling event", 835114239Snjl GpeNumber)); 836129684Snjl break; 837114239Snjl } 838114239Snjl 839246849Sjkim return_UINT32 (ACPI_INTERRUPT_HANDLED); 840114239Snjl} 841114239Snjl 842231844Sjkim#endif /* !ACPI_REDUCED_HARDWARE */ 843