evgpe.c revision 245582
1251881Speter/******************************************************************************
2251881Speter *
3251881Speter * Module Name: evgpe - General Purpose Event handling and dispatch
4251881Speter *
5251881Speter *****************************************************************************/
6251881Speter
7251881Speter/*
8251881Speter * Copyright (C) 2000 - 2013, Intel Corp.
9251881Speter * All rights reserved.
10251881Speter *
11251881Speter * Redistribution and use in source and binary forms, with or without
12251881Speter * modification, are permitted provided that the following conditions
13251881Speter * are met:
14251881Speter * 1. Redistributions of source code must retain the above copyright
15251881Speter *    notice, this list of conditions, and the following disclaimer,
16251881Speter *    without modification.
17251881Speter * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18251881Speter *    substantially similar to the "NO WARRANTY" disclaimer below
19251881Speter *    ("Disclaimer") and any redistribution must be conditioned upon
20251881Speter *    including a substantially similar Disclaimer requirement for further
21251881Speter *    binary redistribution.
22251881Speter * 3. Neither the names of the above-listed copyright holders nor the names
23251881Speter *    of any contributors may be used to endorse or promote products derived
24251881Speter *    from this software without specific prior written permission.
25251881Speter *
26251881Speter * Alternatively, this software may be distributed under the terms of the
27251881Speter * GNU General Public License ("GPL") version 2 as published by the Free
28251881Speter * Software Foundation.
29251881Speter *
30251881Speter * NO WARRANTY
31251881Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32251881Speter * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33251881Speter * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34251881Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35251881Speter * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39251881Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40251881Speter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41251881Speter * POSSIBILITY OF SUCH DAMAGES.
42251881Speter */
43251881Speter
44251881Speter#include <contrib/dev/acpica/include/acpi.h>
45251881Speter#include <contrib/dev/acpica/include/accommon.h>
46251881Speter#include <contrib/dev/acpica/include/acevents.h>
47251881Speter#include <contrib/dev/acpica/include/acnamesp.h>
48251881Speter
49251881Speter#define _COMPONENT          ACPI_EVENTS
50251881Speter        ACPI_MODULE_NAME    ("evgpe")
51251881Speter
52251881Speter#if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53251881Speter
54251881Speter/* Local prototypes */
55251881Speter
56251881Speterstatic void ACPI_SYSTEM_XFACE
57251881SpeterAcpiEvAsynchExecuteGpeMethod (
58251881Speter    void                    *Context);
59251881Speter
60251881Speterstatic void ACPI_SYSTEM_XFACE
61251881SpeterAcpiEvAsynchEnableGpe (
62251881Speter    void                    *Context);
63251881Speter
64251881Speter
65251881Speter/*******************************************************************************
66251881Speter *
67251881Speter * FUNCTION:    AcpiEvUpdateGpeEnableMask
68251881Speter *
69251881Speter * PARAMETERS:  GpeEventInfo            - GPE to update
70251881Speter *
71251881Speter * RETURN:      Status
72251881Speter *
73251881Speter * DESCRIPTION: Updates GPE register enable mask based upon whether there are
74251881Speter *              runtime references to this GPE
75251881Speter *
76251881Speter ******************************************************************************/
77251881Speter
78251881SpeterACPI_STATUS
79251881SpeterAcpiEvUpdateGpeEnableMask (
80251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
81251881Speter{
82251881Speter    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
83251881Speter    UINT32                  RegisterBit;
84251881Speter
85251881Speter
86251881Speter    ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMask);
87251881Speter
88251881Speter
89251881Speter    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
90251881Speter    if (!GpeRegisterInfo)
91251881Speter    {
92251881Speter        return_ACPI_STATUS (AE_NOT_EXIST);
93251881Speter    }
94251881Speter
95251881Speter    RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
96251881Speter
97251881Speter    /* Clear the run bit up front */
98251881Speter
99251881Speter    ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
100251881Speter
101251881Speter    /* Set the mask bit only if there are references to this GPE */
102251881Speter
103251881Speter    if (GpeEventInfo->RuntimeCount)
104251881Speter    {
105251881Speter        ACPI_SET_BIT (GpeRegisterInfo->EnableForRun, (UINT8) RegisterBit);
106251881Speter    }
107251881Speter
108251881Speter    return_ACPI_STATUS (AE_OK);
109251881Speter}
110251881Speter
111251881Speter
112251881Speter/*******************************************************************************
113251881Speter *
114251881Speter * FUNCTION:    AcpiEvEnableGpe
115251881Speter *
116251881Speter * PARAMETERS:  GpeEventInfo            - GPE to enable
117251881Speter *
118251881Speter * RETURN:      Status
119251881Speter *
120251881Speter * DESCRIPTION: Clear a GPE of stale events and enable it.
121251881Speter *
122251881Speter ******************************************************************************/
123251881Speter
124251881SpeterACPI_STATUS
125251881SpeterAcpiEvEnableGpe (
126251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
127251881Speter{
128251881Speter    ACPI_STATUS             Status;
129251881Speter
130251881Speter
131251881Speter    ACPI_FUNCTION_TRACE (EvEnableGpe);
132251881Speter
133251881Speter
134251881Speter    /*
135251881Speter     * We will only allow a GPE to be enabled if it has either an associated
136251881Speter     * method (_Lxx/_Exx) or a handler, or is using the implicit notify
137251881Speter     * feature. Otherwise, the GPE will be immediately disabled by
138251881Speter     * AcpiEvGpeDispatch the first time it fires.
139251881Speter     */
140251881Speter    if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
141251881Speter        ACPI_GPE_DISPATCH_NONE)
142251881Speter    {
143251881Speter        return_ACPI_STATUS (AE_NO_HANDLER);
144251881Speter    }
145251881Speter
146251881Speter    /* Clear the GPE (of stale events) */
147251881Speter
148251881Speter    Status = AcpiHwClearGpe (GpeEventInfo);
149251881Speter    if (ACPI_FAILURE (Status))
150251881Speter    {
151251881Speter        return_ACPI_STATUS (Status);
152251881Speter    }
153251881Speter
154251881Speter    /* Enable the requested GPE */
155251881Speter
156251881Speter    Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE);
157251881Speter    return_ACPI_STATUS (Status);
158251881Speter}
159251881Speter
160251881Speter
161251881Speter/*******************************************************************************
162251881Speter *
163251881Speter * FUNCTION:    AcpiEvAddGpeReference
164251881Speter *
165251881Speter * PARAMETERS:  GpeEventInfo            - Add a reference to this GPE
166251881Speter *
167251881Speter * RETURN:      Status
168251881Speter *
169251881Speter * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
170251881Speter *              hardware-enabled.
171251881Speter *
172251881Speter ******************************************************************************/
173251881Speter
174251881SpeterACPI_STATUS
175251881SpeterAcpiEvAddGpeReference (
176251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
177251881Speter{
178251881Speter    ACPI_STATUS             Status = AE_OK;
179251881Speter
180251881Speter
181251881Speter    ACPI_FUNCTION_TRACE (EvAddGpeReference);
182251881Speter
183251881Speter
184251881Speter    if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX)
185251881Speter    {
186251881Speter        return_ACPI_STATUS (AE_LIMIT);
187251881Speter    }
188251881Speter
189251881Speter    GpeEventInfo->RuntimeCount++;
190251881Speter    if (GpeEventInfo->RuntimeCount == 1)
191251881Speter    {
192251881Speter        /* Enable on first reference */
193251881Speter
194251881Speter        Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo);
195251881Speter        if (ACPI_SUCCESS (Status))
196251881Speter        {
197251881Speter            Status = AcpiEvEnableGpe (GpeEventInfo);
198251881Speter        }
199251881Speter
200251881Speter        if (ACPI_FAILURE (Status))
201251881Speter        {
202251881Speter            GpeEventInfo->RuntimeCount--;
203251881Speter        }
204251881Speter    }
205251881Speter
206251881Speter    return_ACPI_STATUS (Status);
207251881Speter}
208251881Speter
209251881Speter
210251881Speter/*******************************************************************************
211251881Speter *
212251881Speter * FUNCTION:    AcpiEvRemoveGpeReference
213251881Speter *
214251881Speter * PARAMETERS:  GpeEventInfo            - Remove a reference to this GPE
215251881Speter *
216251881Speter * RETURN:      Status
217251881Speter *
218251881Speter * DESCRIPTION: Remove a reference to a GPE. When the last reference is
219251881Speter *              removed, the GPE is hardware-disabled.
220251881Speter *
221251881Speter ******************************************************************************/
222251881Speter
223251881SpeterACPI_STATUS
224251881SpeterAcpiEvRemoveGpeReference (
225251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
226251881Speter{
227251881Speter    ACPI_STATUS             Status = AE_OK;
228251881Speter
229251881Speter
230251881Speter    ACPI_FUNCTION_TRACE (EvRemoveGpeReference);
231251881Speter
232251881Speter
233251881Speter    if (!GpeEventInfo->RuntimeCount)
234251881Speter    {
235251881Speter        return_ACPI_STATUS (AE_LIMIT);
236251881Speter    }
237251881Speter
238251881Speter    GpeEventInfo->RuntimeCount--;
239251881Speter    if (!GpeEventInfo->RuntimeCount)
240251881Speter    {
241251881Speter        /* Disable on last reference */
242251881Speter
243251881Speter        Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo);
244251881Speter        if (ACPI_SUCCESS (Status))
245251881Speter        {
246251881Speter            Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
247251881Speter        }
248251881Speter
249251881Speter        if (ACPI_FAILURE (Status))
250251881Speter        {
251251881Speter            GpeEventInfo->RuntimeCount++;
252251881Speter        }
253251881Speter    }
254251881Speter
255251881Speter    return_ACPI_STATUS (Status);
256251881Speter}
257251881Speter
258251881Speter
259251881Speter/*******************************************************************************
260251881Speter *
261251881Speter * FUNCTION:    AcpiEvLowGetGpeInfo
262251881Speter *
263251881Speter * PARAMETERS:  GpeNumber           - Raw GPE number
264251881Speter *              GpeBlock            - A GPE info block
265251881Speter *
266251881Speter * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE (The GpeNumber
267251881Speter *              is not within the specified GPE block)
268251881Speter *
269251881Speter * DESCRIPTION: Returns the EventInfo struct associated with this GPE. This is
270251881Speter *              the low-level implementation of EvGetGpeEventInfo.
271251881Speter *
272251881Speter ******************************************************************************/
273251881Speter
274251881SpeterACPI_GPE_EVENT_INFO *
275251881SpeterAcpiEvLowGetGpeInfo (
276251881Speter    UINT32                  GpeNumber,
277251881Speter    ACPI_GPE_BLOCK_INFO     *GpeBlock)
278251881Speter{
279251881Speter    UINT32                  GpeIndex;
280251881Speter
281251881Speter
282251881Speter    /*
283251881Speter     * Validate that the GpeNumber is within the specified GpeBlock.
284251881Speter     * (Two steps)
285251881Speter     */
286251881Speter    if (!GpeBlock ||
287251881Speter        (GpeNumber < GpeBlock->BlockBaseNumber))
288251881Speter    {
289251881Speter        return (NULL);
290251881Speter    }
291251881Speter
292251881Speter    GpeIndex = GpeNumber - GpeBlock->BlockBaseNumber;
293251881Speter    if (GpeIndex >= GpeBlock->GpeCount)
294251881Speter    {
295251881Speter        return (NULL);
296251881Speter    }
297251881Speter
298251881Speter    return (&GpeBlock->EventInfo[GpeIndex]);
299251881Speter}
300251881Speter
301251881Speter
302251881Speter/*******************************************************************************
303251881Speter *
304251881Speter * FUNCTION:    AcpiEvGetGpeEventInfo
305251881Speter *
306251881Speter * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
307251881Speter *              GpeNumber           - Raw GPE number
308251881Speter *
309251881Speter * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE
310251881Speter *
311251881Speter * DESCRIPTION: Returns the EventInfo struct associated with this GPE.
312251881Speter *              Validates the GpeBlock and the GpeNumber
313251881Speter *
314251881Speter *              Should be called only when the GPE lists are semaphore locked
315251881Speter *              and not subject to change.
316251881Speter *
317251881Speter ******************************************************************************/
318251881Speter
319251881SpeterACPI_GPE_EVENT_INFO *
320251881SpeterAcpiEvGetGpeEventInfo (
321251881Speter    ACPI_HANDLE             GpeDevice,
322251881Speter    UINT32                  GpeNumber)
323251881Speter{
324251881Speter    ACPI_OPERAND_OBJECT     *ObjDesc;
325251881Speter    ACPI_GPE_EVENT_INFO     *GpeInfo;
326251881Speter    UINT32                  i;
327251881Speter
328251881Speter
329251881Speter    ACPI_FUNCTION_ENTRY ();
330251881Speter
331251881Speter
332251881Speter    /* A NULL GpeDevice means use the FADT-defined GPE block(s) */
333251881Speter
334251881Speter    if (!GpeDevice)
335251881Speter    {
336251881Speter        /* Examine GPE Block 0 and 1 (These blocks are permanent) */
337251881Speter
338251881Speter        for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++)
339251881Speter        {
340251881Speter            GpeInfo = AcpiEvLowGetGpeInfo (GpeNumber,
341251881Speter                        AcpiGbl_GpeFadtBlocks[i]);
342251881Speter            if (GpeInfo)
343251881Speter            {
344251881Speter                return (GpeInfo);
345251881Speter            }
346251881Speter        }
347251881Speter
348251881Speter        /* The GpeNumber was not in the range of either FADT GPE block */
349251881Speter
350251881Speter        return (NULL);
351251881Speter    }
352251881Speter
353251881Speter    /* A Non-NULL GpeDevice means this is a GPE Block Device */
354251881Speter
355251881Speter    ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice);
356251881Speter    if (!ObjDesc ||
357251881Speter        !ObjDesc->Device.GpeBlock)
358251881Speter    {
359251881Speter        return (NULL);
360251881Speter    }
361251881Speter
362251881Speter    return (AcpiEvLowGetGpeInfo (GpeNumber, ObjDesc->Device.GpeBlock));
363251881Speter}
364251881Speter
365251881Speter
366251881Speter/*******************************************************************************
367251881Speter *
368251881Speter * FUNCTION:    AcpiEvGpeDetect
369251881Speter *
370251881Speter * PARAMETERS:  GpeXruptList        - Interrupt block for this interrupt.
371251881Speter *                                    Can have multiple GPE blocks attached.
372251881Speter *
373251881Speter * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
374251881Speter *
375251881Speter * DESCRIPTION: Detect if any GP events have occurred. This function is
376251881Speter *              executed at interrupt level.
377251881Speter *
378251881Speter ******************************************************************************/
379251881Speter
380251881SpeterUINT32
381251881SpeterAcpiEvGpeDetect (
382251881Speter    ACPI_GPE_XRUPT_INFO     *GpeXruptList)
383251881Speter{
384251881Speter    ACPI_STATUS             Status;
385251881Speter    ACPI_GPE_BLOCK_INFO     *GpeBlock;
386251881Speter    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
387251881Speter    UINT32                  IntStatus = ACPI_INTERRUPT_NOT_HANDLED;
388251881Speter    UINT8                   EnabledStatusByte;
389251881Speter    UINT32                  StatusReg;
390251881Speter    UINT32                  EnableReg;
391251881Speter    ACPI_CPU_FLAGS          Flags;
392251881Speter    UINT32                  i;
393251881Speter    UINT32                  j;
394251881Speter
395251881Speter
396251881Speter    ACPI_FUNCTION_NAME (EvGpeDetect);
397251881Speter
398251881Speter    /* Check for the case where there are no GPEs */
399251881Speter
400251881Speter    if (!GpeXruptList)
401251881Speter    {
402251881Speter        return (IntStatus);
403251881Speter    }
404251881Speter
405251881Speter    /*
406251881Speter     * We need to obtain the GPE lock for both the data structs and registers
407251881Speter     * Note: Not necessary to obtain the hardware lock, since the GPE
408251881Speter     * registers are owned by the GpeLock.
409251881Speter     */
410251881Speter    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
411251881Speter
412251881Speter    /* Examine all GPE blocks attached to this interrupt level */
413251881Speter
414251881Speter    GpeBlock = GpeXruptList->GpeBlockListHead;
415251881Speter    while (GpeBlock)
416251881Speter    {
417251881Speter        /*
418251881Speter         * Read all of the 8-bit GPE status and enable registers in this GPE
419251881Speter         * block, saving all of them. Find all currently active GP events.
420251881Speter         */
421251881Speter        for (i = 0; i < GpeBlock->RegisterCount; i++)
422251881Speter        {
423251881Speter            /* Get the next status/enable pair */
424251881Speter
425251881Speter            GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
426251881Speter
427251881Speter            /*
428251881Speter             * Optimization: If there are no GPEs enabled within this
429251881Speter             * register, we can safely ignore the entire register.
430251881Speter             */
431251881Speter            if (!(GpeRegisterInfo->EnableForRun |
432251881Speter                  GpeRegisterInfo->EnableForWake))
433251881Speter            {
434251881Speter                ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
435251881Speter                    "Ignore disabled registers for GPE%02X-GPE%02X: "
436251881Speter                    "RunEnable=%02X, WakeEnable=%02X\n",
437251881Speter                    GpeRegisterInfo->BaseGpeNumber,
438251881Speter                    GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1),
439251881Speter                    GpeRegisterInfo->EnableForRun,
440251881Speter                    GpeRegisterInfo->EnableForWake));
441251881Speter                continue;
442251881Speter            }
443251881Speter
444251881Speter            /* Read the Status Register */
445251881Speter
446251881Speter            Status = AcpiHwRead (&StatusReg, &GpeRegisterInfo->StatusAddress);
447251881Speter            if (ACPI_FAILURE (Status))
448251881Speter            {
449251881Speter                goto UnlockAndExit;
450251881Speter            }
451251881Speter
452251881Speter            /* Read the Enable Register */
453251881Speter
454251881Speter            Status = AcpiHwRead (&EnableReg, &GpeRegisterInfo->EnableAddress);
455251881Speter            if (ACPI_FAILURE (Status))
456251881Speter            {
457251881Speter                goto UnlockAndExit;
458251881Speter            }
459251881Speter
460251881Speter            ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
461251881Speter                "Read registers for GPE%02X-GPE%02X: Status=%02X, Enable=%02X, "
462251881Speter                "RunEnable=%02X, WakeEnable=%02X\n",
463251881Speter                GpeRegisterInfo->BaseGpeNumber,
464251881Speter                GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1),
465251881Speter                StatusReg, EnableReg,
466251881Speter                GpeRegisterInfo->EnableForRun,
467251881Speter                GpeRegisterInfo->EnableForWake));
468251881Speter
469251881Speter            /* Check if there is anything active at all in this register */
470251881Speter
471251881Speter            EnabledStatusByte = (UINT8) (StatusReg & EnableReg);
472251881Speter            if (!EnabledStatusByte)
473251881Speter            {
474251881Speter                /* No active GPEs in this register, move on */
475251881Speter
476251881Speter                continue;
477251881Speter            }
478251881Speter
479251881Speter            /* Now look at the individual GPEs in this byte register */
480251881Speter
481251881Speter            for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
482251881Speter            {
483251881Speter                /* Examine one GPE bit */
484251881Speter
485251881Speter                if (EnabledStatusByte & (1 << j))
486251881Speter                {
487251881Speter                    /*
488251881Speter                     * Found an active GPE. Dispatch the event to a handler
489251881Speter                     * or method.
490251881Speter                     */
491251881Speter                    IntStatus |= AcpiEvGpeDispatch (GpeBlock->Node,
492251881Speter                        &GpeBlock->EventInfo[((ACPI_SIZE) i *
493251881Speter                            ACPI_GPE_REGISTER_WIDTH) + j],
494251881Speter                        j + GpeRegisterInfo->BaseGpeNumber);
495251881Speter                }
496251881Speter            }
497251881Speter        }
498251881Speter
499251881Speter        GpeBlock = GpeBlock->Next;
500251881Speter    }
501251881Speter
502251881SpeterUnlockAndExit:
503251881Speter
504251881Speter    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
505251881Speter    return (IntStatus);
506251881Speter}
507251881Speter
508251881Speter
509251881Speter/*******************************************************************************
510251881Speter *
511251881Speter * FUNCTION:    AcpiEvAsynchExecuteGpeMethod
512251881Speter *
513251881Speter * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
514251881Speter *
515251881Speter * RETURN:      None
516251881Speter *
517251881Speter * DESCRIPTION: Perform the actual execution of a GPE control method. This
518251881Speter *              function is called from an invocation of AcpiOsExecute and
519251881Speter *              therefore does NOT execute at interrupt level - so that
520251881Speter *              the control method itself is not executed in the context of
521251881Speter *              an interrupt handler.
522251881Speter *
523251881Speter ******************************************************************************/
524251881Speter
525251881Speterstatic void ACPI_SYSTEM_XFACE
526251881SpeterAcpiEvAsynchExecuteGpeMethod (
527251881Speter    void                    *Context)
528251881Speter{
529251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
530251881Speter    ACPI_STATUS             Status;
531251881Speter    ACPI_GPE_EVENT_INFO     *LocalGpeEventInfo;
532251881Speter    ACPI_EVALUATE_INFO      *Info;
533251881Speter    ACPI_GPE_NOTIFY_INFO    *Notify;
534251881Speter
535251881Speter
536251881Speter    ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod);
537251881Speter
538251881Speter
539251881Speter    /* Allocate a local GPE block */
540251881Speter
541251881Speter    LocalGpeEventInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_EVENT_INFO));
542251881Speter    if (!LocalGpeEventInfo)
543251881Speter    {
544251881Speter        ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY,
545251881Speter            "while handling a GPE"));
546251881Speter        return_VOID;
547251881Speter    }
548251881Speter
549251881Speter    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
550251881Speter    if (ACPI_FAILURE (Status))
551251881Speter    {
552251881Speter        return_VOID;
553251881Speter    }
554251881Speter
555251881Speter    /* Must revalidate the GpeNumber/GpeBlock */
556251881Speter
557251881Speter    if (!AcpiEvValidGpeEvent (GpeEventInfo))
558251881Speter    {
559251881Speter        Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
560251881Speter        return_VOID;
561251881Speter    }
562251881Speter
563251881Speter    /*
564251881Speter     * Take a snapshot of the GPE info for this level - we copy the info to
565251881Speter     * prevent a race condition with RemoveHandler/RemoveBlock.
566251881Speter     */
567251881Speter    ACPI_MEMCPY (LocalGpeEventInfo, GpeEventInfo,
568251881Speter        sizeof (ACPI_GPE_EVENT_INFO));
569251881Speter
570251881Speter    Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
571251881Speter    if (ACPI_FAILURE (Status))
572251881Speter    {
573251881Speter        return_VOID;
574251881Speter    }
575251881Speter
576251881Speter    /* Do the correct dispatch - normal method or implicit notify */
577251881Speter
578251881Speter    switch (LocalGpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK)
579251881Speter    {
580251881Speter    case ACPI_GPE_DISPATCH_NOTIFY:
581251881Speter
582251881Speter        /*
583251881Speter         * Implicit notify.
584251881Speter         * Dispatch a DEVICE_WAKE notify to the appropriate handler.
585251881Speter         * NOTE: the request is queued for execution after this method
586251881Speter         * completes. The notify handlers are NOT invoked synchronously
587251881Speter         * from this thread -- because handlers may in turn run other
588251881Speter         * control methods.
589251881Speter         *
590251881Speter         * June 2012: Expand implicit notify mechanism to support
591251881Speter         * notifies on multiple device objects.
592251881Speter         */
593251881Speter        Notify = LocalGpeEventInfo->Dispatch.NotifyList;
594251881Speter        while (ACPI_SUCCESS (Status) && Notify)
595251881Speter        {
596251881Speter            Status = AcpiEvQueueNotifyRequest (Notify->DeviceNode,
597251881Speter                        ACPI_NOTIFY_DEVICE_WAKE);
598251881Speter
599251881Speter            Notify = Notify->Next;
600251881Speter        }
601251881Speter        break;
602251881Speter
603251881Speter    case ACPI_GPE_DISPATCH_METHOD:
604251881Speter
605251881Speter        /* Allocate the evaluation information block */
606251881Speter
607251881Speter        Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
608251881Speter        if (!Info)
609251881Speter        {
610251881Speter            Status = AE_NO_MEMORY;
611251881Speter        }
612251881Speter        else
613251881Speter        {
614251881Speter            /*
615251881Speter             * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
616251881Speter             * _Lxx/_Exx control method that corresponds to this GPE
617251881Speter             */
618251881Speter            Info->PrefixNode = LocalGpeEventInfo->Dispatch.MethodNode;
619251881Speter            Info->Flags = ACPI_IGNORE_RETURN_VALUE;
620251881Speter
621251881Speter            Status = AcpiNsEvaluate (Info);
622251881Speter            ACPI_FREE (Info);
623251881Speter        }
624251881Speter
625251881Speter        if (ACPI_FAILURE (Status))
626251881Speter        {
627251881Speter            ACPI_EXCEPTION ((AE_INFO, Status,
628251881Speter                "while evaluating GPE method [%4.4s]",
629251881Speter                AcpiUtGetNodeName (LocalGpeEventInfo->Dispatch.MethodNode)));
630251881Speter        }
631251881Speter
632251881Speter        break;
633251881Speter
634251881Speter    default:
635251881Speter        return_VOID; /* Should never happen */
636251881Speter    }
637251881Speter
638251881Speter    /* Defer enabling of GPE until all notify handlers are done */
639251881Speter
640251881Speter    Status = AcpiOsExecute (OSL_NOTIFY_HANDLER,
641251881Speter                AcpiEvAsynchEnableGpe, LocalGpeEventInfo);
642251881Speter    if (ACPI_FAILURE (Status))
643251881Speter    {
644251881Speter        ACPI_FREE (LocalGpeEventInfo);
645251881Speter    }
646251881Speter    return_VOID;
647251881Speter}
648251881Speter
649251881Speter
650251881Speter/*******************************************************************************
651251881Speter *
652251881Speter * FUNCTION:    AcpiEvAsynchEnableGpe
653251881Speter *
654251881Speter * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
655251881Speter *              Callback from AcpiOsExecute
656251881Speter *
657251881Speter * RETURN:      None
658251881Speter *
659251881Speter * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
660251881Speter *              complete (i.e., finish execution of Notify)
661251881Speter *
662251881Speter ******************************************************************************/
663251881Speter
664251881Speterstatic void ACPI_SYSTEM_XFACE
665251881SpeterAcpiEvAsynchEnableGpe (
666251881Speter    void                    *Context)
667251881Speter{
668251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
669251881Speter
670251881Speter
671251881Speter    (void) AcpiEvFinishGpe (GpeEventInfo);
672251881Speter
673251881Speter    ACPI_FREE (GpeEventInfo);
674251881Speter    return;
675251881Speter}
676251881Speter
677251881Speter
678251881Speter/*******************************************************************************
679251881Speter *
680251881Speter * FUNCTION:    AcpiEvFinishGpe
681251881Speter *
682251881Speter * PARAMETERS:  GpeEventInfo        - Info for this GPE
683251881Speter *
684251881Speter * RETURN:      Status
685251881Speter *
686251881Speter * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
687251881Speter *              of a GPE method or a synchronous or asynchronous GPE handler.
688251881Speter *
689251881Speter ******************************************************************************/
690251881Speter
691251881SpeterACPI_STATUS
692251881SpeterAcpiEvFinishGpe (
693251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
694251881Speter{
695251881Speter    ACPI_STATUS             Status;
696251881Speter
697251881Speter
698251881Speter    if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
699251881Speter            ACPI_GPE_LEVEL_TRIGGERED)
700251881Speter    {
701251881Speter        /*
702251881Speter         * GPE is level-triggered, we clear the GPE status bit after
703251881Speter         * handling the event.
704251881Speter         */
705251881Speter        Status = AcpiHwClearGpe (GpeEventInfo);
706251881Speter        if (ACPI_FAILURE (Status))
707251881Speter        {
708251881Speter            return (Status);
709251881Speter        }
710251881Speter    }
711251881Speter
712251881Speter    /*
713251881Speter     * Enable this GPE, conditionally. This means that the GPE will
714251881Speter     * only be physically enabled if the EnableForRun bit is set
715251881Speter     * in the EventInfo.
716251881Speter     */
717251881Speter    (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE);
718251881Speter    return (AE_OK);
719251881Speter}
720251881Speter
721251881Speter
722251881Speter/*******************************************************************************
723251881Speter *
724251881Speter * FUNCTION:    AcpiEvGpeDispatch
725251881Speter *
726251881Speter * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
727251881Speter *              GpeEventInfo        - Info for this GPE
728251881Speter *              GpeNumber           - Number relative to the parent GPE block
729251881Speter *
730251881Speter * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
731251881Speter *
732251881Speter * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
733251881Speter *              or method (e.g. _Lxx/_Exx) handler.
734251881Speter *
735251881Speter *              This function executes at interrupt level.
736251881Speter *
737251881Speter ******************************************************************************/
738251881Speter
739251881SpeterUINT32
740251881SpeterAcpiEvGpeDispatch (
741251881Speter    ACPI_NAMESPACE_NODE     *GpeDevice,
742251881Speter    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
743251881Speter    UINT32                  GpeNumber)
744251881Speter{
745251881Speter    ACPI_STATUS             Status;
746251881Speter    UINT32                  ReturnValue;
747251881Speter
748251881Speter
749251881Speter    ACPI_FUNCTION_TRACE (EvGpeDispatch);
750251881Speter
751251881Speter
752251881Speter    /* Invoke global event handler if present */
753251881Speter
754251881Speter    AcpiGpeCount++;
755251881Speter    if (AcpiGbl_GlobalEventHandler)
756251881Speter    {
757251881Speter        AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_GPE, GpeDevice,
758251881Speter             GpeNumber, AcpiGbl_GlobalEventHandlerContext);
759251881Speter    }
760251881Speter
761251881Speter    /*
762251881Speter     * If edge-triggered, clear the GPE status bit now. Note that
763251881Speter     * level-triggered events are cleared after the GPE is serviced.
764251881Speter     */
765251881Speter    if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
766251881Speter            ACPI_GPE_EDGE_TRIGGERED)
767251881Speter    {
768251881Speter        Status = AcpiHwClearGpe (GpeEventInfo);
769251881Speter        if (ACPI_FAILURE (Status))
770251881Speter        {
771251881Speter            ACPI_EXCEPTION ((AE_INFO, Status,
772251881Speter                "Unable to clear GPE%02X", GpeNumber));
773251881Speter            return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
774251881Speter        }
775251881Speter    }
776251881Speter
777251881Speter    /*
778251881Speter     * Always disable the GPE so that it does not keep firing before
779251881Speter     * any asynchronous activity completes (either from the execution
780251881Speter     * of a GPE method or an asynchronous GPE handler.)
781251881Speter     *
782251881Speter     * If there is no handler or method to run, just disable the
783251881Speter     * GPE and leave it disabled permanently to prevent further such
784251881Speter     * pointless events from firing.
785251881Speter     */
786251881Speter    Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
787251881Speter    if (ACPI_FAILURE (Status))
788251881Speter    {
789251881Speter        ACPI_EXCEPTION ((AE_INFO, Status,
790251881Speter            "Unable to disable GPE%02X", GpeNumber));
791251881Speter        return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
792251881Speter    }
793251881Speter
794251881Speter    /*
795251881Speter     * Dispatch the GPE to either an installed handler or the control
796251881Speter     * method associated with this GPE (_Lxx or _Exx). If a handler
797251881Speter     * exists, we invoke it and do not attempt to run the method.
798251881Speter     * If there is neither a handler nor a method, leave the GPE
799251881Speter     * disabled.
800251881Speter     */
801251881Speter    switch (GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK)
802251881Speter    {
803251881Speter    case ACPI_GPE_DISPATCH_HANDLER:
804251881Speter
805251881Speter        /* Invoke the installed handler (at interrupt level) */
806251881Speter
807251881Speter        ReturnValue = GpeEventInfo->Dispatch.Handler->Address (
808251881Speter            GpeDevice, GpeNumber,
809251881Speter            GpeEventInfo->Dispatch.Handler->Context);
810251881Speter
811251881Speter        /* If requested, clear (if level-triggered) and reenable the GPE */
812251881Speter
813251881Speter        if (ReturnValue & ACPI_REENABLE_GPE)
814251881Speter        {
815251881Speter            (void) AcpiEvFinishGpe (GpeEventInfo);
816251881Speter        }
817251881Speter        break;
818251881Speter
819251881Speter    case ACPI_GPE_DISPATCH_METHOD:
820251881Speter    case ACPI_GPE_DISPATCH_NOTIFY:
821251881Speter
822251881Speter        /*
823251881Speter         * Execute the method associated with the GPE
824251881Speter         * NOTE: Level-triggered GPEs are cleared after the method completes.
825251881Speter         */
826251881Speter        Status = AcpiOsExecute (OSL_GPE_HANDLER,
827251881Speter                    AcpiEvAsynchExecuteGpeMethod, GpeEventInfo);
828251881Speter        if (ACPI_FAILURE (Status))
829251881Speter        {
830251881Speter            ACPI_EXCEPTION ((AE_INFO, Status,
831251881Speter                "Unable to queue handler for GPE%02X - event disabled",
832251881Speter                GpeNumber));
833251881Speter        }
834251881Speter        break;
835251881Speter
836251881Speter    default:
837251881Speter
838251881Speter        /*
839251881Speter         * No handler or method to run!
840251881Speter         * 03/2010: This case should no longer be possible. We will not allow
841251881Speter         * a GPE to be enabled if it has no handler or method.
842251881Speter         */
843251881Speter        ACPI_ERROR ((AE_INFO,
844251881Speter            "No handler or method for GPE%02X, disabling event",
845251881Speter            GpeNumber));
846251881Speter        break;
847251881Speter    }
848251881Speter
849251881Speter    return_VALUE (ACPI_INTERRUPT_HANDLED);
850251881Speter}
851251881Speter
852251881Speter#endif /* !ACPI_REDUCED_HARDWARE */
853251881Speter