xref: /netbsd/sys/external/bsd/acpica/dist/events/evgpe.c (revision e5631441)
1 /******************************************************************************
2  *
3  * Module Name: evgpe - General Purpose Event handling and dispatch
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acevents.h"
47 #include "acnamesp.h"
48 
49 #define _COMPONENT          ACPI_EVENTS
50         ACPI_MODULE_NAME    ("evgpe")
51 
52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53 
54 /* Local prototypes */
55 
56 static void ACPI_SYSTEM_XFACE
57 AcpiEvAsynchExecuteGpeMethod (
58     void                    *Context);
59 
60 static void ACPI_SYSTEM_XFACE
61 AcpiEvAsynchEnableGpe (
62     void                    *Context);
63 
64 
65 /*******************************************************************************
66  *
67  * FUNCTION:    AcpiEvUpdateGpeEnableMask
68  *
69  * PARAMETERS:  GpeEventInfo            - GPE to update
70  *
71  * RETURN:      Status
72  *
73  * DESCRIPTION: Updates GPE register enable mask based upon whether there are
74  *              runtime references to this GPE
75  *
76  ******************************************************************************/
77 
78 ACPI_STATUS
AcpiEvUpdateGpeEnableMask(ACPI_GPE_EVENT_INFO * GpeEventInfo)79 AcpiEvUpdateGpeEnableMask (
80     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
81 {
82     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
83     UINT32                  RegisterBit;
84 
85 
86     ACPI_FUNCTION_TRACE (EvUpdateGpeEnableMask);
87 
88 
89     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
90     if (!GpeRegisterInfo)
91     {
92         return_ACPI_STATUS (AE_NOT_EXIST);
93     }
94 
95     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
96 
97     /* Clear the run bit up front */
98 
99     ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForRun, RegisterBit);
100 
101     /* Set the mask bit only if there are references to this GPE */
102 
103     if (GpeEventInfo->RuntimeCount)
104     {
105         ACPI_SET_BIT (GpeRegisterInfo->EnableForRun, (UINT8) RegisterBit);
106     }
107 
108     GpeRegisterInfo->EnableMask = GpeRegisterInfo->EnableForRun;
109     return_ACPI_STATUS (AE_OK);
110 }
111 
112 
113 /*******************************************************************************
114  *
115  * FUNCTION:    AcpiEvEnableGpe
116  *
117  * PARAMETERS:  GpeEventInfo            - GPE to enable
118  *
119  * RETURN:      Status
120  *
121  * DESCRIPTION: Enable a GPE.
122  *
123  ******************************************************************************/
124 
125 ACPI_STATUS
AcpiEvEnableGpe(ACPI_GPE_EVENT_INFO * GpeEventInfo)126 AcpiEvEnableGpe (
127     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
128 {
129     ACPI_STATUS             Status;
130 
131 
132     ACPI_FUNCTION_TRACE (EvEnableGpe);
133 
134 
135     /* Enable the requested GPE */
136 
137     Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE);
138     return_ACPI_STATUS (Status);
139 }
140 
141 
142 /*******************************************************************************
143  *
144  * FUNCTION:    AcpiEvMaskGpe
145  *
146  * PARAMETERS:  GpeEventInfo            - GPE to be blocked/unblocked
147  *              IsMasked                - Whether the GPE is masked or not
148  *
149  * RETURN:      Status
150  *
151  * DESCRIPTION: Unconditionally mask/unmask a GPE during runtime.
152  *
153  ******************************************************************************/
154 
155 ACPI_STATUS
AcpiEvMaskGpe(ACPI_GPE_EVENT_INFO * GpeEventInfo,BOOLEAN IsMasked)156 AcpiEvMaskGpe (
157     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
158     BOOLEAN                 IsMasked)
159 {
160     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
161     UINT32                  RegisterBit;
162 
163 
164     ACPI_FUNCTION_TRACE (EvMaskGpe);
165 
166 
167     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
168     if (!GpeRegisterInfo)
169     {
170         return_ACPI_STATUS (AE_NOT_EXIST);
171     }
172 
173     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
174 
175     /* Perform the action */
176 
177     if (IsMasked)
178     {
179         if (RegisterBit & GpeRegisterInfo->MaskForRun)
180         {
181             return_ACPI_STATUS (AE_BAD_PARAMETER);
182         }
183 
184         (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
185         ACPI_SET_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit);
186     }
187     else
188     {
189         if (!(RegisterBit & GpeRegisterInfo->MaskForRun))
190         {
191             return_ACPI_STATUS (AE_BAD_PARAMETER);
192         }
193 
194         ACPI_CLEAR_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit);
195         if (GpeEventInfo->RuntimeCount &&
196             !GpeEventInfo->DisableForDispatch)
197         {
198             (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE);
199         }
200     }
201 
202     return_ACPI_STATUS (AE_OK);
203 }
204 
205 
206 /*******************************************************************************
207  *
208  * FUNCTION:    AcpiEvAddGpeReference
209  *
210  * PARAMETERS:  GpeEventInfo            - Add a reference to this GPE
211  *              ClearOnEnable           - Clear GPE status before enabling it
212  *
213  * RETURN:      Status
214  *
215  * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
216  *              hardware-enabled.
217  *
218  ******************************************************************************/
219 
220 ACPI_STATUS
AcpiEvAddGpeReference(ACPI_GPE_EVENT_INFO * GpeEventInfo,BOOLEAN ClearOnEnable)221 AcpiEvAddGpeReference (
222     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
223     BOOLEAN                 ClearOnEnable)
224 {
225     ACPI_STATUS             Status = AE_OK;
226 
227 
228     ACPI_FUNCTION_TRACE (EvAddGpeReference);
229 
230 
231     if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX)
232     {
233         return_ACPI_STATUS (AE_LIMIT);
234     }
235 
236     GpeEventInfo->RuntimeCount++;
237     if (GpeEventInfo->RuntimeCount == 1)
238     {
239         /* Enable on first reference */
240 
241         if (ClearOnEnable)
242         {
243             (void) AcpiHwClearGpe (GpeEventInfo);
244         }
245 
246         Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo);
247         if (ACPI_SUCCESS (Status))
248         {
249             Status = AcpiEvEnableGpe (GpeEventInfo);
250         }
251 
252         if (ACPI_FAILURE (Status))
253         {
254             GpeEventInfo->RuntimeCount--;
255         }
256     }
257 
258     return_ACPI_STATUS (Status);
259 }
260 
261 
262 /*******************************************************************************
263  *
264  * FUNCTION:    AcpiEvRemoveGpeReference
265  *
266  * PARAMETERS:  GpeEventInfo            - Remove a reference to this GPE
267  *
268  * RETURN:      Status
269  *
270  * DESCRIPTION: Remove a reference to a GPE. When the last reference is
271  *              removed, the GPE is hardware-disabled.
272  *
273  ******************************************************************************/
274 
275 ACPI_STATUS
AcpiEvRemoveGpeReference(ACPI_GPE_EVENT_INFO * GpeEventInfo)276 AcpiEvRemoveGpeReference (
277     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
278 {
279     ACPI_STATUS             Status = AE_OK;
280 
281 
282     ACPI_FUNCTION_TRACE (EvRemoveGpeReference);
283 
284 
285     if (!GpeEventInfo->RuntimeCount)
286     {
287         return_ACPI_STATUS (AE_LIMIT);
288     }
289 
290     GpeEventInfo->RuntimeCount--;
291     if (!GpeEventInfo->RuntimeCount)
292     {
293         /* Disable on last reference */
294 
295         Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo);
296         if (ACPI_SUCCESS (Status))
297         {
298             Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
299         }
300 
301         if (ACPI_FAILURE (Status))
302         {
303             GpeEventInfo->RuntimeCount++;
304         }
305     }
306 
307     return_ACPI_STATUS (Status);
308 }
309 
310 
311 /*******************************************************************************
312  *
313  * FUNCTION:    AcpiEvLowGetGpeInfo
314  *
315  * PARAMETERS:  GpeNumber           - Raw GPE number
316  *              GpeBlock            - A GPE info block
317  *
318  * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE (The GpeNumber
319  *              is not within the specified GPE block)
320  *
321  * DESCRIPTION: Returns the EventInfo struct associated with this GPE. This is
322  *              the low-level implementation of EvGetGpeEventInfo.
323  *
324  ******************************************************************************/
325 
326 ACPI_GPE_EVENT_INFO *
AcpiEvLowGetGpeInfo(UINT32 GpeNumber,ACPI_GPE_BLOCK_INFO * GpeBlock)327 AcpiEvLowGetGpeInfo (
328     UINT32                  GpeNumber,
329     ACPI_GPE_BLOCK_INFO     *GpeBlock)
330 {
331     UINT32                  GpeIndex;
332 
333 
334     /*
335      * Validate that the GpeNumber is within the specified GpeBlock.
336      * (Two steps)
337      */
338     if (!GpeBlock ||
339         (GpeNumber < GpeBlock->BlockBaseNumber))
340     {
341         return (NULL);
342     }
343 
344     GpeIndex = GpeNumber - GpeBlock->BlockBaseNumber;
345     if (GpeIndex >= GpeBlock->GpeCount)
346     {
347         return (NULL);
348     }
349 
350     return (&GpeBlock->EventInfo[GpeIndex]);
351 }
352 
353 
354 /*******************************************************************************
355  *
356  * FUNCTION:    AcpiEvGetGpeEventInfo
357  *
358  * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
359  *              GpeNumber           - Raw GPE number
360  *
361  * RETURN:      A GPE EventInfo struct. NULL if not a valid GPE
362  *
363  * DESCRIPTION: Returns the EventInfo struct associated with this GPE.
364  *              Validates the GpeBlock and the GpeNumber
365  *
366  *              Should be called only when the GPE lists are semaphore locked
367  *              and not subject to change.
368  *
369  ******************************************************************************/
370 
371 ACPI_GPE_EVENT_INFO *
AcpiEvGetGpeEventInfo(ACPI_HANDLE GpeDevice,UINT32 GpeNumber)372 AcpiEvGetGpeEventInfo (
373     ACPI_HANDLE             GpeDevice,
374     UINT32                  GpeNumber)
375 {
376     ACPI_OPERAND_OBJECT     *ObjDesc;
377     ACPI_GPE_EVENT_INFO     *GpeInfo;
378     UINT32                  i;
379 
380 
381     ACPI_FUNCTION_ENTRY ();
382 
383 
384     /* A NULL GpeDevice means use the FADT-defined GPE block(s) */
385 
386     if (!GpeDevice)
387     {
388         /* Examine GPE Block 0 and 1 (These blocks are permanent) */
389 
390         for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++)
391         {
392             GpeInfo = AcpiEvLowGetGpeInfo (GpeNumber,
393                 AcpiGbl_GpeFadtBlocks[i]);
394             if (GpeInfo)
395             {
396                 return (GpeInfo);
397             }
398         }
399 
400         /* The GpeNumber was not in the range of either FADT GPE block */
401 
402         return (NULL);
403     }
404 
405     /* A Non-NULL GpeDevice means this is a GPE Block Device */
406 
407     ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice);
408     if (!ObjDesc ||
409         !ObjDesc->Device.GpeBlock)
410     {
411         return (NULL);
412     }
413 
414     return (AcpiEvLowGetGpeInfo (GpeNumber, ObjDesc->Device.GpeBlock));
415 }
416 
417 
418 /*******************************************************************************
419  *
420  * FUNCTION:    AcpiEvGpeDetect
421  *
422  * PARAMETERS:  GpeXruptList        - Interrupt block for this interrupt.
423  *                                    Can have multiple GPE blocks attached.
424  *
425  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
426  *
427  * DESCRIPTION: Detect if any GP events have occurred. This function is
428  *              executed at interrupt level.
429  *
430  ******************************************************************************/
431 
432 UINT32
AcpiEvGpeDetect(ACPI_GPE_XRUPT_INFO * GpeXruptList)433 AcpiEvGpeDetect (
434     ACPI_GPE_XRUPT_INFO     *GpeXruptList)
435 {
436     ACPI_GPE_BLOCK_INFO     *GpeBlock;
437     ACPI_NAMESPACE_NODE     *GpeDevice;
438     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
439     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
440     UINT32                  GpeNumber;
441     UINT32                  IntStatus = ACPI_INTERRUPT_NOT_HANDLED;
442     ACPI_CPU_FLAGS          Flags;
443     UINT32                  i;
444     UINT32                  j;
445 
446 
447     ACPI_FUNCTION_NAME (EvGpeDetect);
448 
449     /* Check for the case where there are no GPEs */
450 
451     if (!GpeXruptList)
452     {
453         return (IntStatus);
454     }
455 
456     /*
457      * We need to obtain the GPE lock for both the data structs and registers
458      * Note: Not necessary to obtain the hardware lock, since the GPE
459      * registers are owned by the GpeLock.
460      */
461     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
462 
463     /* Examine all GPE blocks attached to this interrupt level */
464 
465     GpeBlock = GpeXruptList->GpeBlockListHead;
466     while (GpeBlock)
467     {
468         GpeDevice = GpeBlock->Node;
469 
470         /*
471          * Read all of the 8-bit GPE status and enable registers in this GPE
472          * block, saving all of them. Find all currently active GP events.
473          */
474         for (i = 0; i < GpeBlock->RegisterCount; i++)
475         {
476             /* Get the next status/enable pair */
477 
478             GpeRegisterInfo = &GpeBlock->RegisterInfo[i];
479 
480             /*
481              * Optimization: If there are no GPEs enabled within this
482              * register, we can safely ignore the entire register.
483              */
484             if (!(GpeRegisterInfo->EnableForRun |
485                   GpeRegisterInfo->EnableForWake))
486             {
487                 ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
488                     "Ignore disabled registers for GPE %02X-%02X: "
489                     "RunEnable=%02X, WakeEnable=%02X\n",
490                     GpeRegisterInfo->BaseGpeNumber,
491                     GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1),
492                     GpeRegisterInfo->EnableForRun,
493                     GpeRegisterInfo->EnableForWake));
494                 continue;
495             }
496 
497             /* Now look at the individual GPEs in this byte register */
498 
499             for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
500             {
501                 /* Detect and dispatch one GPE bit */
502 
503                 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
504                     ACPI_GPE_REGISTER_WIDTH) + j];
505                 GpeNumber = j + GpeRegisterInfo->BaseGpeNumber;
506                 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
507                 IntStatus |= AcpiEvDetectGpe (
508                     GpeDevice, GpeEventInfo, GpeNumber);
509                 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
510             }
511         }
512 
513         GpeBlock = GpeBlock->Next;
514     }
515 
516     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
517     return (IntStatus);
518 }
519 
520 
521 /*******************************************************************************
522  *
523  * FUNCTION:    AcpiEvAsynchExecuteGpeMethod
524  *
525  * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
526  *
527  * RETURN:      None
528  *
529  * DESCRIPTION: Perform the actual execution of a GPE control method. This
530  *              function is called from an invocation of AcpiOsExecute and
531  *              therefore does NOT execute at interrupt level - so that
532  *              the control method itself is not executed in the context of
533  *              an interrupt handler.
534  *
535  ******************************************************************************/
536 
537 static void ACPI_SYSTEM_XFACE
AcpiEvAsynchExecuteGpeMethod(void * Context)538 AcpiEvAsynchExecuteGpeMethod (
539     void                    *Context)
540 {
541     ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
542     ACPI_STATUS             Status = AE_OK;
543     ACPI_EVALUATE_INFO      *Info;
544     ACPI_GPE_NOTIFY_INFO    *Notify;
545 
546 
547     ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod);
548 
549 
550     /* Do the correct dispatch - normal method or implicit notify */
551 
552     switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags))
553     {
554     case ACPI_GPE_DISPATCH_NOTIFY:
555         /*
556          * Implicit notify.
557          * Dispatch a DEVICE_WAKE notify to the appropriate handler.
558          * NOTE: the request is queued for execution after this method
559          * completes. The notify handlers are NOT invoked synchronously
560          * from this thread -- because handlers may in turn run other
561          * control methods.
562          *
563          * June 2012: Expand implicit notify mechanism to support
564          * notifies on multiple device objects.
565          */
566         Notify = GpeEventInfo->Dispatch.NotifyList;
567         while (ACPI_SUCCESS (Status) && Notify)
568         {
569             Status = AcpiEvQueueNotifyRequest (
570                 Notify->DeviceNode, ACPI_NOTIFY_DEVICE_WAKE);
571 
572             Notify = Notify->Next;
573         }
574         break;
575 
576     case ACPI_GPE_DISPATCH_METHOD:
577 
578         /* Allocate the evaluation information block */
579 
580         Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
581         if (!Info)
582         {
583             Status = AE_NO_MEMORY;
584         }
585         else
586         {
587             /*
588              * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
589              * _Lxx/_Exx control method that corresponds to this GPE
590              */
591             Info->PrefixNode = GpeEventInfo->Dispatch.MethodNode;
592             Info->Flags = ACPI_IGNORE_RETURN_VALUE;
593 
594             Status = AcpiNsEvaluate (Info);
595             ACPI_FREE (Info);
596         }
597 
598         if (ACPI_FAILURE (Status))
599         {
600             ACPI_EXCEPTION ((AE_INFO, Status,
601                 "while evaluating GPE method [%4.4s]",
602                 AcpiUtGetNodeName (GpeEventInfo->Dispatch.MethodNode)));
603         }
604         break;
605 
606     default:
607 
608         goto ErrorExit; /* Should never happen */
609     }
610 
611     /* Defer enabling of GPE until all notify handlers are done */
612 
613     Status = AcpiOsExecute (OSL_NOTIFY_HANDLER,
614         AcpiEvAsynchEnableGpe, GpeEventInfo);
615     if (ACPI_SUCCESS (Status))
616     {
617         return_VOID;
618     }
619 
620 ErrorExit:
621     AcpiEvAsynchEnableGpe (GpeEventInfo);
622     return_VOID;
623 }
624 
625 
626 /*******************************************************************************
627  *
628  * FUNCTION:    AcpiEvAsynchEnableGpe
629  *
630  * PARAMETERS:  Context (GpeEventInfo) - Info for this GPE
631  *              Callback from AcpiOsExecute
632  *
633  * RETURN:      None
634  *
635  * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
636  *              complete (i.e., finish execution of Notify)
637  *
638  ******************************************************************************/
639 
640 static void ACPI_SYSTEM_XFACE
AcpiEvAsynchEnableGpe(void * Context)641 AcpiEvAsynchEnableGpe (
642     void                    *Context)
643 {
644     ACPI_GPE_EVENT_INFO     *GpeEventInfo = Context;
645     ACPI_CPU_FLAGS          Flags;
646 
647 
648     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
649     (void) AcpiEvFinishGpe (GpeEventInfo);
650     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
651 
652     return;
653 }
654 
655 
656 /*******************************************************************************
657  *
658  * FUNCTION:    AcpiEvFinishGpe
659  *
660  * PARAMETERS:  GpeEventInfo        - Info for this GPE
661  *
662  * RETURN:      Status
663  *
664  * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
665  *              of a GPE method or a synchronous or asynchronous GPE handler.
666  *
667  ******************************************************************************/
668 
669 ACPI_STATUS
AcpiEvFinishGpe(ACPI_GPE_EVENT_INFO * GpeEventInfo)670 AcpiEvFinishGpe (
671     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
672 {
673     ACPI_STATUS             Status;
674 
675 
676     if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
677             ACPI_GPE_LEVEL_TRIGGERED)
678     {
679         /*
680          * GPE is level-triggered, we clear the GPE status bit after
681          * handling the event.
682          */
683         Status = AcpiHwClearGpe (GpeEventInfo);
684         if (ACPI_FAILURE (Status))
685         {
686             return (Status);
687         }
688     }
689 
690     /*
691      * Enable this GPE, conditionally. This means that the GPE will
692      * only be physically enabled if the EnableMask bit is set
693      * in the EventInfo.
694      */
695     (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE);
696     GpeEventInfo->DisableForDispatch = FALSE;
697     return (AE_OK);
698 }
699 
700 
701 /*******************************************************************************
702  *
703  * FUNCTION:    AcpiEvDetectGpe
704  *
705  * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
706  *              GpeEventInfo        - Info for this GPE
707  *              GpeNumber           - Number relative to the parent GPE block
708  *
709  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
710  *
711  * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function
712  *              (e.g. EC) or method (e.g. _Lxx/_Exx) handler.
713  * NOTE:        GPE is W1C, so it is possible to handle a single GPE from both
714  *              task and irq context in parallel as long as the process to
715  *              detect and mask the GPE is atomic.
716  *              However the atomicity of ACPI_GPE_DISPATCH_RAW_HANDLER is
717  *              dependent on the raw handler itself.
718  *
719  ******************************************************************************/
720 
721 UINT32
AcpiEvDetectGpe(ACPI_NAMESPACE_NODE * GpeDevice,ACPI_GPE_EVENT_INFO * GpeEventInfo,UINT32 GpeNumber)722 AcpiEvDetectGpe (
723     ACPI_NAMESPACE_NODE     *GpeDevice,
724     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
725     UINT32                  GpeNumber)
726 {
727     UINT32                  IntStatus = ACPI_INTERRUPT_NOT_HANDLED;
728     UINT8                   EnabledStatusByte;
729     UINT64                  StatusReg;
730     UINT64                  EnableReg;
731     UINT32                  RegisterBit;
732     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo;
733     ACPI_GPE_HANDLER_INFO   *GpeHandlerInfo;
734     ACPI_CPU_FLAGS          Flags;
735     ACPI_STATUS             Status;
736 
737 
738     ACPI_FUNCTION_TRACE (EvGpeDetect);
739 
740 
741     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
742 
743     if (!GpeEventInfo)
744     {
745         GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
746         if (!GpeEventInfo)
747         {
748             goto ErrorExit;
749         }
750     }
751 
752     /* Get the info block for the entire GPE register */
753 
754     GpeRegisterInfo = GpeEventInfo->RegisterInfo;
755 
756     /* Get the register bitmask for this GPE */
757 
758     RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);
759 
760     /* GPE currently enabled (enable bit == 1)? */
761 
762     Status = AcpiHwRead (&EnableReg, &GpeRegisterInfo->EnableAddress);
763     if (ACPI_FAILURE (Status))
764     {
765         goto ErrorExit;
766     }
767 
768     /* GPE currently active (status bit == 1)? */
769 
770     Status = AcpiHwRead (&StatusReg, &GpeRegisterInfo->StatusAddress);
771     if (ACPI_FAILURE (Status))
772     {
773         goto ErrorExit;
774     }
775 
776     /* Check if there is anything active at all in this GPE */
777 
778     ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
779         "Read registers for GPE %02X: Status=%02X, Enable=%02X, "
780         "RunEnable=%02X, WakeEnable=%02X\n",
781         GpeNumber,
782         (UINT32) (StatusReg & RegisterBit),
783         (UINT32) (EnableReg & RegisterBit),
784         GpeRegisterInfo->EnableForRun,
785         GpeRegisterInfo->EnableForWake));
786 
787     EnabledStatusByte = (UINT8) (StatusReg & EnableReg);
788     if (!(EnabledStatusByte & RegisterBit))
789     {
790         goto ErrorExit;
791     }
792 
793     /* Invoke global event handler if present */
794 
795     AcpiGpeCount++;
796     if (AcpiGbl_GlobalEventHandler)
797     {
798         AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_GPE,
799             GpeDevice, GpeNumber,
800             AcpiGbl_GlobalEventHandlerContext);
801     }
802 
803     /* Found an active GPE */
804 
805     if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
806         ACPI_GPE_DISPATCH_RAW_HANDLER)
807     {
808         /* Dispatch the event to a raw handler */
809 
810         GpeHandlerInfo = GpeEventInfo->Dispatch.Handler;
811 
812         /*
813          * There is no protection around the namespace node
814          * and the GPE handler to ensure a safe destruction
815          * because:
816          * 1. The namespace node is expected to always
817          *    exist after loading a table.
818          * 2. The GPE handler is expected to be flushed by
819          *    AcpiOsWaitEventsComplete() before the
820          *    destruction.
821          */
822         AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
823         IntStatus |= GpeHandlerInfo->Address (
824             GpeDevice, GpeNumber, GpeHandlerInfo->Context);
825         Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
826     }
827     else
828     {
829         /* Dispatch the event to a standard handler or method. */
830 
831         IntStatus |= AcpiEvGpeDispatch (GpeDevice,
832             GpeEventInfo, GpeNumber);
833     }
834 
835 ErrorExit:
836     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
837     return (IntStatus);
838 }
839 
840 
841 /*******************************************************************************
842  *
843  * FUNCTION:    AcpiEvGpeDispatch
844  *
845  * PARAMETERS:  GpeDevice           - Device node. NULL for GPE0/GPE1
846  *              GpeEventInfo        - Info for this GPE
847  *              GpeNumber           - Number relative to the parent GPE block
848  *
849  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
850  *
851  * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
852  *              or method (e.g. _Lxx/_Exx) handler.
853  *
854  ******************************************************************************/
855 
856 UINT32
AcpiEvGpeDispatch(ACPI_NAMESPACE_NODE * GpeDevice,ACPI_GPE_EVENT_INFO * GpeEventInfo,UINT32 GpeNumber)857 AcpiEvGpeDispatch (
858     ACPI_NAMESPACE_NODE     *GpeDevice,
859     ACPI_GPE_EVENT_INFO     *GpeEventInfo,
860     UINT32                  GpeNumber)
861 {
862     ACPI_STATUS             Status;
863     UINT32                  ReturnValue;
864 
865 
866     ACPI_FUNCTION_TRACE (EvGpeDispatch);
867 
868 
869     /*
870      * Always disable the GPE so that it does not keep firing before
871      * any asynchronous activity completes (either from the execution
872      * of a GPE method or an asynchronous GPE handler.)
873      *
874      * If there is no handler or method to run, just disable the
875      * GPE and leave it disabled permanently to prevent further such
876      * pointless events from firing.
877      */
878     Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
879     if (ACPI_FAILURE (Status))
880     {
881         ACPI_EXCEPTION ((AE_INFO, Status,
882             "Unable to disable GPE %02X", GpeNumber));
883         return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
884     }
885 
886     /*
887      * If edge-triggered, clear the GPE status bit now. Note that
888      * level-triggered events are cleared after the GPE is serviced.
889      */
890     if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
891             ACPI_GPE_EDGE_TRIGGERED)
892     {
893         Status = AcpiHwClearGpe (GpeEventInfo);
894         if (ACPI_FAILURE (Status))
895         {
896             ACPI_EXCEPTION ((AE_INFO, Status,
897                 "Unable to clear GPE %02X", GpeNumber));
898             (void) AcpiHwLowSetGpe (
899                 GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE);
900             return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED);
901         }
902     }
903 
904     GpeEventInfo->DisableForDispatch = TRUE;
905 
906     /*
907      * Dispatch the GPE to either an installed handler or the control
908      * method associated with this GPE (_Lxx or _Exx). If a handler
909      * exists, we invoke it and do not attempt to run the method.
910      * If there is neither a handler nor a method, leave the GPE
911      * disabled.
912      */
913     switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags))
914     {
915     case ACPI_GPE_DISPATCH_HANDLER:
916 
917         /* Invoke the installed handler (at interrupt level) */
918 
919         ReturnValue = GpeEventInfo->Dispatch.Handler->Address (
920             GpeDevice, GpeNumber,
921             GpeEventInfo->Dispatch.Handler->Context);
922 
923         /* If requested, clear (if level-triggered) and re-enable the GPE */
924 
925         if (ReturnValue & ACPI_REENABLE_GPE)
926         {
927             (void) AcpiEvFinishGpe (GpeEventInfo);
928         }
929         break;
930 
931     case ACPI_GPE_DISPATCH_METHOD:
932     case ACPI_GPE_DISPATCH_NOTIFY:
933         /*
934          * Execute the method associated with the GPE
935          * NOTE: Level-triggered GPEs are cleared after the method completes.
936          */
937         Status = AcpiOsExecute (OSL_GPE_HANDLER,
938             AcpiEvAsynchExecuteGpeMethod, GpeEventInfo);
939         if (ACPI_FAILURE (Status))
940         {
941             ACPI_EXCEPTION ((AE_INFO, Status,
942                 "Unable to queue handler for GPE %02X - event disabled",
943                 GpeNumber));
944         }
945         break;
946 
947     default:
948         /*
949          * No handler or method to run!
950          * 03/2010: This case should no longer be possible. We will not allow
951          * a GPE to be enabled if it has no handler or method.
952          */
953         ACPI_ERROR ((AE_INFO,
954             "No handler or method for GPE %02X, disabling event",
955             GpeNumber));
956         break;
957     }
958 
959     return_UINT32 (ACPI_INTERRUPT_HANDLED);
960 }
961 
962 #endif /* !ACPI_REDUCED_HARDWARE */
963