1 | /****************************************************************************** |
2 | * |
3 | * Module Name: evgpe - General Purpose Event handling and dispatch |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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 MERCHANTIBILITY 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 |
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: Clear a GPE of stale events and enable it. |
122 | * |
123 | ******************************************************************************/ |
124 | |
125 | ACPI_STATUS |
126 | AcpiEvEnableGpe ( |
127 | ACPI_GPE_EVENT_INFO *GpeEventInfo) |
128 | { |
129 | ACPI_STATUS Status; |
130 | |
131 | |
132 | ACPI_FUNCTION_TRACE (EvEnableGpe); |
133 | |
134 | |
135 | /* Clear the GPE (of stale events) */ |
136 | |
137 | Status = AcpiHwClearGpe (GpeEventInfo); |
138 | if (ACPI_FAILURE (Status)) |
139 | { |
140 | return_ACPI_STATUS (Status); |
141 | } |
142 | |
143 | /* Enable the requested GPE */ |
144 | |
145 | Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); |
146 | return_ACPI_STATUS (Status); |
147 | } |
148 | |
149 | |
150 | /******************************************************************************* |
151 | * |
152 | * FUNCTION: AcpiEvMaskGpe |
153 | * |
154 | * PARAMETERS: GpeEventInfo - GPE to be blocked/unblocked |
155 | * IsMasked - Whether the GPE is masked or not |
156 | * |
157 | * RETURN: Status |
158 | * |
159 | * DESCRIPTION: Unconditionally mask/unmask a GPE during runtime. |
160 | * |
161 | ******************************************************************************/ |
162 | |
163 | ACPI_STATUS |
164 | AcpiEvMaskGpe ( |
165 | ACPI_GPE_EVENT_INFO *GpeEventInfo, |
166 | BOOLEAN IsMasked) |
167 | { |
168 | ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; |
169 | UINT32 RegisterBit; |
170 | |
171 | |
172 | ACPI_FUNCTION_TRACE (EvMaskGpe); |
173 | |
174 | |
175 | GpeRegisterInfo = GpeEventInfo->RegisterInfo; |
176 | if (!GpeRegisterInfo) |
177 | { |
178 | return_ACPI_STATUS (AE_NOT_EXIST); |
179 | } |
180 | |
181 | RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); |
182 | |
183 | /* Perform the action */ |
184 | |
185 | if (IsMasked) |
186 | { |
187 | if (RegisterBit & GpeRegisterInfo->MaskForRun) |
188 | { |
189 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
190 | } |
191 | |
192 | (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); |
193 | ACPI_SET_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit); |
194 | } |
195 | else |
196 | { |
197 | if (!(RegisterBit & GpeRegisterInfo->MaskForRun)) |
198 | { |
199 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
200 | } |
201 | |
202 | ACPI_CLEAR_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit); |
203 | if (GpeEventInfo->RuntimeCount && |
204 | !GpeEventInfo->DisableForDispatch) |
205 | { |
206 | (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); |
207 | } |
208 | } |
209 | |
210 | return_ACPI_STATUS (AE_OK); |
211 | } |
212 | |
213 | |
214 | /******************************************************************************* |
215 | * |
216 | * FUNCTION: AcpiEvAddGpeReference |
217 | * |
218 | * PARAMETERS: GpeEventInfo - Add a reference to this GPE |
219 | * |
220 | * RETURN: Status |
221 | * |
222 | * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is |
223 | * hardware-enabled. |
224 | * |
225 | ******************************************************************************/ |
226 | |
227 | ACPI_STATUS |
228 | AcpiEvAddGpeReference ( |
229 | ACPI_GPE_EVENT_INFO *GpeEventInfo) |
230 | { |
231 | ACPI_STATUS Status = AE_OK; |
232 | |
233 | |
234 | ACPI_FUNCTION_TRACE (EvAddGpeReference); |
235 | |
236 | |
237 | if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX) |
238 | { |
239 | return_ACPI_STATUS (AE_LIMIT); |
240 | } |
241 | |
242 | GpeEventInfo->RuntimeCount++; |
243 | if (GpeEventInfo->RuntimeCount == 1) |
244 | { |
245 | /* Enable on first reference */ |
246 | |
247 | Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); |
248 | if (ACPI_SUCCESS (Status)) |
249 | { |
250 | Status = AcpiEvEnableGpe (GpeEventInfo); |
251 | } |
252 | |
253 | if (ACPI_FAILURE (Status)) |
254 | { |
255 | GpeEventInfo->RuntimeCount--; |
256 | } |
257 | } |
258 | |
259 | return_ACPI_STATUS (Status); |
260 | } |
261 | |
262 | |
263 | /******************************************************************************* |
264 | * |
265 | * FUNCTION: AcpiEvRemoveGpeReference |
266 | * |
267 | * PARAMETERS: GpeEventInfo - Remove a reference to this GPE |
268 | * |
269 | * RETURN: Status |
270 | * |
271 | * DESCRIPTION: Remove a reference to a GPE. When the last reference is |
272 | * removed, the GPE is hardware-disabled. |
273 | * |
274 | ******************************************************************************/ |
275 | |
276 | ACPI_STATUS |
277 | AcpiEvRemoveGpeReference ( |
278 | ACPI_GPE_EVENT_INFO *GpeEventInfo) |
279 | { |
280 | ACPI_STATUS Status = AE_OK; |
281 | |
282 | |
283 | ACPI_FUNCTION_TRACE (EvRemoveGpeReference); |
284 | |
285 | |
286 | if (!GpeEventInfo->RuntimeCount) |
287 | { |
288 | return_ACPI_STATUS (AE_LIMIT); |
289 | } |
290 | |
291 | GpeEventInfo->RuntimeCount--; |
292 | if (!GpeEventInfo->RuntimeCount) |
293 | { |
294 | /* Disable on last reference */ |
295 | |
296 | Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); |
297 | if (ACPI_SUCCESS (Status)) |
298 | { |
299 | Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); |
300 | } |
301 | |
302 | if (ACPI_FAILURE (Status)) |
303 | { |
304 | GpeEventInfo->RuntimeCount++; |
305 | } |
306 | } |
307 | |
308 | return_ACPI_STATUS (Status); |
309 | } |
310 | |
311 | |
312 | /******************************************************************************* |
313 | * |
314 | * FUNCTION: AcpiEvLowGetGpeInfo |
315 | * |
316 | * PARAMETERS: GpeNumber - Raw GPE number |
317 | * GpeBlock - A GPE info block |
318 | * |
319 | * RETURN: A GPE EventInfo struct. NULL if not a valid GPE (The GpeNumber |
320 | * is not within the specified GPE block) |
321 | * |
322 | * DESCRIPTION: Returns the EventInfo struct associated with this GPE. This is |
323 | * the low-level implementation of EvGetGpeEventInfo. |
324 | * |
325 | ******************************************************************************/ |
326 | |
327 | ACPI_GPE_EVENT_INFO * |
328 | AcpiEvLowGetGpeInfo ( |
329 | UINT32 GpeNumber, |
330 | ACPI_GPE_BLOCK_INFO *GpeBlock) |
331 | { |
332 | UINT32 GpeIndex; |
333 | |
334 | |
335 | /* |
336 | * Validate that the GpeNumber is within the specified GpeBlock. |
337 | * (Two steps) |
338 | */ |
339 | if (!GpeBlock || |
340 | (GpeNumber < GpeBlock->BlockBaseNumber)) |
341 | { |
342 | return (NULL); |
343 | } |
344 | |
345 | GpeIndex = GpeNumber - GpeBlock->BlockBaseNumber; |
346 | if (GpeIndex >= GpeBlock->GpeCount) |
347 | { |
348 | return (NULL); |
349 | } |
350 | |
351 | return (&GpeBlock->EventInfo[GpeIndex]); |
352 | } |
353 | |
354 | |
355 | /******************************************************************************* |
356 | * |
357 | * FUNCTION: AcpiEvGetGpeEventInfo |
358 | * |
359 | * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 |
360 | * GpeNumber - Raw GPE number |
361 | * |
362 | * RETURN: A GPE EventInfo struct. NULL if not a valid GPE |
363 | * |
364 | * DESCRIPTION: Returns the EventInfo struct associated with this GPE. |
365 | * Validates the GpeBlock and the GpeNumber |
366 | * |
367 | * Should be called only when the GPE lists are semaphore locked |
368 | * and not subject to change. |
369 | * |
370 | ******************************************************************************/ |
371 | |
372 | ACPI_GPE_EVENT_INFO * |
373 | AcpiEvGetGpeEventInfo ( |
374 | ACPI_HANDLE GpeDevice, |
375 | UINT32 GpeNumber) |
376 | { |
377 | ACPI_OPERAND_OBJECT *ObjDesc; |
378 | ACPI_GPE_EVENT_INFO *GpeInfo; |
379 | UINT32 i; |
380 | |
381 | |
382 | ACPI_FUNCTION_ENTRY (); |
383 | |
384 | |
385 | /* A NULL GpeDevice means use the FADT-defined GPE block(s) */ |
386 | |
387 | if (!GpeDevice) |
388 | { |
389 | /* Examine GPE Block 0 and 1 (These blocks are permanent) */ |
390 | |
391 | for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) |
392 | { |
393 | GpeInfo = AcpiEvLowGetGpeInfo (GpeNumber, |
394 | AcpiGbl_GpeFadtBlocks[i]); |
395 | if (GpeInfo) |
396 | { |
397 | return (GpeInfo); |
398 | } |
399 | } |
400 | |
401 | /* The GpeNumber was not in the range of either FADT GPE block */ |
402 | |
403 | return (NULL); |
404 | } |
405 | |
406 | /* A Non-NULL GpeDevice means this is a GPE Block Device */ |
407 | |
408 | ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice); |
409 | if (!ObjDesc || |
410 | !ObjDesc->Device.GpeBlock) |
411 | { |
412 | return (NULL); |
413 | } |
414 | |
415 | return (AcpiEvLowGetGpeInfo (GpeNumber, ObjDesc->Device.GpeBlock)); |
416 | } |
417 | |
418 | |
419 | /******************************************************************************* |
420 | * |
421 | * FUNCTION: AcpiEvGpeDetect |
422 | * |
423 | * PARAMETERS: GpeXruptList - Interrupt block for this interrupt. |
424 | * Can have multiple GPE blocks attached. |
425 | * |
426 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
427 | * |
428 | * DESCRIPTION: Detect if any GP events have occurred. This function is |
429 | * executed at interrupt level. |
430 | * |
431 | ******************************************************************************/ |
432 | |
433 | UINT32 |
434 | AcpiEvGpeDetect ( |
435 | ACPI_GPE_XRUPT_INFO *GpeXruptList) |
436 | { |
437 | ACPI_STATUS Status; |
438 | ACPI_GPE_BLOCK_INFO *GpeBlock; |
439 | ACPI_NAMESPACE_NODE *GpeDevice; |
440 | ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; |
441 | ACPI_GPE_EVENT_INFO *GpeEventInfo; |
442 | UINT32 GpeNumber; |
443 | ACPI_GPE_HANDLER_INFO *GpeHandlerInfo; |
444 | UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; |
445 | UINT8 EnabledStatusByte; |
446 | UINT32 StatusReg; |
447 | UINT32 EnableReg; |
448 | ACPI_CPU_FLAGS Flags; |
449 | UINT32 i; |
450 | UINT32 j; |
451 | |
452 | |
453 | ACPI_FUNCTION_NAME (EvGpeDetect); |
454 | |
455 | /* Check for the case where there are no GPEs */ |
456 | |
457 | if (!GpeXruptList) |
458 | { |
459 | return (IntStatus); |
460 | } |
461 | |
462 | /* |
463 | * We need to obtain the GPE lock for both the data structs and registers |
464 | * Note: Not necessary to obtain the hardware lock, since the GPE |
465 | * registers are owned by the GpeLock. |
466 | */ |
467 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
468 | |
469 | /* Examine all GPE blocks attached to this interrupt level */ |
470 | |
471 | GpeBlock = GpeXruptList->GpeBlockListHead; |
472 | while (GpeBlock) |
473 | { |
474 | GpeDevice = GpeBlock->Node; |
475 | |
476 | /* |
477 | * Read all of the 8-bit GPE status and enable registers in this GPE |
478 | * block, saving all of them. Find all currently active GP events. |
479 | */ |
480 | for (i = 0; i < GpeBlock->RegisterCount; i++) |
481 | { |
482 | /* Get the next status/enable pair */ |
483 | |
484 | GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; |
485 | |
486 | /* |
487 | * Optimization: If there are no GPEs enabled within this |
488 | * register, we can safely ignore the entire register. |
489 | */ |
490 | if (!(GpeRegisterInfo->EnableForRun | |
491 | GpeRegisterInfo->EnableForWake)) |
492 | { |
493 | ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, |
494 | "Ignore disabled registers for GPE %02X-%02X: " |
495 | "RunEnable=%02X, WakeEnable=%02X\n" , |
496 | GpeRegisterInfo->BaseGpeNumber, |
497 | GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), |
498 | GpeRegisterInfo->EnableForRun, |
499 | GpeRegisterInfo->EnableForWake)); |
500 | continue; |
501 | } |
502 | |
503 | /* Read the Status Register */ |
504 | |
505 | Status = AcpiHwRead (&StatusReg, &GpeRegisterInfo->StatusAddress); |
506 | if (ACPI_FAILURE (Status)) |
507 | { |
508 | goto UnlockAndExit; |
509 | } |
510 | |
511 | /* Read the Enable Register */ |
512 | |
513 | Status = AcpiHwRead (&EnableReg, &GpeRegisterInfo->EnableAddress); |
514 | if (ACPI_FAILURE (Status)) |
515 | { |
516 | goto UnlockAndExit; |
517 | } |
518 | |
519 | ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, |
520 | "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, " |
521 | "RunEnable=%02X, WakeEnable=%02X\n" , |
522 | GpeRegisterInfo->BaseGpeNumber, |
523 | GpeRegisterInfo->BaseGpeNumber + (ACPI_GPE_REGISTER_WIDTH - 1), |
524 | StatusReg, EnableReg, |
525 | GpeRegisterInfo->EnableForRun, |
526 | GpeRegisterInfo->EnableForWake)); |
527 | |
528 | /* Check if there is anything active at all in this register */ |
529 | |
530 | EnabledStatusByte = (UINT8) (StatusReg & EnableReg); |
531 | if (!EnabledStatusByte) |
532 | { |
533 | /* No active GPEs in this register, move on */ |
534 | |
535 | continue; |
536 | } |
537 | |
538 | /* Now look at the individual GPEs in this byte register */ |
539 | |
540 | for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) |
541 | { |
542 | /* Examine one GPE bit */ |
543 | |
544 | GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * |
545 | ACPI_GPE_REGISTER_WIDTH) + j]; |
546 | GpeNumber = j + GpeRegisterInfo->BaseGpeNumber; |
547 | |
548 | if (EnabledStatusByte & (1 << j)) |
549 | { |
550 | /* Invoke global event handler if present */ |
551 | |
552 | AcpiGpeCount++; |
553 | if (AcpiGbl_GlobalEventHandler) |
554 | { |
555 | AcpiGbl_GlobalEventHandler (ACPI_EVENT_TYPE_GPE, |
556 | GpeDevice, GpeNumber, |
557 | AcpiGbl_GlobalEventHandlerContext); |
558 | } |
559 | |
560 | /* Found an active GPE */ |
561 | |
562 | if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == |
563 | ACPI_GPE_DISPATCH_RAW_HANDLER) |
564 | { |
565 | /* Dispatch the event to a raw handler */ |
566 | |
567 | GpeHandlerInfo = GpeEventInfo->Dispatch.Handler; |
568 | |
569 | /* |
570 | * There is no protection around the namespace node |
571 | * and the GPE handler to ensure a safe destruction |
572 | * because: |
573 | * 1. The namespace node is expected to always |
574 | * exist after loading a table. |
575 | * 2. The GPE handler is expected to be flushed by |
576 | * AcpiOsWaitEventsComplete() before the |
577 | * destruction. |
578 | */ |
579 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
580 | IntStatus |= GpeHandlerInfo->Address ( |
581 | GpeDevice, GpeNumber, GpeHandlerInfo->Context); |
582 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
583 | } |
584 | else |
585 | { |
586 | /* |
587 | * Dispatch the event to a standard handler or |
588 | * method. |
589 | */ |
590 | IntStatus |= AcpiEvGpeDispatch (GpeDevice, |
591 | GpeEventInfo, GpeNumber); |
592 | } |
593 | } |
594 | } |
595 | } |
596 | |
597 | GpeBlock = GpeBlock->Next; |
598 | } |
599 | |
600 | UnlockAndExit: |
601 | |
602 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
603 | return (IntStatus); |
604 | } |
605 | |
606 | |
607 | /******************************************************************************* |
608 | * |
609 | * FUNCTION: AcpiEvAsynchExecuteGpeMethod |
610 | * |
611 | * PARAMETERS: Context (GpeEventInfo) - Info for this GPE |
612 | * |
613 | * RETURN: None |
614 | * |
615 | * DESCRIPTION: Perform the actual execution of a GPE control method. This |
616 | * function is called from an invocation of AcpiOsExecute and |
617 | * therefore does NOT execute at interrupt level - so that |
618 | * the control method itself is not executed in the context of |
619 | * an interrupt handler. |
620 | * |
621 | ******************************************************************************/ |
622 | |
623 | static void ACPI_SYSTEM_XFACE |
624 | AcpiEvAsynchExecuteGpeMethod ( |
625 | void *Context) |
626 | { |
627 | ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; |
628 | ACPI_STATUS Status = AE_OK; |
629 | ACPI_EVALUATE_INFO *Info; |
630 | ACPI_GPE_NOTIFY_INFO *Notify; |
631 | |
632 | |
633 | ACPI_FUNCTION_TRACE (EvAsynchExecuteGpeMethod); |
634 | |
635 | |
636 | /* Do the correct dispatch - normal method or implicit notify */ |
637 | |
638 | switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) |
639 | { |
640 | case ACPI_GPE_DISPATCH_NOTIFY: |
641 | /* |
642 | * Implicit notify. |
643 | * Dispatch a DEVICE_WAKE notify to the appropriate handler. |
644 | * NOTE: the request is queued for execution after this method |
645 | * completes. The notify handlers are NOT invoked synchronously |
646 | * from this thread -- because handlers may in turn run other |
647 | * control methods. |
648 | * |
649 | * June 2012: Expand implicit notify mechanism to support |
650 | * notifies on multiple device objects. |
651 | */ |
652 | Notify = GpeEventInfo->Dispatch.NotifyList; |
653 | while (ACPI_SUCCESS (Status) && Notify) |
654 | { |
655 | Status = AcpiEvQueueNotifyRequest ( |
656 | Notify->DeviceNode, ACPI_NOTIFY_DEVICE_WAKE); |
657 | |
658 | Notify = Notify->Next; |
659 | } |
660 | break; |
661 | |
662 | case ACPI_GPE_DISPATCH_METHOD: |
663 | |
664 | /* Allocate the evaluation information block */ |
665 | |
666 | Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); |
667 | if (!Info) |
668 | { |
669 | Status = AE_NO_MEMORY; |
670 | } |
671 | else |
672 | { |
673 | /* |
674 | * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the |
675 | * _Lxx/_Exx control method that corresponds to this GPE |
676 | */ |
677 | Info->PrefixNode = GpeEventInfo->Dispatch.MethodNode; |
678 | Info->Flags = ACPI_IGNORE_RETURN_VALUE; |
679 | |
680 | Status = AcpiNsEvaluate (Info); |
681 | ACPI_FREE (Info); |
682 | } |
683 | |
684 | if (ACPI_FAILURE (Status)) |
685 | { |
686 | ACPI_EXCEPTION ((AE_INFO, Status, |
687 | "while evaluating GPE method [%4.4s]" , |
688 | AcpiUtGetNodeName (GpeEventInfo->Dispatch.MethodNode))); |
689 | } |
690 | break; |
691 | |
692 | default: |
693 | |
694 | goto ErrorExit; /* Should never happen */ |
695 | } |
696 | |
697 | /* Defer enabling of GPE until all notify handlers are done */ |
698 | |
699 | Status = AcpiOsExecute (OSL_NOTIFY_HANDLER, |
700 | AcpiEvAsynchEnableGpe, GpeEventInfo); |
701 | if (ACPI_SUCCESS (Status)) |
702 | { |
703 | return_VOID; |
704 | } |
705 | |
706 | ErrorExit: |
707 | AcpiEvAsynchEnableGpe (GpeEventInfo); |
708 | return_VOID; |
709 | } |
710 | |
711 | |
712 | /******************************************************************************* |
713 | * |
714 | * FUNCTION: AcpiEvAsynchEnableGpe |
715 | * |
716 | * PARAMETERS: Context (GpeEventInfo) - Info for this GPE |
717 | * Callback from AcpiOsExecute |
718 | * |
719 | * RETURN: None |
720 | * |
721 | * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to |
722 | * complete (i.e., finish execution of Notify) |
723 | * |
724 | ******************************************************************************/ |
725 | |
726 | static void ACPI_SYSTEM_XFACE |
727 | AcpiEvAsynchEnableGpe ( |
728 | void *Context) |
729 | { |
730 | ACPI_GPE_EVENT_INFO *GpeEventInfo = Context; |
731 | ACPI_CPU_FLAGS Flags; |
732 | |
733 | |
734 | Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); |
735 | (void) AcpiEvFinishGpe (GpeEventInfo); |
736 | AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); |
737 | |
738 | return; |
739 | } |
740 | |
741 | |
742 | /******************************************************************************* |
743 | * |
744 | * FUNCTION: AcpiEvFinishGpe |
745 | * |
746 | * PARAMETERS: GpeEventInfo - Info for this GPE |
747 | * |
748 | * RETURN: Status |
749 | * |
750 | * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution |
751 | * of a GPE method or a synchronous or asynchronous GPE handler. |
752 | * |
753 | ******************************************************************************/ |
754 | |
755 | ACPI_STATUS |
756 | AcpiEvFinishGpe ( |
757 | ACPI_GPE_EVENT_INFO *GpeEventInfo) |
758 | { |
759 | ACPI_STATUS Status; |
760 | |
761 | |
762 | if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == |
763 | ACPI_GPE_LEVEL_TRIGGERED) |
764 | { |
765 | /* |
766 | * GPE is level-triggered, we clear the GPE status bit after |
767 | * handling the event. |
768 | */ |
769 | Status = AcpiHwClearGpe (GpeEventInfo); |
770 | if (ACPI_FAILURE (Status)) |
771 | { |
772 | return (Status); |
773 | } |
774 | } |
775 | |
776 | /* |
777 | * Enable this GPE, conditionally. This means that the GPE will |
778 | * only be physically enabled if the EnableMask bit is set |
779 | * in the EventInfo. |
780 | */ |
781 | (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); |
782 | GpeEventInfo->DisableForDispatch = FALSE; |
783 | return (AE_OK); |
784 | } |
785 | |
786 | |
787 | /******************************************************************************* |
788 | * |
789 | * FUNCTION: AcpiEvGpeDispatch |
790 | * |
791 | * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 |
792 | * GpeEventInfo - Info for this GPE |
793 | * GpeNumber - Number relative to the parent GPE block |
794 | * |
795 | * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED |
796 | * |
797 | * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) |
798 | * or method (e.g. _Lxx/_Exx) handler. |
799 | * |
800 | * This function executes at interrupt level. |
801 | * |
802 | ******************************************************************************/ |
803 | |
804 | UINT32 |
805 | AcpiEvGpeDispatch ( |
806 | ACPI_NAMESPACE_NODE *GpeDevice, |
807 | ACPI_GPE_EVENT_INFO *GpeEventInfo, |
808 | UINT32 GpeNumber) |
809 | { |
810 | ACPI_STATUS Status; |
811 | UINT32 ReturnValue; |
812 | |
813 | |
814 | ACPI_FUNCTION_TRACE (EvGpeDispatch); |
815 | |
816 | |
817 | /* |
818 | * Always disable the GPE so that it does not keep firing before |
819 | * any asynchronous activity completes (either from the execution |
820 | * of a GPE method or an asynchronous GPE handler.) |
821 | * |
822 | * If there is no handler or method to run, just disable the |
823 | * GPE and leave it disabled permanently to prevent further such |
824 | * pointless events from firing. |
825 | */ |
826 | Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); |
827 | if (ACPI_FAILURE (Status)) |
828 | { |
829 | ACPI_EXCEPTION ((AE_INFO, Status, |
830 | "Unable to disable GPE %02X" , GpeNumber)); |
831 | return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); |
832 | } |
833 | |
834 | /* |
835 | * If edge-triggered, clear the GPE status bit now. Note that |
836 | * level-triggered events are cleared after the GPE is serviced. |
837 | */ |
838 | if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == |
839 | ACPI_GPE_EDGE_TRIGGERED) |
840 | { |
841 | Status = AcpiHwClearGpe (GpeEventInfo); |
842 | if (ACPI_FAILURE (Status)) |
843 | { |
844 | ACPI_EXCEPTION ((AE_INFO, Status, |
845 | "Unable to clear GPE %02X" , GpeNumber)); |
846 | (void) AcpiHwLowSetGpe ( |
847 | GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); |
848 | return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); |
849 | } |
850 | } |
851 | |
852 | GpeEventInfo->DisableForDispatch = TRUE; |
853 | |
854 | /* |
855 | * Dispatch the GPE to either an installed handler or the control |
856 | * method associated with this GPE (_Lxx or _Exx). If a handler |
857 | * exists, we invoke it and do not attempt to run the method. |
858 | * If there is neither a handler nor a method, leave the GPE |
859 | * disabled. |
860 | */ |
861 | switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) |
862 | { |
863 | case ACPI_GPE_DISPATCH_HANDLER: |
864 | |
865 | /* Invoke the installed handler (at interrupt level) */ |
866 | |
867 | ReturnValue = GpeEventInfo->Dispatch.Handler->Address ( |
868 | GpeDevice, GpeNumber, |
869 | GpeEventInfo->Dispatch.Handler->Context); |
870 | |
871 | /* If requested, clear (if level-triggered) and reenable the GPE */ |
872 | |
873 | if (ReturnValue & ACPI_REENABLE_GPE) |
874 | { |
875 | (void) AcpiEvFinishGpe (GpeEventInfo); |
876 | } |
877 | break; |
878 | |
879 | case ACPI_GPE_DISPATCH_METHOD: |
880 | case ACPI_GPE_DISPATCH_NOTIFY: |
881 | /* |
882 | * Execute the method associated with the GPE |
883 | * NOTE: Level-triggered GPEs are cleared after the method completes. |
884 | */ |
885 | Status = AcpiOsExecute (OSL_GPE_HANDLER, |
886 | AcpiEvAsynchExecuteGpeMethod, GpeEventInfo); |
887 | if (ACPI_FAILURE (Status)) |
888 | { |
889 | ACPI_EXCEPTION ((AE_INFO, Status, |
890 | "Unable to queue handler for GPE %02X - event disabled" , |
891 | GpeNumber)); |
892 | } |
893 | break; |
894 | |
895 | default: |
896 | /* |
897 | * No handler or method to run! |
898 | * 03/2010: This case should no longer be possible. We will not allow |
899 | * a GPE to be enabled if it has no handler or method. |
900 | */ |
901 | ACPI_ERROR ((AE_INFO, |
902 | "No handler or method for GPE %02X, disabling event" , |
903 | GpeNumber)); |
904 | break; |
905 | } |
906 | |
907 | return_UINT32 (ACPI_INTERRUPT_HANDLED); |
908 | } |
909 | |
910 | #endif /* !ACPI_REDUCED_HARDWARE */ |
911 | |