]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - sys/contrib/dev/acpica/events/evgpe.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / sys / contrib / dev / acpica / events / evgpe.c
1 /******************************************************************************
2  *
3  * Module Name: evgpe - General Purpose Event handling and dispatch
4  *
5  *****************************************************************************/
6
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights.  You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code.  No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision.  In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change.  Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee.  Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution.  In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government.  In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************/
115
116 #include <contrib/dev/acpica/include/acpi.h>
117 #include <contrib/dev/acpica/include/accommon.h>
118 #include <contrib/dev/acpica/include/acevents.h>
119 #include <contrib/dev/acpica/include/acnamesp.h>
120
121 #define _COMPONENT          ACPI_EVENTS
122         ACPI_MODULE_NAME    ("evgpe")
123
124 /* Local prototypes */
125
126 static void ACPI_SYSTEM_XFACE
127 AcpiEvAsynchExecuteGpeMethod (
128     void                    *Context);
129
130 static void ACPI_SYSTEM_XFACE
131 AcpiEvAsynchEnableGpe (
132     void                    *Context);
133
134
135 /*******************************************************************************
136  *
137  * FUNCTION:    AcpiEvSetGpeType
138  *
139  * PARAMETERS:  GpeEventInfo            - GPE to set
140  *              Type                    - New type
141  *
142  * RETURN:      Status
143  *
144  * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run)
145  *
146  ******************************************************************************/
147
148 ACPI_STATUS
149 AcpiEvSetGpeType (
150     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
151     UINT8                   Type)
152 {
153     ACPI_STATUS             Status;
154
155
156     ACPI_FUNCTION_TRACE (EvSetGpeType);
157
158
159     /* Validate type and update register enable masks */
160
161     switch (Type)
162     {
163     case ACPI_GPE_TYPE_WAKE:
164     case ACPI_GPE_TYPE_RUNTIME:
165     case ACPI_GPE_TYPE_WAKE_RUN:
166         break;
167
168     default:
169         return_ACPI_STATUS (AE_BAD_PARAMETER);
170     }
171
172     /* Disable the GPE if currently enabled */
173
174     Status = AcpiEvDisableGpe (GpeEventInfo);
175
176     /* Clear the type bits and insert the new Type */
177
178     GpeEventInfo->Flags &= ~ACPI_GPE_TYPE_MASK;
179     GpeEventInfo->Flags |= Type;
180     return_ACPI_STATUS (Status);
181 }
182
183
184 /*******************************************************************************
185  *
186  * FUNCTION:    AcpiEvUpdateGpeEnableMasks
187  *
188  * PARAMETERS:  GpeEventInfo            - GPE to update
189  *              Type                    - What to do: ACPI_GPE_DISABLE or
190  *                                        ACPI_GPE_ENABLE
191  *
192  * RETURN:      Status
193  *
194  * DESCRIPTION: Updates GPE register enable masks based on the GPE type
195  *
196  ******************************************************************************/
197
198 ACPI_STATUS
199 AcpiEvUpdateGpeEnableMasks (
200     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
201     UINT8                   Type)
202 {
203     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
204     UINT8                   RegisterBit;
205
206
207     ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMasks);
208
209
210     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
211     if (!GpeRegisterInfo)
212     {
213         return_ACPI_STATUS (AE_NOT_EXIST);
214     }
215
216     RegisterBit = (UINT8)
217         (1 << (GpeEventInfo->GpeNumber - GpeRegisterInfo->BaseGpeNumber));
218
219     /* 1) Disable case. Simply clear all enable bits */
220
221     if (Type == ACPI_GPE_DISABLE)
222     {
223         ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, RegisterBit);
224         ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
225         return_ACPI_STATUS (AE_OK);
226     }
227
228     /* 2) Enable case. Set/Clear the appropriate enable bits */
229
230     switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
231     {
232     case ACPI_GPE_TYPE_WAKE:
233         ACPI_SET_BIT   (GpeRegisterInfo->EnableForWake, RegisterBit);
234         ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
235         break;
236
237     case ACPI_GPE_TYPE_RUNTIME:
238         ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, RegisterBit);
239         ACPI_SET_BIT   (GpeRegisterInfo->EnableForRun, RegisterBit);
240         break;
241
242     case ACPI_GPE_TYPE_WAKE_RUN:
243         ACPI_SET_BIT   (GpeRegisterInfo->EnableForWake, RegisterBit);
244         ACPI_SET_BIT   (GpeRegisterInfo->EnableForRun, RegisterBit);
245         break;
246
247     default:
248         return_ACPI_STATUS (AE_BAD_PARAMETER);
249     }
250
251     return_ACPI_STATUS (AE_OK);
252 }
253
254
255 /*******************************************************************************
256  *
257  * FUNCTION:    AcpiEvEnableGpe
258  *
259  * PARAMETERS:  GpeEventInfo            - GPE to enable
260  *              WriteToHardware         - Enable now, or just mark data structs
261  *                                        (WAKE GPEs should be deferred)
262  *
263  * RETURN:      Status
264  *
265  * DESCRIPTION: Enable a GPE based on the GPE type
266  *
267  ******************************************************************************/
268
269 ACPI_STATUS
270 AcpiEvEnableGpe (
271     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
272     BOOLEAN                 WriteToHardware)
273 {
274     ACPI_STATUS             Status;
275
276
277     ACPI_FUNCTION_TRACE (EvEnableGpe);
278
279
280     /* Make sure HW enable masks are updated */
281
282     Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_ENABLE);
283     if (ACPI_FAILURE (Status))
284     {
285         return_ACPI_STATUS (Status);
286     }
287
288     /* Mark wake-enabled or HW enable, or both */
289
290     switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
291     {
292     case ACPI_GPE_TYPE_WAKE:
293
294         ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
295         break;
296
297     case ACPI_GPE_TYPE_WAKE_RUN:
298
299         ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
300
301         /*lint -fallthrough */
302
303     case ACPI_GPE_TYPE_RUNTIME:
304
305         ACPI_SET_BIT (GpeEventInfo->Flags, ACPI_GPE_RUN_ENABLED);
306
307         if (WriteToHardware)
308         {
309             /* Clear the GPE (of stale events), then enable it */
310
311             Status = AcpiHwClearGpe (GpeEventInfo);
312             if (ACPI_FAILURE (Status))
313             {
314                 return_ACPI_STATUS (Status);
315             }
316
317             /* Enable the requested runtime GPE */
318
319             Status = AcpiHwWriteGpeEnableReg (GpeEventInfo);
320         }
321         break;
322
323     default:
324         return_ACPI_STATUS (AE_BAD_PARAMETER);
325     }
326
327     return_ACPI_STATUS (AE_OK);
328 }
329
330
331 /*******************************************************************************
332  *
333  * FUNCTION:    AcpiEvDisableGpe
334  *
335  * PARAMETERS:  GpeEventInfo            - GPE to disable
336  *
337  * RETURN:      Status
338  *
339  * DESCRIPTION: Disable a GPE based on the GPE type
340  *
341  ******************************************************************************/
342
343 ACPI_STATUS
344 AcpiEvDisableGpe (
345     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
346 {
347     ACPI_STATUS             Status;
348
349
350     ACPI_FUNCTION_TRACE (EvDisableGpe);
351
352
353     /*
354      * Note: Always disable the GPE, even if we think that that it is already
355      * disabled. It is possible that the AML or some other code has enabled
356      * the GPE behind our back.
357      */
358
359     /* Make sure HW enable masks are updated */
360
361     Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_DISABLE);
362     if (ACPI_FAILURE (Status))
363     {
364         return_ACPI_STATUS (Status);
365     }
366
367     /* Clear the appropriate enabled flags for this GPE */
368
369     switch (GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK)
370     {
371     case ACPI_GPE_TYPE_WAKE:
372
373         ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
374         break;
375
376     case ACPI_GPE_TYPE_WAKE_RUN:
377
378         ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_WAKE_ENABLED);
379
380         /*lint -fallthrough */
381
382     case ACPI_GPE_TYPE_RUNTIME:
383
384         /* Disable the requested runtime GPE */
385
386         ACPI_CLEAR_BIT (GpeEventInfo->Flags, ACPI_GPE_RUN_ENABLED);
387         break;
388
389     default:
390         break;
391     }
392
393     /*
394      * Always H/W disable this GPE, even if we don't know the GPE type.
395      * Simply clear the enable bit for this particular GPE, but do not
396      * write out the current GPE enable mask since this may inadvertently
397      * enable GPEs too early. An example is a rogue GPE that has arrived
398      * during ACPICA initialization - possibly because AML or other code
399      * has enabled the GPE.
400      */
401     Status = AcpiHwLowDisableGpe (GpeEventInfo);
402     return_ACPI_STATUS (Status);
403 }
404
405
406 /*******************************************************************************
407  *
408  * FUNCTION:    AcpiEvGetGpeEventInfo
409  *
410  * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
411  *              GpeNumber           - Raw GPE number
412  *
413  * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE
414  *
415  * DESCRIPTION: Returns the EventInfo struct associated with this GPE.
416  *              Validates the GpeBlock and the GpeNumber
417  *
418  *              Should be called only when the GPE lists are semaphore locked
419  *              and not subject to change.
420  *
421  ******************************************************************************/
422
423 ACPI_GPE_EVENT_INFO *
424 AcpiEvGetGpeEventInfo (
425     ACPI_HANDLE             GpeDevice,
426     UINT32                  GpeNumber)
427 {
428     ACPI_OPERAND_OBJECT     *ObjDesc;
429     ACPI_GPE_BLOCK_INFO     *GpeBlock;
430     UINT32                  i;
431
432
433     ACPI_FUNCTION_ENTRY ();
434
435
436     /* A NULL GpeBlock means use the FADT-defined GPE block(s) */
437
438     if (!GpeDevice)
439     {
440         /* Examine GPE Block 0 and 1 (These blocks are permanent) */
441
442         for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++)
443         {
444             GpeBlock = AcpiGbl_GpeFadtBlocks[i];
445             if (GpeBlock)
446             {
447                 if ((GpeNumber >= GpeBlock->BlockBaseNumber) &&
448                     (GpeNumber < GpeBlock->BlockBaseNumber +
449                         (GpeBlock->RegisterCount * 8)))
450                 {
451                     return (&GpeBlock->EventInfo[GpeNumber -
452                         GpeBlock->BlockBaseNumber]);
453                 }
454             }
455         }
456
457         /* The GpeNumber was not in the range of either FADT GPE block */
458
459         return (NULL);
460     }
461
462     /* A Non-NULL GpeDevice means this is a GPE Block Device */
463
464     ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice);
465     if (!ObjDesc ||
466         !ObjDesc->Device.GpeBlock)
467     {
468         return (NULL);
469     }
470
471     GpeBlock = ObjDesc->Device.GpeBlock;
472
473     if ((GpeNumber >= GpeBlock->BlockBaseNumber) &&
474         (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8)))
475     {
476         return (&GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]);
477     }
478
479     return (NULL);
480 }
481
482
483 /*******************************************************************************
484  *
485  * FUNCTION:    AcpiEvGpeDetect
486  *
487  * PARAMETERS:  GpeXruptList        - Interrupt block for this interrupt.
488  *                                    Can have multiple GPE blocks attached.
489  *
490  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
491  *
492  * DESCRIPTION: Detect if any GP events have occurred. This function is
493  *              executed at interrupt level.
494  *
495  ******************************************************************************/
496
497 UINT32
498 AcpiEvGpeDetect (
499     ACPI_GPE_XRUPT_INFO     *GpeXruptList)
500 {
501     ACPI_STATUS             Status;
502     ACPI_GPE_BLOCK_INFO     *GpeBlock;
503     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
504     UINT32                  IntStatus = ACPI_INTERRUPT_NOT_HANDLED;
505     UINT8                   EnabledStatusByte;
506     UINT32                  StatusReg;
507     UINT32                  EnableReg;
508     ACPI_CPU_FLAGS          Flags;
509     UINT32                  i;
510     UINT32                  j;
511
512
513     ACPI_FUNCTION_NAME (EvGpeDetect);
514
515     /* Check for the case where there are no GPEs */
516
517     if (!GpeXruptList)
518     {
519         return (IntStatus);
520     }
521
522     /*
523      * We need to obtain the GPE lock for both the data structs and registers
524      * Note: Not necessary to obtain the hardware lock, since the GPE
525      * registers are owned by the GpeLock.
526      */
527     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
528
529     /* Examine all GPE blocks attached to this interrupt level */
530
531     GpeBlock = GpeXruptList->GpeBlockListHead;
532     while (GpeBlock)
533     {
534         /*
535          * Read all of the 8-bit GPE status and enable registers in this GPE
536          * block, saving all of them. Find all currently active GP events.
537          */
538         for (i = 0; i < GpeBlock->RegisterCount; i++)
539         {
540             /* Get the next status/enable pair */
541
542             GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
543
544             /* Read the Status Register */
545
546             Status = AcpiRead (&StatusReg, &GpeRegisterInfo->StatusAddress);
547             if (ACPI_FAILURE (Status))
548             {
549                 goto UnlockAndExit;
550             }
551
552             /* Read the Enable Register */
553
554             Status = AcpiRead (&EnableReg, &GpeRegisterInfo->EnableAddress);
555             if (ACPI_FAILURE (Status))
556             {
557                 goto UnlockAndExit;
558             }
559
560             ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
561                 "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
562                 GpeRegisterInfo->BaseGpeNumber, StatusReg, EnableReg));
563
564             /* Check if there is anything active at all in this register */
565
566             EnabledStatusByte = (UINT8) (StatusReg & EnableReg);
567             if (!EnabledStatusByte)
568             {
569                 /* No active GPEs in this register, move on */
570
571                 continue;
572             }
573
574             /* Now look at the individual GPEs in this byte register */
575
576             for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
577             {
578                 /* Examine one GPE bit */
579
580                 if (EnabledStatusByte & (1 << j))
581                 {
582                     /*
583                      * Found an active GPE. Dispatch the event to a handler
584                      * or method.
585                      */
586                     IntStatus |= AcpiEvGpeDispatch (
587                         &GpeBlock->EventInfo[((ACPI_SIZE) i *
588                             ACPI_GPE_REGISTER_WIDTH) + j],
589                         j + GpeRegisterInfo->BaseGpeNumber);
590                 }
591             }
592         }
593
594         GpeBlock = GpeBlock->Next;
595     }
596
597 UnlockAndExit:
598
599     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
600     return (IntStatus);
601 }
602
603
604 /*******************************************************************************
605  *
606  * FUNCTION:    AcpiEvAsynchExecuteGpeMethod
607  *
608  * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
609  *
610  * RETURN:      None
611  *
612  * DESCRIPTION: Perform the actual execution of a GPE control method. This
613  *              function is called from an invocation of AcpiOsExecute and
614  *              therefore does NOT execute at interrupt level - so that
615  *              the control method itself is not executed in the context of
616  *              an interrupt handler.
617  *
618  ******************************************************************************/
619
620 static void ACPI_SYSTEM_XFACE
621 AcpiEvAsynchExecuteGpeMethod (
622     void                    *Context)
623 {
624     ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
625     ACPI_STATUS             Status;
626     ACPI_GPE_EVENT_INFO     *LocalGpeEventInfo;
627     ACPI_EVALUATE_INFO      *Info;
628
629
630     ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod);
631
632
633     /* Allocate a local GPE block */
634
635     LocalGpeEventInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_EVENT_INFO));
636     if (!LocalGpeEventInfo)
637     {
638         ACPI_EXCEPTION ((AE_INFO, AE_NO_MEMORY,
639             "while handling a GPE"));
640         return_VOID;
641     }
642
643     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
644     if (ACPI_FAILURE (Status))
645     {
646         return_VOID;
647     }
648
649     /* Must revalidate the GpeNumber/GpeBlock */
650
651     if (!AcpiEvValidGpeEvent (GpeEventInfo))
652     {
653         Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
654         return_VOID;
655     }
656
657     /* Set the GPE flags for return to enabled state */
658
659     (void) AcpiEvEnableGpe (GpeEventInfo, FALSE);
660
661     /*
662      * Take a snapshot of the GPE info for this level - we copy the info to
663      * prevent a race condition with RemoveHandler/RemoveBlock.
664      */
665     ACPI_MEMCPY (LocalGpeEventInfo, GpeEventInfo,
666         sizeof (ACPI_GPE_EVENT_INFO));
667
668     Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
669     if (ACPI_FAILURE (Status))
670     {
671         return_VOID;
672     }
673
674     /*
675      * Must check for control method type dispatch one more time to avoid a
676      * race with EvGpeInstallHandler
677      */
678     if ((LocalGpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
679             ACPI_GPE_DISPATCH_METHOD)
680     {
681         /* Allocate the evaluation information block */
682
683         Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
684         if (!Info)
685         {
686             Status = AE_NO_MEMORY;
687         }
688         else
689         {
690             /*
691              * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
692              * control method that corresponds to this GPE
693              */
694             Info->PrefixNode = LocalGpeEventInfo->Dispatch.MethodNode;
695             Info->Flags = ACPI_IGNORE_RETURN_VALUE;
696
697             Status = AcpiNsEvaluate (Info);
698             ACPI_FREE (Info);
699         }
700
701         if (ACPI_FAILURE (Status))
702         {
703             ACPI_EXCEPTION ((AE_INFO, Status,
704                 "while evaluating GPE method [%4.4s]",
705                 AcpiUtGetNodeName (LocalGpeEventInfo->Dispatch.MethodNode)));
706         }
707     }
708
709     /* Defer enabling of GPE until all notify handlers are done */
710
711     Status = AcpiOsExecute (OSL_NOTIFY_HANDLER,
712                 AcpiEvAsynchEnableGpe, LocalGpeEventInfo);
713     if (ACPI_FAILURE (Status))
714     {
715         ACPI_FREE (LocalGpeEventInfo);
716     }
717     return_VOID;
718 }
719
720
721 /*******************************************************************************
722  *
723  * FUNCTION:    AcpiEvAsynchEnableGpe
724  *
725  * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
726  *
727  * RETURN:      None
728  *
729  * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
730  *              complete (i.e., finish execution of Notify)
731  *
732  ******************************************************************************/
733
734 static void ACPI_SYSTEM_XFACE
735 AcpiEvAsynchEnableGpe (
736     void                    *Context)
737 {
738     ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
739     ACPI_STATUS             Status;
740
741
742     if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
743             ACPI_GPE_LEVEL_TRIGGERED)
744     {
745         /*
746          * GPE is level-triggered, we clear the GPE status bit after handling
747          * the event.
748          */
749         Status = AcpiHwClearGpe (GpeEventInfo);
750         if (ACPI_FAILURE (Status))
751         {
752             goto Exit;
753         }
754     }
755
756     /* Enable this GPE */
757
758     (void) AcpiHwWriteGpeEnableReg (GpeEventInfo);
759
760 Exit:
761     ACPI_FREE (GpeEventInfo);
762     return;
763 }
764
765
766 /*******************************************************************************
767  *
768  * FUNCTION:    AcpiEvGpeDispatch
769  *
770  * PARAMETERS:  GpeEventInfo    - Info for this GPE
771  *              GpeNumber       - Number relative to the parent GPE block
772  *
773  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
774  *
775  * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
776  *              or method (e.g. _Lxx/_Exx) handler.
777  *
778  *              This function executes at interrupt level.
779  *
780  ******************************************************************************/
781
782 UINT32
783 AcpiEvGpeDispatch (
784     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
785     UINT32                  GpeNumber)
786 {
787     ACPI_STATUS             Status;
788
789
790     ACPI_FUNCTION_TRACE (EvGpeDispatch);
791
792
793     AcpiGpeCount++;
794
795     /*
796      * If edge-triggered, clear the GPE status bit now. Note that
797      * level-triggered events are cleared after the GPE is serviced.
798      */
799     if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
800             ACPI_GPE_EDGE_TRIGGERED)
801     {
802         Status = AcpiHwClearGpe (GpeEventInfo);
803         if (ACPI_FAILURE (Status))
804         {
805             ACPI_EXCEPTION ((AE_INFO, Status,
806                 "Unable to clear GPE[%2X]", GpeNumber));
807             return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
808         }
809     }
810
811     /*
812      * Dispatch the GPE to either an installed handler, or the control method
813      * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
814      * it and do not attempt to run the method. If there is neither a handler
815      * nor a method, we disable this GPE to prevent further such pointless
816      * events from firing.
817      */
818     switch (GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK)
819     {
820     case ACPI_GPE_DISPATCH_HANDLER:
821
822         /*
823          * Invoke the installed handler (at interrupt level)
824          * Ignore return status for now.
825          * TBD: leave GPE disabled on error?
826          */
827         (void) GpeEventInfo->Dispatch.Handler->Address (
828                         GpeEventInfo->Dispatch.Handler->Context);
829
830         /* It is now safe to clear level-triggered events. */
831
832         if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
833                 ACPI_GPE_LEVEL_TRIGGERED)
834         {
835             Status = AcpiHwClearGpe (GpeEventInfo);
836             if (ACPI_FAILURE (Status))
837             {
838                 ACPI_EXCEPTION ((AE_INFO, Status,
839                     "Unable to clear GPE[%2X]", GpeNumber));
840                 return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
841             }
842         }
843         break;
844
845     case ACPI_GPE_DISPATCH_METHOD:
846
847         /*
848          * Disable the GPE, so it doesn't keep firing before the method has a
849          * chance to run (it runs asynchronously with interrupts enabled).
850          */
851         Status = AcpiEvDisableGpe (GpeEventInfo);
852         if (ACPI_FAILURE (Status))
853         {
854             ACPI_EXCEPTION ((AE_INFO, Status,
855                 "Unable to disable GPE[%2X]", GpeNumber));
856             return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
857         }
858
859         /*
860          * Execute the method associated with the GPE
861          * NOTE: Level-triggered GPEs are cleared after the method completes.
862          */
863         Status = AcpiOsExecute (OSL_GPE_HANDLER,
864                     AcpiEvAsynchExecuteGpeMethod, GpeEventInfo);
865         if (ACPI_FAILURE (Status))
866         {
867             ACPI_EXCEPTION ((AE_INFO, Status,
868                 "Unable to queue handler for GPE[%2X] - event disabled",
869                 GpeNumber));
870         }
871         break;
872
873     default:
874
875         /* No handler or method to run! */
876
877         ACPI_ERROR ((AE_INFO,
878             "No handler or method for GPE[%2X], disabling event",
879             GpeNumber));
880
881         /*
882          * Disable the GPE. The GPE will remain disabled until the ACPICA
883          * Core Subsystem is restarted, or a handler is installed.
884          */
885         Status = AcpiEvDisableGpe (GpeEventInfo);
886         if (ACPI_FAILURE (Status))
887         {
888             ACPI_EXCEPTION ((AE_INFO, Status,
889                 "Unable to disable GPE[%2X]", GpeNumber));
890             return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
891         }
892         break;
893     }
894
895     return_UINT32 (ACPI_INTERRUPT_HANDLED);
896 }
897