evgpe.c revision 193335
138357Sjdp/******************************************************************************
238357Sjdp *
338357Sjdp * Module Name: evgpe - General Purpose Event handling and dispatch
438357Sjdp *
538357Sjdp *****************************************************************************/
638357Sjdp
738357Sjdp/******************************************************************************
838357Sjdp *
938357Sjdp * 1. Copyright Notice
1038357Sjdp *
1138357Sjdp * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
1238357Sjdp * All rights reserved.
1338357Sjdp *
1438357Sjdp * 2. License
1538357Sjdp *
1638357Sjdp * 2.1. This is your license from Intel Corp. under its intellectual property
1738357Sjdp * rights.  You may have additional license terms from the party that provided
1838357Sjdp * you this software, covering your right to use that party's intellectual
1938357Sjdp * property rights.
2038357Sjdp *
2138357Sjdp * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2238357Sjdp * copy of the source code appearing in this file ("Covered Code") an
2338357Sjdp * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2438357Sjdp * base code distributed originally by Intel ("Original Intel Code") to copy,
2538357Sjdp * make derivatives, distribute, use and display any portion of the Covered
2650477Speter * Code in any form, with the right to sublicense such rights; and
2738357Sjdp *
2838357Sjdp * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
2938357Sjdp * license (with the right to sublicense), under only those claims of Intel
30186666Sobrien * patents that are infringed by the Original Intel Code, to make, use, sell,
3138357Sjdp * offer to sell, and import the Covered Code and derivative works thereof
3238357Sjdp * solely to the minimum extent necessary to exercise the above copyright
3338357Sjdp * license, and in no event shall the patent license extend to any additions
3438357Sjdp * to or modifications of the Original Intel Code.  No other license or right
3538357Sjdp * is granted directly or by implication, estoppel or otherwise;
3646656Sdfr *
3746656Sdfr * The above copyright and patent license is granted only if the following
3846656Sdfr * conditions are met:
3946656Sdfr *
4046656Sdfr * 3. Conditions
4146656Sdfr *
4246656Sdfr * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4346656Sdfr * Redistribution of source code of any substantial portion of the Covered
4446656Sdfr * Code or modification with rights to further distribute source must include
4546656Sdfr * the above Copyright Notice, the above License, this list of Conditions,
4646656Sdfr * and the following Disclaimer and Export Compliance provision.  In addition,
4746656Sdfr * Licensee must cause all Covered Code to which Licensee contributes to
4846656Sdfr * contain a file documenting the changes Licensee made to create that Covered
4946656Sdfr * Code and the date of any change.  Licensee must include in that file the
5046656Sdfr * documentation of any changes made by any predecessor Licensee.  Licensee
51188050Sjkoshy * must include a prominent statement that the modification is derived,
52188050Sjkoshy * directly or indirectly, from Original Intel Code.
53188050Sjkoshy *
54188050Sjkoshy * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55188050Sjkoshy * Redistribution of source code of any substantial portion of the Covered
56188050Sjkoshy * Code or modification without rights to further distribute source must
57188050Sjkoshy * include the following Disclaimer and Export Compliance provision in the
58188050Sjkoshy * documentation and/or other materials provided with distribution.  In
59188050Sjkoshy * addition, Licensee may not authorize further sublicense of source of any
60188050Sjkoshy * portion of the Covered Code, and must include terms to the effect that the
61188050Sjkoshy * license from Licensee to its licensee is limited to the intellectual
62159103Smaxim * property embodied in the software Licensee provides to its licensee, and
63159103Smaxim * not to intellectual property embodied in modifications its licensee may
64186666Sobrien * make.
65186666Sobrien *
66186666Sobrien * 3.3. Redistribution of Executable. Redistribution in executable form of any
67186666Sobrien * substantial portion of the Covered Code or modification must reproduce the
68186666Sobrien * above Copyright Notice, and the following Disclaimer and Export Compliance
69186666Sobrien * provision in the documentation and/or other materials provided with the
70186666Sobrien * distribution.
71186666Sobrien *
72186666Sobrien * 3.4. Intel retains all right, title, and interest in and to the Original
73186666Sobrien * Intel Code.
74186666Sobrien *
75186666Sobrien * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7638357Sjdp * Intel shall be used in advertising or otherwise to promote the sale, use or
7738357Sjdp * other dealings in products derived from or relating to the Covered Code
78186666Sobrien * without prior written authorization from Intel.
79186666Sobrien *
80186666Sobrien * 4. Disclaimer and Export Compliance
81186666Sobrien *
82186666Sobrien * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83186666Sobrien * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8438357Sjdp * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8538357Sjdp * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
86186666Sobrien * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
87186666Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8838357Sjdp * PARTICULAR PURPOSE.
8938357Sjdp *
90186666Sobrien * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91186666Sobrien * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92186666Sobrien * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9338357Sjdp * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9438357Sjdp * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95186666Sobrien * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
96186666Sobrien * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97186666Sobrien * LIMITED REMEDY.
9838357Sjdp *
9959342Sobrien * 4.3. Licensee shall not export, either directly or indirectly, any of this
100186666Sobrien * software or system incorporating such software without first obtaining any
101186666Sobrien * required license or other approval from the U. S. Department of Commerce or
102186666Sobrien * any other agency or department of the United States Government.  In the
103186666Sobrien * event Licensee exports any such software from the United States or
104186666Sobrien * re-exports any such software from a foreign destination, Licensee shall
105186666Sobrien * ensure that the distribution and export/re-export of the software is in
106186666Sobrien * compliance with all laws, regulations, orders, or other restrictions of the
107186666Sobrien * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108186666Sobrien * any of its subsidiaries will export/re-export any technical data, process,
109186666Sobrien * software, or service, directly or indirectly, to any country for which the
110186666Sobrien * United States government or any agency thereof requires an export license,
111186666Sobrien * other governmental approval, or letter of assurance, without first obtaining
112186666Sobrien * such license, approval or letter.
113186666Sobrien *
114186666Sobrien *****************************************************************************/
115186666Sobrien
116186666Sobrien#include "acpi.h"
117186666Sobrien#include "accommon.h"
11859342Sobrien#include "acevents.h"
119186666Sobrien#include "acnamesp.h"
120186666Sobrien
121153502Smarcel#define _COMPONENT          ACPI_EVENTS
12238357Sjdp        ACPI_MODULE_NAME    ("evgpe")
123186666Sobrien
12438357Sjdp/* Local prototypes */
12538357Sjdp
12638357Sjdpstatic void ACPI_SYSTEM_XFACE
12738357SjdpAcpiEvAsynchExecuteGpeMethod (
12838357Sjdp    void                    *Context);
129186666Sobrien
130186666Sobrienstatic void ACPI_SYSTEM_XFACE
131186666SobrienAcpiEvAsynchEnableGpe (
132186666Sobrien    void                    *Context);
133186666Sobrien
134186666Sobrien
135186666Sobrien/*******************************************************************************
136186666Sobrien *
137186666Sobrien * FUNCTION:    AcpiEvSetGpeType
13838357Sjdp *
13938357Sjdp * PARAMETERS:  GpeEventInfo            - GPE to set
140186666Sobrien *              Type                    - New type
141186666Sobrien *
142186666Sobrien * RETURN:      Status
143186666Sobrien *
144186666Sobrien * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run)
145186666Sobrien *
146186666Sobrien ******************************************************************************/
147186666Sobrien
148186666SobrienACPI_STATUS
149186666SobrienAcpiEvSetGpeType (
150186666Sobrien    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
151186666Sobrien    UINT8                   Type)
152186666Sobrien{
153186666Sobrien    ACPI_STATUS             Status;
154186666Sobrien
155186666Sobrien
156186666Sobrien    ACPI_FUNCTION_TRACE (EvSetGpeType);
157186666Sobrien
158186666Sobrien
159186666Sobrien    /* Validate type and update register enable masks */
160186666Sobrien
161186666Sobrien    switch (Type)
162186666Sobrien    {
163186666Sobrien    case ACPI_GPE_TYPE_WAKE:
164186666Sobrien    case ACPI_GPE_TYPE_RUNTIME:
165186666Sobrien    case ACPI_GPE_TYPE_WAKE_RUN:
166186666Sobrien        break;
167186666Sobrien
168186666Sobrien    default:
169186666Sobrien        return_ACPI_STATUS (AE_BAD_PARAMETER);
170186666Sobrien    }
171186666Sobrien
172186666Sobrien    /* Disable the GPE if currently enabled */
173186666Sobrien
174186666Sobrien    Status = AcpiEvDisableGpe (GpeEventInfo);
175186666Sobrien
176186666Sobrien    /* Clear the type bits and insert the new Type */
177186666Sobrien
178186666Sobrien    GpeEventInfo->Flags &= ~ACPI_GPE_TYPE_MASK;
179186666Sobrien    GpeEventInfo->Flags |= Type;
180186666Sobrien    return_ACPI_STATUS (Status);
181186666Sobrien}
182186666Sobrien
183163016Sjb
184186666Sobrien/*******************************************************************************
185186666Sobrien *
186186666Sobrien * FUNCTION:    AcpiEvUpdateGpeEnableMasks
187186316Skaiw *
188186666Sobrien * PARAMETERS:  GpeEventInfo            - GPE to update
189186316Skaiw *              Type                    - What to do: ACPI_GPE_DISABLE or
190186666Sobrien *                                        ACPI_GPE_ENABLE
191186666Sobrien *
192186666Sobrien * RETURN:      Status
193186666Sobrien *
194186666Sobrien * DESCRIPTION: Updates GPE register enable masks based on the GPE type
195186666Sobrien *
196186666Sobrien ******************************************************************************/
197186666Sobrien
198186316SkaiwACPI_STATUS
199186666SobrienAcpiEvUpdateGpeEnableMasks (
200186316Skaiw    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
201186666Sobrien    UINT8                   Type)
202186666Sobrien{
203186666Sobrien    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
204186666Sobrien    UINT8                   RegisterBit;
205186316Skaiw
206186666Sobrien
207186666Sobrien    ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMasks);
208186666Sobrien
209186666Sobrien
210186666Sobrien    GpeRegisterInfo = GpeEventInfo->RegisterInfo;
211186666Sobrien    if (!GpeRegisterInfo)
212186666Sobrien    {
213186666Sobrien        return_ACPI_STATUS (AE_NOT_EXIST);
214186666Sobrien    }
215186666Sobrien
216186666Sobrien    RegisterBit = (UINT8)
217186666Sobrien        (1 << (GpeEventInfo->GpeNumber - GpeRegisterInfo->BaseGpeNumber));
218186666Sobrien
219186666Sobrien    /* 1) Disable case. Simply clear all enable bits */
220186666Sobrien
221186316Skaiw    if (Type == ACPI_GPE_DISABLE)
222186666Sobrien    {
223186666Sobrien        ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, RegisterBit);
224186666Sobrien        ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
225186666Sobrien        return_ACPI_STATUS (AE_OK);
226186666Sobrien    }
227186666Sobrien
228186666Sobrien    /* 2) Enable case. Set/Clear the appropriate enable bits */
229186316Skaiw
230186666Sobrien    switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
231186666Sobrien    {
232186316Skaiw    case ACPI_GPE_TYPE_WAKE:
233186666Sobrien        ACPI_SET_BIT   (GpeRegisterInfo->EnableForWake, RegisterBit);
234186666Sobrien        ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
235186666Sobrien        break;
236186666Sobrien
237186666Sobrien    case ACPI_GPE_TYPE_RUNTIME:
238186316Skaiw        ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, RegisterBit);
23938357Sjdp        ACPI_SET_BIT   (GpeRegisterInfo->EnableForRun, RegisterBit);
240153502Smarcel        break;
241186666Sobrien
242186666Sobrien    case ACPI_GPE_TYPE_WAKE_RUN:
243186666Sobrien        ACPI_SET_BIT   (GpeRegisterInfo->EnableForWake, RegisterBit);
244186666Sobrien        ACPI_SET_BIT   (GpeRegisterInfo->EnableForRun, RegisterBit);
245153502Smarcel        break;
24638357Sjdp
247186666Sobrien    default:
248186666Sobrien        return_ACPI_STATUS (AE_BAD_PARAMETER);
249186666Sobrien    }
250186666Sobrien
251186666Sobrien    return_ACPI_STATUS (AE_OK);
252186666Sobrien}
253186666Sobrien
254186666Sobrien
255186666Sobrien/*******************************************************************************
256186666Sobrien *
25738357Sjdp * FUNCTION:    AcpiEvEnableGpe
25838357Sjdp *
259186666Sobrien * PARAMETERS:  GpeEventInfo            - GPE to enable
260186666Sobrien *              WriteToHardware         - Enable now, or just mark data structs
261186666Sobrien *                                        (WAKE GPEs should be deferred)
262186666Sobrien *
263186666Sobrien * RETURN:      Status
264186666Sobrien *
265186666Sobrien * DESCRIPTION: Enable a GPE based on the GPE type
266186666Sobrien *
267186666Sobrien ******************************************************************************/
268186666Sobrien
269186666SobrienACPI_STATUS
270186666SobrienAcpiEvEnableGpe (
271186666Sobrien    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
272186666Sobrien    BOOLEAN                 WriteToHardware)
273186666Sobrien{
274186666Sobrien    ACPI_STATUS             Status;
275186666Sobrien
276186666Sobrien
277186666Sobrien    ACPI_FUNCTION_TRACE (EvEnableGpe);
278186666Sobrien
279186666Sobrien
280186666Sobrien    /* Make sure HW enable masks are updated */
281186720Skaiw
282186666Sobrien    Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_ENABLE);
283186666Sobrien    if (ACPI_FAILURE (Status))
284186666Sobrien    {
285186666Sobrien        return_ACPI_STATUS (Status);
286186666Sobrien    }
287186666Sobrien
288186666Sobrien    /* Mark wake-enabled or HW enable, or both */
289186666Sobrien
290186666Sobrien    switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
291186666Sobrien    {
292186666Sobrien    case ACPI_GPE_TYPE_WAKE:
293186666Sobrien
294186666Sobrien        ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
295186666Sobrien        break;
296186666Sobrien
297186666Sobrien    case ACPI_GPE_TYPE_WAKE_RUN:
298186666Sobrien
299186666Sobrien        ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
300186666Sobrien
30138357Sjdp        /*lint -fallthrough */
30238954Sjdp
303186666Sobrien    case ACPI_GPE_TYPE_RUNTIME:
304186666Sobrien
305186666Sobrien        ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_RUN_ENABLED);
306186666Sobrien
307186666Sobrien        if (WriteToHardware)
308186666Sobrien        {
309186666Sobrien            /* Clear the GPE (of stale events), then enable it */
310186666Sobrien
311186666Sobrien            Status = AcpiHwClearGpe (GpeEventInfo);
312186666Sobrien            if (ACPI_FAILURE (Status))
313186666Sobrien            {
314186666Sobrien                return_ACPI_STATUS (Status);
31538954Sjdp            }
31638357Sjdp
317186666Sobrien            /* Enable the requested runtime GPE */
318186666Sobrien
319186666Sobrien            Status = AcpiHwWriteGpeEnableReg (GpeEventInfo);
320186666Sobrien        }
321186666Sobrien        break;
322186666Sobrien
323186666Sobrien    default:
324116511Smdodd        return_ACPI_STATUS (AE_BAD_PARAMETER);
325186666Sobrien    }
326163016Sjb
327168286Skan    return_ACPI_STATUS (AE_OK);
328163016Sjb}
329163016Sjb
330163016Sjb
331163016Sjb/*******************************************************************************
332163016Sjb *
333163016Sjb * FUNCTION:    AcpiEvDisableGpe
334186666Sobrien *
335186666Sobrien * PARAMETERS:  GpeEventInfo            - GPE to disable
336186666Sobrien *
33738357Sjdp * RETURN:      Status
33838357Sjdp *
339186666Sobrien * DESCRIPTION: Disable a GPE based on the GPE type
340186666Sobrien *
341186666Sobrien ******************************************************************************/
342186666Sobrien
343186666SobrienACPI_STATUS
34438357SjdpAcpiEvDisableGpe (
345164276Sjkoshy    ACPI_GPE_EVENT_INFO     *GpeEventInfo)
346164276Sjkoshy{
347164276Sjkoshy    ACPI_STATUS             Status;
34838357Sjdp
349186666Sobrien
350186666Sobrien    ACPI_FUNCTION_TRACE (EvDisableGpe);
35138357Sjdp
352186666Sobrien
353186666Sobrien    /*
354186666Sobrien     * Note: Always disable the GPE, even if we think that that it is already
355186666Sobrien     * disabled. It is possible that the AML or some other code has enabled
356186666Sobrien     * the GPE behind our back.
357186666Sobrien     */
358186666Sobrien
359186666Sobrien    /* Make sure HW enable masks are updated */
360186666Sobrien
361186666Sobrien    Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_DISABLE);
362186666Sobrien    if (ACPI_FAILURE (Status))
363186666Sobrien    {
364186666Sobrien        return_ACPI_STATUS (Status);
36538357Sjdp    }
366186666Sobrien
367186666Sobrien    /* Clear the appropriate enabled flags for this GPE */
368186666Sobrien
369186666Sobrien    switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
370186666Sobrien    {
371186666Sobrien    case ACPI_GPE_TYPE_WAKE:
372186666Sobrien
373186666Sobrien        ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
374116511Smdodd        break;
375186666Sobrien
376116511Smdodd    case ACPI_GPE_TYPE_WAKE_RUN:
377116511Smdodd
378116511Smdodd        ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
379116511Smdodd
380116511Smdodd        /*lint -fallthrough */
381116511Smdodd
382116511Smdodd    case ACPI_GPE_TYPE_RUNTIME:
383116511Smdodd
384116511Smdodd        /* Disable the requested runtime GPE */
385116511Smdodd
386116511Smdodd        ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_RUN_ENABLED);
387116515Sphk        break;
388116511Smdodd
389116511Smdodd    default:
390116511Smdodd        break;
391116511Smdodd    }
392116511Smdodd
393116511Smdodd    /*
394116511Smdodd     * Always H/W disable this GPE, even if we don't know the GPE type.
395116511Smdodd     * Simply clear the enable bit for this particular GPE, but do not
396116511Smdodd     * write out the current GPE enable mask since this may inadvertently
397163016Sjb     * enable GPEs too early. An example is a rogue GPE that has arrived
398116511Smdodd     * during ACPICA initialization - possibly because AML or other code
399163016Sjb     * has enabled the GPE.
400163016Sjb     */
401163016Sjb    Status = AcpiHwLowDisableGpe (GpeEventInfo);
402163016Sjb    return_ACPI_STATUS (Status);
403153544Smarcel}
404116511Smdodd
405163016Sjb
406163016Sjb/*******************************************************************************
407163016Sjb *
408163016Sjb * FUNCTION:    AcpiEvGetGpeEventInfo
409163016Sjb *
410163016Sjb * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
411163016Sjb *              GpeNumber           - Raw GPE number
412163016Sjb *
413163016Sjb * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE
414163016Sjb *
415163016Sjb * DESCRIPTION: Returns the EventInfo struct associated with this GPE.
416163016Sjb *              Validates the GpeBlock and the GpeNumber
417163016Sjb *
418163016Sjb *              Should be called only when the GPE lists are semaphore locked
419163016Sjb *              and not subject to change.
420163016Sjb *
421163016Sjb ******************************************************************************/
422163016Sjb
423163016SjbACPI_GPE_EVENT_INFO *
424163016SjbAcpiEvGetGpeEventInfo (
425163016Sjb    ACPI_HANDLE             GpeDevice,
426163016Sjb    UINT32                  GpeNumber)
427163016Sjb{
428163016Sjb    ACPI_OPERAND_OBJECT     *ObjDesc;
429163016Sjb    ACPI_GPE_BLOCK_INFO     *GpeBlock;
430163016Sjb    UINT32                  i;
431163016Sjb
432163016Sjb
433163016Sjb    ACPI_FUNCTION_ENTRY ();
434163016Sjb
435163016Sjb
436163016Sjb    /* A NULL GpeBlock means use the FADT-defined GPE block(s) */
437163016Sjb
438153515Skan    if (!GpeDevice)
439163016Sjb    {
440163016Sjb        /* Examine GPE Block 0 and 1 (These blocks are permanent) */
441163016Sjb
442153515Skan        for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++)
443153515Skan        {
444153515Skan            GpeBlock = AcpiGbl_GpeFadtBlocks[i];
445153515Skan            if (GpeBlock)
446153515Skan            {
447163016Sjb                if ((GpeNumber >= GpeBlock->BlockBaseNumber) &&
448163016Sjb                    (GpeNumber < GpeBlock->BlockBaseNumber +
449163016Sjb                        (GpeBlock->RegisterCount * 8)))
450163016Sjb                {
451163016Sjb                    return (&GpeBlock->EventInfo[GpeNumber -
452163016Sjb                        GpeBlock->BlockBaseNumber]);
453163016Sjb                }
454116511Smdodd            }
455116511Smdodd        }
456116511Smdodd
457116511Smdodd        /* The GpeNumber was not in the range of either FADT GPE block */
458116511Smdodd
459116511Smdodd        return (NULL);
460116511Smdodd    }
461116511Smdodd
462116511Smdodd    /* A Non-NULL GpeDevice means this is a GPE Block Device */
463116511Smdodd
464116511Smdodd    ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice);
465116511Smdodd    if (!ObjDesc ||
466116511Smdodd        !ObjDesc->Device.GpeBlock)
467116511Smdodd    {
468116511Smdodd        return (NULL);
46939189Sjdp    }
470186666Sobrien
471186666Sobrien    GpeBlock = ObjDesc->Device.GpeBlock;
472186666Sobrien
47339189Sjdp    if ((GpeNumber >= GpeBlock->BlockBaseNumber) &&
47438357Sjdp        (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8)))
475186666Sobrien    {
476186666Sobrien        return (&GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]);
477186666Sobrien    }
478186666Sobrien
479186666Sobrien    return (NULL);
480186666Sobrien}
481186666Sobrien
48238357Sjdp
48338357Sjdp/*******************************************************************************
484186666Sobrien *
485186666Sobrien * FUNCTION:    AcpiEvGpeDetect
486186666Sobrien *
487186666Sobrien * PARAMETERS:  GpeXruptList        - Interrupt block for this interrupt.
488186666Sobrien *                                    Can have multiple GPE blocks attached.
489186666Sobrien *
490186666Sobrien * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
491186666Sobrien *
492186666Sobrien * DESCRIPTION: Detect if any GP events have occurred. This function is
493186666Sobrien *              executed at interrupt level.
494186666Sobrien *
495186666Sobrien ******************************************************************************/
49638357Sjdp
497153502SmarcelUINT32
498186666SobrienAcpiEvGpeDetect (
499186666Sobrien    ACPI_GPE_XRUPT_INFO     *GpeXruptList)
500186666Sobrien{
501186666Sobrien    ACPI_STATUS             Status;
502186666Sobrien    ACPI_GPE_BLOCK_INFO     *GpeBlock;
503186666Sobrien    ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
504186666Sobrien    UINT32                  IntStatus = ACPI_INTERRUPT_NOT_HANDLED;
505153502Smarcel    UINT8                   EnabledStatusByte;
50638357Sjdp    UINT32                  StatusReg;
507186666Sobrien    UINT32                  EnableReg;
50838357Sjdp    ACPI_CPU_FLAGS          Flags;
509153515Skan    UINT32                  i;
510153515Skan    UINT32                  j;
511186666Sobrien
512153515Skan
513153515Skan    ACPI_FUNCTION_NAME (EvGpeDetect);
514153515Skan
515153515Skan    /* Check for the case where there are no GPEs */
516153515Skan
517186666Sobrien    if (!GpeXruptList)
518186666Sobrien    {
519186666Sobrien        return (IntStatus);
520153515Skan    }
521153515Skan
522153515Skan    /*
523186666Sobrien     * We need to obtain the GPE lock for both the data structs and registers
524153515Skan     * Note: Not necessary to obtain the hardware lock, since the GPE
525186666Sobrien     * registers are owned by the GpeLock.
526186666Sobrien     */
527153515Skan    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
528163016Sjb
529163016Sjb    /* Examine all GPE blocks attached to this interrupt level */
530163016Sjb
531163016Sjb    GpeBlock = GpeXruptList->GpeBlockListHead;
532163016Sjb    while (GpeBlock)
533163016Sjb    {
534163016Sjb        /*
535163016Sjb         * Read all of the 8-bit GPE status and enable registers in this GPE
536163016Sjb         * block, saving all of them. Find all currently active GP events.
537163016Sjb         */
538163016Sjb        for (i = 0; i < GpeBlock->RegisterCount; i++)
539163016Sjb        {
540163016Sjb            /* Get the next status/enable pair */
541163016Sjb
542163016Sjb            GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
543163016Sjb
544163016Sjb            /* Read the Status Register */
545163016Sjb
546163016Sjb            Status = AcpiRead (&StatusReg, &GpeRegisterInfo->StatusAddress);
547163016Sjb            if (ACPI_FAILURE (Status))
548163016Sjb            {
549163016Sjb                goto UnlockAndExit;
550163016Sjb            }
551163016Sjb
552163016Sjb            /* Read the Enable Register */
553163016Sjb
554163016Sjb            Status = AcpiRead (&EnableReg, &GpeRegisterInfo->EnableAddress);
555163016Sjb            if (ACPI_FAILURE (Status))
556163016Sjb            {
557163016Sjb                goto UnlockAndExit;
558163016Sjb            }
559163016Sjb
560163016Sjb            ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
561163016Sjb                "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
562163016Sjb                GpeRegisterInfo->BaseGpeNumber, StatusReg, EnableReg));
563163016Sjb
564163016Sjb            /* Check if there is anything active at all in this register */
565163016Sjb
566163016Sjb            EnabledStatusByte = (UINT8) (StatusReg & EnableReg);
567163016Sjb            if (!EnabledStatusByte)
568163016Sjb            {
569163016Sjb                /* No active GPEs in this register, move on */
570163016Sjb
571163016Sjb                continue;
572163016Sjb            }
573163016Sjb
574163016Sjb            /* Now look at the individual GPEs in this byte register */
575163016Sjb
576163016Sjb            for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
577163016Sjb            {
578163016Sjb                /* Examine one GPE bit */
579163016Sjb
580163016Sjb                if (EnabledStatusByte & (1 << j))
581163016Sjb                {
582163016Sjb                    /*
583163016Sjb                     * Found an active GPE. Dispatch the event to a handler
584163016Sjb                     * or method.
585163016Sjb                     */
586163016Sjb                    IntStatus |= AcpiEvGpeDispatch (
587163016Sjb                        &GpeBlock->EventInfo[((ACPI_SIZE) i *
588163016Sjb                            ACPI_GPE_REGISTER_WIDTH) + j],
589163016Sjb                        j + GpeRegisterInfo->BaseGpeNumber);
590163016Sjb                }
591163016Sjb            }
592163016Sjb        }
593163016Sjb
594163016Sjb        GpeBlock = GpeBlock->Next;
595163016Sjb    }
596163016Sjb
597163016SjbUnlockAndExit:
598163016Sjb
599163016Sjb    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
600163016Sjb    return (IntStatus);
601163016Sjb}
602163016Sjb
603163016Sjb
604163016Sjb/*******************************************************************************
605163016Sjb *
606163016Sjb * FUNCTION:    AcpiEvAsynchExecuteGpeMethod
607163016Sjb *
608163016Sjb * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
609163016Sjb *
610163016Sjb * RETURN:      None
611163016Sjb *
612163016Sjb * DESCRIPTION: Perform the actual execution of a GPE control method. This
613163016Sjb *              function is called from an invocation of AcpiOsExecute and
614163016Sjb *              therefore does NOT execute at interrupt level - so that
615163016Sjb *              the control method itself is not executed in the context of
616163016Sjb *              an interrupt handler.
617163016Sjb *
618163016Sjb ******************************************************************************/
619163016Sjb
620163016Sjbstatic void ACPI_SYSTEM_XFACE
621163016SjbAcpiEvAsynchExecuteGpeMethod (
622163016Sjb    void                    *Context)
623163016Sjb{
624163016Sjb    ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
625163016Sjb    ACPI_STATUS             Status;
626163016Sjb    ACPI_GPE_EVENT_INFO     *LocalGpeEventInfo;
627163016Sjb    ACPI_EVALUATE_INFO      *Info;
628163016Sjb
629163016Sjb
630163016Sjb    ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod);
631163016Sjb
632163016Sjb
633163016Sjb    /* Allocate a local GPE block */
634163016Sjb
635163016Sjb    LocalGpeEventInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_EVENT_INFO));
636163016Sjb    if (!LocalGpeEventInfo)
637163016Sjb    {
638163016Sjb        ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY,
639163016Sjb            "while handling a GPE"));
640163016Sjb        return_VOID;
641163016Sjb    }
642163016Sjb
643163016Sjb    Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
644163016Sjb    if (ACPI_FAILURE (Status))
645163016Sjb    {
646163016Sjb        return_VOID;
647163016Sjb    }
648163016Sjb
649163016Sjb    /* Must revalidate the GpeNumber/GpeBlock */
650163016Sjb
651163016Sjb    if (!AcpiEvValidGpeEvent (GpeEventInfo))
652163016Sjb    {
653163016Sjb        Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
654163016Sjb        return_VOID;
655163016Sjb    }
656163016Sjb
657163016Sjb    /* Set the GPE flags for return to enabled state */
658163016Sjb
659163016Sjb    (void) AcpiEvEnableGpe (GpeEventInfo, FALSE);
660163016Sjb
661163016Sjb    /*
662163016Sjb     * Take a snapshot of the GPE info for this level - we copy the info to
663163016Sjb     * prevent a race condition with RemoveHandler/RemoveBlock.
664163016Sjb     */
665163016Sjb    ACPI_MEMCPY (LocalGpeEventInfo, GpeEventInfo,
666163016Sjb        sizeof (ACPI_GPE_EVENT_INFO));
667163016Sjb
668163016Sjb    Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
669163016Sjb    if (ACPI_FAILURE (Status))
670163016Sjb    {
671163016Sjb        return_VOID;
672163016Sjb    }
673163016Sjb
674163016Sjb    /*
675163016Sjb     * Must check for control method type dispatch one more time to avoid a
676163016Sjb     * race with EvGpeInstallHandler
677163016Sjb     */
678163016Sjb    if ((LocalGpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
679163016Sjb            ACPI_GPE_DISPATCH_METHOD)
680163016Sjb    {
681163016Sjb        /* Allocate the evaluation information block */
682163016Sjb
683163016Sjb        Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
684163016Sjb        if (!Info)
685163016Sjb        {
686163016Sjb            Status = AE_NO_MEMORY;
687163016Sjb        }
688163016Sjb        else
689163016Sjb        {
690163016Sjb            /*
691163016Sjb             * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
692163016Sjb             * control method that corresponds to this GPE
693163016Sjb             */
694163016Sjb            Info->PrefixNode = LocalGpeEventInfo->Dispatch.MethodNode;
695163016Sjb            Info->Flags = ACPI_IGNORE_RETURN_VALUE;
696163016Sjb
697163016Sjb            Status = AcpiNsEvaluate (Info);
698163016Sjb            ACPI_FREE (Info);
699163016Sjb        }
700163016Sjb
701163016Sjb        if (ACPI_FAILURE (Status))
702163016Sjb        {
703163016Sjb            ACPI_EXCEPTION ((AE_INFO, Status,
704163016Sjb                "while evaluating GPE method [%4.4s]",
705163016Sjb                AcpiUtGetNodeName (LocalGpeEventInfo->Dispatch.MethodNode)));
706163016Sjb        }
707163016Sjb    }
708163016Sjb
709163016Sjb    /* Defer enabling of GPE until all notify handlers are done */
710163016Sjb
711163016Sjb    Status = AcpiOsExecute (OSL_NOTIFY_HANDLER,
712163016Sjb                AcpiEvAsynchEnableGpe, LocalGpeEventInfo);
713163016Sjb    if (ACPI_FAILURE (Status))
714163016Sjb    {
715163016Sjb        ACPI_FREE (LocalGpeEventInfo);
716163016Sjb    }
717163016Sjb    return_VOID;
718163016Sjb}
719181147Simp
720181147Simp
721181147Simp/*******************************************************************************
722181147Simp *
723181147Simp * FUNCTION:    AcpiEvAsynchEnableGpe
724181147Simp *
725181147Simp * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
726181147Simp *
727181147Simp * RETURN:      None
728181147Simp *
729181147Simp * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
730181147Simp *              complete (i.e., finish execution of Notify)
731181147Simp *
732181147Simp ******************************************************************************/
733181147Simp
734181147Simpstatic void ACPI_SYSTEM_XFACE
735181147SimpAcpiEvAsynchEnableGpe (
736181147Simp    void                    *Context)
737163016Sjb{
738163016Sjb    ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
739163016Sjb    ACPI_STATUS             Status;
740163016Sjb
741163016Sjb
742163016Sjb    if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
743163016Sjb            ACPI_GPE_LEVEL_TRIGGERED)
744163016Sjb    {
745163016Sjb        /*
746163016Sjb         * GPE is level-triggered, we clear the GPE status bit after handling
747163016Sjb         * the event.
748163016Sjb         */
749163016Sjb        Status = AcpiHwClearGpe (GpeEventInfo);
750163016Sjb        if (ACPI_FAILURE (Status))
751163016Sjb        {
752163016Sjb            goto Exit;
753163016Sjb        }
754163016Sjb    }
755163016Sjb
756163016Sjb    /* Enable this GPE */
757163016Sjb
758163016Sjb    (void) AcpiHwWriteGpeEnableReg (GpeEventInfo);
759163016Sjb
760163016SjbExit:
761163016Sjb    ACPI_FREE (GpeEventInfo);
762163016Sjb    return;
763163016Sjb}
764163016Sjb
765163016Sjb
766163016Sjb/*******************************************************************************
767163016Sjb *
768163016Sjb * FUNCTION:    AcpiEvGpeDispatch
769163016Sjb *
770163016Sjb * PARAMETERS:  GpeEventInfo    - Info for this GPE
771163016Sjb *              GpeNumber       - Number relative to the parent GPE block
772163016Sjb *
773163016Sjb * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
774163016Sjb *
775163016Sjb * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
776163016Sjb *              or method (e.g. _Lxx/_Exx) handler.
777163016Sjb *
778186666Sobrien *              This function executes at interrupt level.
779186666Sobrien *
780186666Sobrien ******************************************************************************/
781186666Sobrien
782186666SobrienUINT32
783186666SobrienAcpiEvGpeDispatch (
784186666Sobrien    ACPI_GPE_EVENT_INFO     *GpeEventInfo,
785186666Sobrien    UINT32                  GpeNumber)
786186666Sobrien{
787186666Sobrien    ACPI_STATUS             Status;
788186666Sobrien
789186666Sobrien
790186666Sobrien    ACPI_FUNCTION_TRACE (EvGpeDispatch);
791186666Sobrien
792186666Sobrien
793186666Sobrien    AcpiGpeCount++;
794186666Sobrien
795186666Sobrien    /*
796186666Sobrien     * If edge-triggered, clear the GPE status bit now. Note that
797186666Sobrien     * level-triggered events are cleared after the GPE is serviced.
798186666Sobrien     */
799186666Sobrien    if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
800186666Sobrien            ACPI_GPE_EDGE_TRIGGERED)
801186666Sobrien    {
802163016Sjb        Status = AcpiHwClearGpe (GpeEventInfo);
803163016Sjb        if (ACPI_FAILURE (Status))
804163016Sjb        {
805163016Sjb            ACPI_EXCEPTION ((AE_INFO, Status,
806163016Sjb                "Unable to clear GPE[%2X]", GpeNumber));
807163016Sjb            return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
808163016Sjb        }
809163016Sjb    }
810163016Sjb
811163016Sjb    /*
812163016Sjb     * Dispatch the GPE to either an installed handler, or the control method
813163016Sjb     * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
814163016Sjb     * it and do not attempt to run the method. If there is neither a handler
815163016Sjb     * nor a method, we disable this GPE to prevent further such pointless
816163016Sjb     * events from firing.
817163016Sjb     */
818163016Sjb    switch (GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK)
819163016Sjb    {
820163016Sjb    case ACPI_GPE_DISPATCH_HANDLER:
821163016Sjb
822163016Sjb        /*
823163016Sjb         * Invoke the installed handler (at interrupt level)
824163016Sjb         * Ignore return status for now.
825163016Sjb         * TBD: leave GPE disabled on error?
826163016Sjb         */
827163016Sjb        (void) GpeEventInfo->Dispatch.Handler->Address (
828163016Sjb                        GpeEventInfo->Dispatch.Handler->Context);
829163016Sjb
830163016Sjb        /* It is now safe to clear level-triggered events. */
831163016Sjb
832163016Sjb        if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
833163016Sjb                ACPI_GPE_LEVEL_TRIGGERED)
834163016Sjb        {
835163016Sjb            Status = AcpiHwClearGpe (GpeEventInfo);
836163016Sjb            if (ACPI_FAILURE (Status))
837163016Sjb            {
838163016Sjb                ACPI_EXCEPTION ((AE_INFO, Status,
839163016Sjb                    "Unable to clear GPE[%2X]", GpeNumber));
840163016Sjb                return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
841163016Sjb            }
842163016Sjb        }
843163016Sjb        break;
844163016Sjb
845163016Sjb    case ACPI_GPE_DISPATCH_METHOD:
846163016Sjb
847163016Sjb        /*
848163016Sjb         * Disable the GPE, so it doesn't keep firing before the method has a
849163016Sjb         * chance to run (it runs asynchronously with interrupts enabled).
850163016Sjb         */
851163016Sjb        Status = AcpiEvDisableGpe (GpeEventInfo);
852163016Sjb        if (ACPI_FAILURE (Status))
853163016Sjb        {
854163016Sjb            ACPI_EXCEPTION ((AE_INFO, Status,
855163016Sjb                "Unable to disable GPE[%2X]", GpeNumber));
856163016Sjb            return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
857163016Sjb        }
858163016Sjb
859163016Sjb        /*
860163016Sjb         * Execute the method associated with the GPE
861163016Sjb         * NOTE: Level-triggered GPEs are cleared after the method completes.
862163016Sjb         */
863163016Sjb        Status = AcpiOsExecute (OSL_GPE_HANDLER,
864163016Sjb                    AcpiEvAsynchExecuteGpeMethod, GpeEventInfo);
865163016Sjb        if (ACPI_FAILURE (Status))
866163016Sjb        {
867163016Sjb            ACPI_EXCEPTION ((AE_INFO, Status,
868163016Sjb                "Unable to queue handler for GPE[%2X] - event disabled",
869163016Sjb                GpeNumber));
870163016Sjb        }
871163016Sjb        break;
872163016Sjb
873163016Sjb    default:
874163016Sjb
875163016Sjb        /* No handler or method to run! */
876163016Sjb
877163016Sjb        ACPI_ERROR ((AE_INFO,
878163016Sjb            "No handler or method for GPE[%2X], disabling event",
879163016Sjb            GpeNumber));
880163016Sjb
881163016Sjb        /*
882163016Sjb         * Disable the GPE. The GPE will remain disabled until the ACPICA
883163016Sjb         * Core Subsystem is restarted, or a handler is installed.
884163016Sjb         */
885163016Sjb        Status = AcpiEvDisableGpe (GpeEventInfo);
886163016Sjb        if (ACPI_FAILURE (Status))
887163016Sjb        {
888163016Sjb            ACPI_EXCEPTION ((AE_INFO, Status,
889163016Sjb                "Unable to disable GPE[%2X]", GpeNumber));
890163016Sjb            return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
891163016Sjb        }
892163016Sjb        break;
893163016Sjb    }
894163016Sjb
895163016Sjb    return_UINT32 (ACPI_INTERRUPT_HANDLED);
896163016Sjb}
897163016Sjb
898163016Sjb