1 /******************************************************************************
2 *
3 * Module Name: evgpeutil - GPE utilities
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
48 #define _COMPONENT ACPI_EVENTS
49 ACPI_MODULE_NAME ("evgpeutil")
50
51
52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53 /*******************************************************************************
54 *
55 * FUNCTION: AcpiEvWalkGpeList
56 *
57 * PARAMETERS: GpeWalkCallback - Routine called for each GPE block
58 * Context - Value passed to callback
59 *
60 * RETURN: Status
61 *
62 * DESCRIPTION: Walk the GPE lists.
63 *
64 ******************************************************************************/
65
66 ACPI_STATUS
AcpiEvWalkGpeList(ACPI_GPE_CALLBACK GpeWalkCallback,void * Context)67 AcpiEvWalkGpeList (
68 ACPI_GPE_CALLBACK GpeWalkCallback,
69 void *Context)
70 {
71 ACPI_GPE_BLOCK_INFO *GpeBlock;
72 ACPI_GPE_XRUPT_INFO *GpeXruptInfo;
73 ACPI_STATUS Status = AE_OK;
74 ACPI_CPU_FLAGS Flags;
75
76
77 ACPI_FUNCTION_TRACE (EvWalkGpeList);
78
79
80 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
81
82 /* Walk the interrupt level descriptor list */
83
84 GpeXruptInfo = AcpiGbl_GpeXruptListHead;
85 while (GpeXruptInfo)
86 {
87 /* Walk all Gpe Blocks attached to this interrupt level */
88
89 GpeBlock = GpeXruptInfo->GpeBlockListHead;
90 while (GpeBlock)
91 {
92 /* One callback per GPE block */
93
94 Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context);
95 if (ACPI_FAILURE (Status))
96 {
97 if (Status == AE_CTRL_END) /* Callback abort */
98 {
99 Status = AE_OK;
100 }
101 goto UnlockAndExit;
102 }
103
104 GpeBlock = GpeBlock->Next;
105 }
106
107 GpeXruptInfo = GpeXruptInfo->Next;
108 }
109
110 UnlockAndExit:
111 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
112 return_ACPI_STATUS (Status);
113 }
114
115
116 /*******************************************************************************
117 *
118 * FUNCTION: AcpiEvGetGpeDevice
119 *
120 * PARAMETERS: GPE_WALK_CALLBACK
121 *
122 * RETURN: Status
123 *
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.
126 *
127 ******************************************************************************/
128
129 ACPI_STATUS
AcpiEvGetGpeDevice(ACPI_GPE_XRUPT_INFO * GpeXruptInfo,ACPI_GPE_BLOCK_INFO * GpeBlock,void * Context)130 AcpiEvGetGpeDevice (
131 ACPI_GPE_XRUPT_INFO *GpeXruptInfo,
132 ACPI_GPE_BLOCK_INFO *GpeBlock,
133 void *Context)
134 {
135 ACPI_GPE_DEVICE_INFO *Info = Context;
136
137
138 /* Increment Index by the number of GPEs in this block */
139
140 Info->NextBlockBaseIndex += GpeBlock->GpeCount;
141
142 if (Info->Index < Info->NextBlockBaseIndex)
143 {
144 /*
145 * The GPE index is within this block, get the node. Leave the node
146 * NULL for the FADT-defined GPEs
147 */
148 if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE)
149 {
150 Info->GpeDevice = GpeBlock->Node;
151 }
152
153 Info->Status = AE_OK;
154 return (AE_CTRL_END);
155 }
156
157 return (AE_OK);
158 }
159
160
161 /*******************************************************************************
162 *
163 * FUNCTION: AcpiEvGetGpeXruptBlock
164 *
165 * PARAMETERS: InterruptNumber - Interrupt for a GPE block
166 * GpeXruptBlock - Where the block is returned
167 *
168 * RETURN: Status
169 *
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
173 * subject to change.
174 *
175 ******************************************************************************/
176
177 ACPI_STATUS
AcpiEvGetGpeXruptBlock(UINT32 InterruptNumber,ACPI_GPE_XRUPT_INFO ** GpeXruptBlock)178 AcpiEvGetGpeXruptBlock (
179 UINT32 InterruptNumber,
180 ACPI_GPE_XRUPT_INFO **GpeXruptBlock)
181 {
182 ACPI_GPE_XRUPT_INFO *NextGpeXrupt;
183 ACPI_GPE_XRUPT_INFO *GpeXrupt;
184 ACPI_STATUS Status;
185 ACPI_CPU_FLAGS Flags;
186
187
188 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock);
189
190
191 /* No need for lock since we are not changing any list elements here */
192
193 NextGpeXrupt = AcpiGbl_GpeXruptListHead;
194 while (NextGpeXrupt)
195 {
196 if (NextGpeXrupt->InterruptNumber == InterruptNumber)
197 {
198 *GpeXruptBlock = NextGpeXrupt;
199 return_ACPI_STATUS (AE_OK);
200 }
201
202 NextGpeXrupt = NextGpeXrupt->Next;
203 }
204
205 /* Not found, must allocate a new xrupt descriptor */
206
207 GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO));
208 if (!GpeXrupt)
209 {
210 return_ACPI_STATUS (AE_NO_MEMORY);
211 }
212
213 GpeXrupt->InterruptNumber = InterruptNumber;
214
215 /* Install new interrupt descriptor with spin lock */
216
217 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
218 if (AcpiGbl_GpeXruptListHead)
219 {
220 NextGpeXrupt = AcpiGbl_GpeXruptListHead;
221 while (NextGpeXrupt->Next)
222 {
223 NextGpeXrupt = NextGpeXrupt->Next;
224 }
225
226 NextGpeXrupt->Next = GpeXrupt;
227 GpeXrupt->Previous = NextGpeXrupt;
228 }
229 else
230 {
231 AcpiGbl_GpeXruptListHead = GpeXrupt;
232 }
233
234 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
235
236 /* Install new interrupt handler if not SCI_INT */
237
238 if (InterruptNumber != AcpiGbl_FADT.SciInterrupt)
239 {
240 Status = AcpiOsInstallInterruptHandler (InterruptNumber,
241 AcpiEvGpeXruptHandler, GpeXrupt);
242 if (ACPI_FAILURE (Status))
243 {
244 ACPI_EXCEPTION ((AE_INFO, Status,
245 "Could not install GPE interrupt handler at level 0x%X",
246 InterruptNumber));
247 return_ACPI_STATUS (Status);
248 }
249 }
250
251 *GpeXruptBlock = GpeXrupt;
252 return_ACPI_STATUS (AE_OK);
253 }
254
255
256 /*******************************************************************************
257 *
258 * FUNCTION: AcpiEvDeleteGpeXrupt
259 *
260 * PARAMETERS: GpeXrupt - A GPE interrupt info block
261 *
262 * RETURN: Status
263 *
264 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
265 * interrupt handler if not the SCI interrupt.
266 *
267 ******************************************************************************/
268
269 ACPI_STATUS
AcpiEvDeleteGpeXrupt(ACPI_GPE_XRUPT_INFO * GpeXrupt)270 AcpiEvDeleteGpeXrupt (
271 ACPI_GPE_XRUPT_INFO *GpeXrupt)
272 {
273 ACPI_STATUS Status;
274 ACPI_CPU_FLAGS Flags;
275
276
277 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt);
278
279
280 /* We never want to remove the SCI interrupt handler */
281
282 if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt)
283 {
284 GpeXrupt->GpeBlockListHead = NULL;
285 return_ACPI_STATUS (AE_OK);
286 }
287
288 /* Disable this interrupt */
289
290 Status = AcpiOsRemoveInterruptHandler (
291 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler);
292 if (ACPI_FAILURE (Status))
293 {
294 return_ACPI_STATUS (Status);
295 }
296
297 /* Unlink the interrupt block with lock */
298
299 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
300 if (GpeXrupt->Previous)
301 {
302 GpeXrupt->Previous->Next = GpeXrupt->Next;
303 }
304 else
305 {
306 /* No previous, update list head */
307
308 AcpiGbl_GpeXruptListHead = GpeXrupt->Next;
309 }
310
311 if (GpeXrupt->Next)
312 {
313 GpeXrupt->Next->Previous = GpeXrupt->Previous;
314 }
315 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
316
317 /* Free the block */
318
319 ACPI_FREE (GpeXrupt);
320 return_ACPI_STATUS (AE_OK);
321 }
322
323
324 /*******************************************************************************
325 *
326 * FUNCTION: AcpiEvDeleteGpeHandlers
327 *
328 * PARAMETERS: GpeXruptInfo - GPE Interrupt info
329 * GpeBlock - Gpe Block info
330 *
331 * RETURN: Status
332 *
333 * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
334 * Used only prior to termination.
335 *
336 ******************************************************************************/
337
338 ACPI_STATUS
AcpiEvDeleteGpeHandlers(ACPI_GPE_XRUPT_INFO * GpeXruptInfo,ACPI_GPE_BLOCK_INFO * GpeBlock,void * Context)339 AcpiEvDeleteGpeHandlers (
340 ACPI_GPE_XRUPT_INFO *GpeXruptInfo,
341 ACPI_GPE_BLOCK_INFO *GpeBlock,
342 void *Context)
343 {
344 ACPI_GPE_EVENT_INFO *GpeEventInfo;
345 ACPI_GPE_NOTIFY_INFO *Notify;
346 ACPI_GPE_NOTIFY_INFO *Next;
347 UINT32 i;
348 UINT32 j;
349
350
351 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
352
353
354 /* Examine each GPE Register within the block */
355
356 for (i = 0; i < GpeBlock->RegisterCount; i++)
357 {
358 /* Now look at the individual GPEs in this byte register */
359
360 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
361 {
362 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
363 ACPI_GPE_REGISTER_WIDTH) + j];
364
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))
369 {
370 /* Delete an installed handler block */
371
372 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
373 GpeEventInfo->Dispatch.Handler = NULL;
374 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
375 }
376 else if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) ==
377 ACPI_GPE_DISPATCH_NOTIFY)
378 {
379 /* Delete the implicit notification device list */
380
381 Notify = GpeEventInfo->Dispatch.NotifyList;
382 while (Notify)
383 {
384 Next = Notify->Next;
385 ACPI_FREE (Notify);
386 Notify = Next;
387 }
388
389 GpeEventInfo->Dispatch.NotifyList = NULL;
390 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
391 }
392 }
393 }
394
395 return_ACPI_STATUS (AE_OK);
396 }
397
398 #endif /* !ACPI_REDUCED_HARDWARE */
399