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