1 /******************************************************************************
3 * Module Name: evgpeutil - GPE utilities
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2014, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
48 #define _COMPONENT ACPI_EVENTS
49 ACPI_MODULE_NAME ("evgpeutil")
52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53 /*******************************************************************************
55 * FUNCTION: AcpiEvWalkGpeList
57 * PARAMETERS: GpeWalkCallback - Routine called for each GPE block
58 * Context - Value passed to callback
62 * DESCRIPTION: Walk the GPE lists.
64 ******************************************************************************/
68 ACPI_GPE_CALLBACK GpeWalkCallback,
71 ACPI_GPE_BLOCK_INFO *GpeBlock;
72 ACPI_GPE_XRUPT_INFO *GpeXruptInfo;
73 ACPI_STATUS Status = AE_OK;
77 ACPI_FUNCTION_TRACE (EvWalkGpeList);
80 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
82 /* Walk the interrupt level descriptor list */
84 GpeXruptInfo = AcpiGbl_GpeXruptListHead;
87 /* Walk all Gpe Blocks attached to this interrupt level */
89 GpeBlock = GpeXruptInfo->GpeBlockListHead;
92 /* One callback per GPE block */
94 Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context);
95 if (ACPI_FAILURE (Status))
97 if (Status == AE_CTRL_END) /* Callback abort */
104 GpeBlock = GpeBlock->Next;
107 GpeXruptInfo = GpeXruptInfo->Next;
111 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
112 return_ACPI_STATUS (Status);
116 /*******************************************************************************
118 * FUNCTION: AcpiEvValidGpeEvent
120 * PARAMETERS: GpeEventInfo - Info for this GPE
122 * RETURN: TRUE if the GpeEvent is valid
124 * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.
125 * Should be called only when the GPE lists are semaphore locked
126 * and not subject to change.
128 ******************************************************************************/
131 AcpiEvValidGpeEvent (
132 ACPI_GPE_EVENT_INFO *GpeEventInfo)
134 ACPI_GPE_XRUPT_INFO *GpeXruptBlock;
135 ACPI_GPE_BLOCK_INFO *GpeBlock;
138 ACPI_FUNCTION_ENTRY ();
141 /* No need for spin lock since we are not changing any list elements */
143 /* Walk the GPE interrupt levels */
145 GpeXruptBlock = AcpiGbl_GpeXruptListHead;
146 while (GpeXruptBlock)
148 GpeBlock = GpeXruptBlock->GpeBlockListHead;
150 /* Walk the GPE blocks on this interrupt level */
154 if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) &&
155 (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo))
160 GpeBlock = GpeBlock->Next;
163 GpeXruptBlock = GpeXruptBlock->Next;
170 /*******************************************************************************
172 * FUNCTION: AcpiEvGetGpeDevice
174 * PARAMETERS: GPE_WALK_CALLBACK
178 * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE
179 * block device. NULL if the GPE is one of the FADT-defined GPEs.
181 ******************************************************************************/
185 ACPI_GPE_XRUPT_INFO *GpeXruptInfo,
186 ACPI_GPE_BLOCK_INFO *GpeBlock,
189 ACPI_GPE_DEVICE_INFO *Info = Context;
192 /* Increment Index by the number of GPEs in this block */
194 Info->NextBlockBaseIndex += GpeBlock->GpeCount;
196 if (Info->Index < Info->NextBlockBaseIndex)
199 * The GPE index is within this block, get the node. Leave the node
200 * NULL for the FADT-defined GPEs
202 if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE)
204 Info->GpeDevice = GpeBlock->Node;
207 Info->Status = AE_OK;
208 return (AE_CTRL_END);
215 /*******************************************************************************
217 * FUNCTION: AcpiEvGetGpeXruptBlock
219 * PARAMETERS: InterruptNumber - Interrupt for a GPE block
220 * GpeXruptBlock - Where the block is returned
224 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
225 * block per unique interrupt level used for GPEs. Should be
226 * called only when the GPE lists are semaphore locked and not
229 ******************************************************************************/
232 AcpiEvGetGpeXruptBlock (
233 UINT32 InterruptNumber,
234 ACPI_GPE_XRUPT_INFO **GpeXruptBlock)
236 ACPI_GPE_XRUPT_INFO *NextGpeXrupt;
237 ACPI_GPE_XRUPT_INFO *GpeXrupt;
239 ACPI_CPU_FLAGS Flags;
242 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock);
245 /* No need for lock since we are not changing any list elements here */
247 NextGpeXrupt = AcpiGbl_GpeXruptListHead;
250 if (NextGpeXrupt->InterruptNumber == InterruptNumber)
252 *GpeXruptBlock = NextGpeXrupt;
253 return_ACPI_STATUS (AE_OK);
256 NextGpeXrupt = NextGpeXrupt->Next;
259 /* Not found, must allocate a new xrupt descriptor */
261 GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO));
264 return_ACPI_STATUS (AE_NO_MEMORY);
267 GpeXrupt->InterruptNumber = InterruptNumber;
269 /* Install new interrupt descriptor with spin lock */
271 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
272 if (AcpiGbl_GpeXruptListHead)
274 NextGpeXrupt = AcpiGbl_GpeXruptListHead;
275 while (NextGpeXrupt->Next)
277 NextGpeXrupt = NextGpeXrupt->Next;
280 NextGpeXrupt->Next = GpeXrupt;
281 GpeXrupt->Previous = NextGpeXrupt;
285 AcpiGbl_GpeXruptListHead = GpeXrupt;
288 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
290 /* Install new interrupt handler if not SCI_INT */
292 if (InterruptNumber != AcpiGbl_FADT.SciInterrupt)
294 Status = AcpiOsInstallInterruptHandler (InterruptNumber,
295 AcpiEvGpeXruptHandler, GpeXrupt);
296 if (ACPI_FAILURE (Status))
298 ACPI_EXCEPTION ((AE_INFO, Status,
299 "Could not install GPE interrupt handler at level 0x%X",
301 return_ACPI_STATUS (Status);
305 *GpeXruptBlock = GpeXrupt;
306 return_ACPI_STATUS (AE_OK);
310 /*******************************************************************************
312 * FUNCTION: AcpiEvDeleteGpeXrupt
314 * PARAMETERS: GpeXrupt - A GPE interrupt info block
318 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
319 * interrupt handler if not the SCI interrupt.
321 ******************************************************************************/
324 AcpiEvDeleteGpeXrupt (
325 ACPI_GPE_XRUPT_INFO *GpeXrupt)
328 ACPI_CPU_FLAGS Flags;
331 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt);
334 /* We never want to remove the SCI interrupt handler */
336 if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt)
338 GpeXrupt->GpeBlockListHead = NULL;
339 return_ACPI_STATUS (AE_OK);
342 /* Disable this interrupt */
344 Status = AcpiOsRemoveInterruptHandler (
345 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler);
346 if (ACPI_FAILURE (Status))
348 return_ACPI_STATUS (Status);
351 /* Unlink the interrupt block with lock */
353 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
354 if (GpeXrupt->Previous)
356 GpeXrupt->Previous->Next = GpeXrupt->Next;
360 /* No previous, update list head */
362 AcpiGbl_GpeXruptListHead = GpeXrupt->Next;
367 GpeXrupt->Next->Previous = GpeXrupt->Previous;
369 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
373 ACPI_FREE (GpeXrupt);
374 return_ACPI_STATUS (AE_OK);
378 /*******************************************************************************
380 * FUNCTION: AcpiEvDeleteGpeHandlers
382 * PARAMETERS: GpeXruptInfo - GPE Interrupt info
383 * GpeBlock - Gpe Block info
387 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
388 * Used only prior to termination.
390 ******************************************************************************/
393 AcpiEvDeleteGpeHandlers (
394 ACPI_GPE_XRUPT_INFO *GpeXruptInfo,
395 ACPI_GPE_BLOCK_INFO *GpeBlock,
398 ACPI_GPE_EVENT_INFO *GpeEventInfo;
399 ACPI_GPE_NOTIFY_INFO *Notify;
400 ACPI_GPE_NOTIFY_INFO *Next;
405 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
408 /* Examine each GPE Register within the block */
410 for (i = 0; i < GpeBlock->RegisterCount; i++)
412 /* Now look at the individual GPEs in this byte register */
414 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
416 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
417 ACPI_GPE_REGISTER_WIDTH) + j];
419 if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
420 ACPI_GPE_DISPATCH_HANDLER)
422 /* Delete an installed handler block */
424 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
425 GpeEventInfo->Dispatch.Handler = NULL;
426 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
428 else if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
429 ACPI_GPE_DISPATCH_NOTIFY)
431 /* Delete the implicit notification device list */
433 Notify = GpeEventInfo->Dispatch.NotifyList;
440 GpeEventInfo->Dispatch.NotifyList = NULL;
441 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
446 return_ACPI_STATUS (AE_OK);
449 #endif /* !ACPI_REDUCED_HARDWARE */