1 /******************************************************************************
3 * Module Name: evgpeutil - GPE utilities
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, 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: AcpiEvGetGpeDevice
120 * PARAMETERS: GPE_WALK_CALLBACK
124 * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE
125 * block device. NULL if the GPE is one of the FADT-defined GPEs.
127 ******************************************************************************/
131 ACPI_GPE_XRUPT_INFO
*GpeXruptInfo
,
132 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
135 ACPI_GPE_DEVICE_INFO
*Info
= Context
;
138 /* Increment Index by the number of GPEs in this block */
140 Info
->NextBlockBaseIndex
+= GpeBlock
->GpeCount
;
142 if (Info
->Index
< Info
->NextBlockBaseIndex
)
145 * The GPE index is within this block, get the node. Leave the node
146 * NULL for the FADT-defined GPEs
148 if ((GpeBlock
->Node
)->Type
== ACPI_TYPE_DEVICE
)
150 Info
->GpeDevice
= GpeBlock
->Node
;
153 Info
->Status
= AE_OK
;
154 return (AE_CTRL_END
);
161 /*******************************************************************************
163 * FUNCTION: AcpiEvGetGpeXruptBlock
165 * PARAMETERS: InterruptNumber - Interrupt for a GPE block
166 * GpeXruptBlock - Where the block is returned
170 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
171 * block per unique interrupt level used for GPEs. Should be
172 * called only when the GPE lists are semaphore locked and not
175 ******************************************************************************/
178 AcpiEvGetGpeXruptBlock (
179 UINT32 InterruptNumber
,
180 ACPI_GPE_XRUPT_INFO
**GpeXruptBlock
)
182 ACPI_GPE_XRUPT_INFO
*NextGpeXrupt
;
183 ACPI_GPE_XRUPT_INFO
*GpeXrupt
;
185 ACPI_CPU_FLAGS Flags
;
188 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock
);
191 /* No need for lock since we are not changing any list elements here */
193 NextGpeXrupt
= AcpiGbl_GpeXruptListHead
;
196 if (NextGpeXrupt
->InterruptNumber
== InterruptNumber
)
198 *GpeXruptBlock
= NextGpeXrupt
;
199 return_ACPI_STATUS (AE_OK
);
202 NextGpeXrupt
= NextGpeXrupt
->Next
;
205 /* Not found, must allocate a new xrupt descriptor */
207 GpeXrupt
= ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO
));
210 return_ACPI_STATUS (AE_NO_MEMORY
);
213 GpeXrupt
->InterruptNumber
= InterruptNumber
;
215 /* Install new interrupt descriptor with spin lock */
217 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
218 if (AcpiGbl_GpeXruptListHead
)
220 NextGpeXrupt
= AcpiGbl_GpeXruptListHead
;
221 while (NextGpeXrupt
->Next
)
223 NextGpeXrupt
= NextGpeXrupt
->Next
;
226 NextGpeXrupt
->Next
= GpeXrupt
;
227 GpeXrupt
->Previous
= NextGpeXrupt
;
231 AcpiGbl_GpeXruptListHead
= GpeXrupt
;
234 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
236 /* Install new interrupt handler if not SCI_INT */
238 if (InterruptNumber
!= AcpiGbl_FADT
.SciInterrupt
)
240 Status
= AcpiOsInstallInterruptHandler (InterruptNumber
,
241 AcpiEvGpeXruptHandler
, GpeXrupt
);
242 if (ACPI_FAILURE (Status
))
244 ACPI_EXCEPTION ((AE_INFO
, Status
,
245 "Could not install GPE interrupt handler at level 0x%X",
247 return_ACPI_STATUS (Status
);
251 *GpeXruptBlock
= GpeXrupt
;
252 return_ACPI_STATUS (AE_OK
);
256 /*******************************************************************************
258 * FUNCTION: AcpiEvDeleteGpeXrupt
260 * PARAMETERS: GpeXrupt - A GPE interrupt info block
264 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
265 * interrupt handler if not the SCI interrupt.
267 ******************************************************************************/
270 AcpiEvDeleteGpeXrupt (
271 ACPI_GPE_XRUPT_INFO
*GpeXrupt
)
274 ACPI_CPU_FLAGS Flags
;
277 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt
);
280 /* We never want to remove the SCI interrupt handler */
282 if (GpeXrupt
->InterruptNumber
== AcpiGbl_FADT
.SciInterrupt
)
284 GpeXrupt
->GpeBlockListHead
= NULL
;
285 return_ACPI_STATUS (AE_OK
);
288 /* Disable this interrupt */
290 Status
= AcpiOsRemoveInterruptHandler (
291 GpeXrupt
->InterruptNumber
, AcpiEvGpeXruptHandler
);
292 if (ACPI_FAILURE (Status
))
294 return_ACPI_STATUS (Status
);
297 /* Unlink the interrupt block with lock */
299 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
300 if (GpeXrupt
->Previous
)
302 GpeXrupt
->Previous
->Next
= GpeXrupt
->Next
;
306 /* No previous, update list head */
308 AcpiGbl_GpeXruptListHead
= GpeXrupt
->Next
;
313 GpeXrupt
->Next
->Previous
= GpeXrupt
->Previous
;
315 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
319 ACPI_FREE (GpeXrupt
);
320 return_ACPI_STATUS (AE_OK
);
324 /*******************************************************************************
326 * FUNCTION: AcpiEvDeleteGpeHandlers
328 * PARAMETERS: GpeXruptInfo - GPE Interrupt info
329 * GpeBlock - Gpe Block info
333 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
334 * Used only prior to termination.
336 ******************************************************************************/
339 AcpiEvDeleteGpeHandlers (
340 ACPI_GPE_XRUPT_INFO
*GpeXruptInfo
,
341 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
344 ACPI_GPE_EVENT_INFO
*GpeEventInfo
;
345 ACPI_GPE_NOTIFY_INFO
*Notify
;
346 ACPI_GPE_NOTIFY_INFO
*Next
;
351 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers
);
354 /* Examine each GPE Register within the block */
356 for (i
= 0; i
< GpeBlock
->RegisterCount
; i
++)
358 /* Now look at the individual GPEs in this byte register */
360 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++)
362 GpeEventInfo
= &GpeBlock
->EventInfo
[((ACPI_SIZE
) i
*
363 ACPI_GPE_REGISTER_WIDTH
) + j
];
365 if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) ==
366 ACPI_GPE_DISPATCH_HANDLER
) ||
367 (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) ==
368 ACPI_GPE_DISPATCH_RAW_HANDLER
))
370 /* Delete an installed handler block */
372 ACPI_FREE (GpeEventInfo
->Dispatch
.Handler
);
373 GpeEventInfo
->Dispatch
.Handler
= NULL
;
374 GpeEventInfo
->Flags
&= ~ACPI_GPE_DISPATCH_MASK
;
376 else if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) ==
377 ACPI_GPE_DISPATCH_NOTIFY
)
379 /* Delete the implicit notification device list */
381 Notify
= GpeEventInfo
->Dispatch
.NotifyList
;
389 GpeEventInfo
->Dispatch
.NotifyList
= NULL
;
390 GpeEventInfo
->Flags
&= ~ACPI_GPE_DISPATCH_MASK
;
395 return_ACPI_STATUS (AE_OK
);
398 #endif /* !ACPI_REDUCED_HARDWARE */