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