]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/dev/acpica/components/events/evgpeutil.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / dev / acpica / components / events / evgpeutil.c
1 /******************************************************************************
2  *
3  * Module Name: evgpeutil - GPE utilities
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2013, 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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/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
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:    AcpiEvValidGpeEvent
119  *
120  * PARAMETERS:  GpeEventInfo                - Info for this GPE
121  *
122  * RETURN:      TRUE if the GpeEvent is valid
123  *
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.
127  *
128  ******************************************************************************/
129
130 BOOLEAN
131 AcpiEvValidGpeEvent (
132     ACPI_GPE_EVENT_INFO     *GpeEventInfo)
133 {
134     ACPI_GPE_XRUPT_INFO     *GpeXruptBlock;
135     ACPI_GPE_BLOCK_INFO     *GpeBlock;
136
137
138     ACPI_FUNCTION_ENTRY ();
139
140
141     /* No need for spin lock since we are not changing any list elements */
142
143     /* Walk the GPE interrupt levels */
144
145     GpeXruptBlock = AcpiGbl_GpeXruptListHead;
146     while (GpeXruptBlock)
147     {
148         GpeBlock = GpeXruptBlock->GpeBlockListHead;
149
150         /* Walk the GPE blocks on this interrupt level */
151
152         while (GpeBlock)
153         {
154             if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) &&
155                 (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo))
156             {
157                 return (TRUE);
158             }
159
160             GpeBlock = GpeBlock->Next;
161         }
162
163         GpeXruptBlock = GpeXruptBlock->Next;
164     }
165
166     return (FALSE);
167 }
168
169
170 /*******************************************************************************
171  *
172  * FUNCTION:    AcpiEvGetGpeDevice
173  *
174  * PARAMETERS:  GPE_WALK_CALLBACK
175  *
176  * RETURN:      Status
177  *
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.
180  *
181  ******************************************************************************/
182
183 ACPI_STATUS
184 AcpiEvGetGpeDevice (
185     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
186     ACPI_GPE_BLOCK_INFO     *GpeBlock,
187     void                    *Context)
188 {
189     ACPI_GPE_DEVICE_INFO    *Info = Context;
190
191
192     /* Increment Index by the number of GPEs in this block */
193
194     Info->NextBlockBaseIndex += GpeBlock->GpeCount;
195
196     if (Info->Index < Info->NextBlockBaseIndex)
197     {
198         /*
199          * The GPE index is within this block, get the node. Leave the node
200          * NULL for the FADT-defined GPEs
201          */
202         if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE)
203         {
204             Info->GpeDevice = GpeBlock->Node;
205         }
206
207         Info->Status = AE_OK;
208         return (AE_CTRL_END);
209     }
210
211     return (AE_OK);
212 }
213
214
215 /*******************************************************************************
216  *
217  * FUNCTION:    AcpiEvGetGpeXruptBlock
218  *
219  * PARAMETERS:  InterruptNumber             - Interrupt for a GPE block
220  *
221  * RETURN:      A GPE interrupt block
222  *
223  * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
224  *              block per unique interrupt level used for GPEs. Should be
225  *              called only when the GPE lists are semaphore locked and not
226  *              subject to change.
227  *
228  ******************************************************************************/
229
230 ACPI_GPE_XRUPT_INFO *
231 AcpiEvGetGpeXruptBlock (
232     UINT32                  InterruptNumber)
233 {
234     ACPI_GPE_XRUPT_INFO     *NextGpeXrupt;
235     ACPI_GPE_XRUPT_INFO     *GpeXrupt;
236     ACPI_STATUS             Status;
237     ACPI_CPU_FLAGS          Flags;
238
239
240     ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock);
241
242
243     /* No need for lock since we are not changing any list elements here */
244
245     NextGpeXrupt = AcpiGbl_GpeXruptListHead;
246     while (NextGpeXrupt)
247     {
248         if (NextGpeXrupt->InterruptNumber == InterruptNumber)
249         {
250             return_PTR (NextGpeXrupt);
251         }
252
253         NextGpeXrupt = NextGpeXrupt->Next;
254     }
255
256     /* Not found, must allocate a new xrupt descriptor */
257
258     GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO));
259     if (!GpeXrupt)
260     {
261         return_PTR (NULL);
262     }
263
264     GpeXrupt->InterruptNumber = InterruptNumber;
265
266     /* Install new interrupt descriptor with spin lock */
267
268     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
269     if (AcpiGbl_GpeXruptListHead)
270     {
271         NextGpeXrupt = AcpiGbl_GpeXruptListHead;
272         while (NextGpeXrupt->Next)
273         {
274             NextGpeXrupt = NextGpeXrupt->Next;
275         }
276
277         NextGpeXrupt->Next = GpeXrupt;
278         GpeXrupt->Previous = NextGpeXrupt;
279     }
280     else
281     {
282         AcpiGbl_GpeXruptListHead = GpeXrupt;
283     }
284     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
285
286     /* Install new interrupt handler if not SCI_INT */
287
288     if (InterruptNumber != AcpiGbl_FADT.SciInterrupt)
289     {
290         Status = AcpiOsInstallInterruptHandler (InterruptNumber,
291                     AcpiEvGpeXruptHandler, GpeXrupt);
292         if (ACPI_FAILURE (Status))
293         {
294             ACPI_ERROR ((AE_INFO,
295                 "Could not install GPE interrupt handler at level 0x%X",
296                 InterruptNumber));
297             return_PTR (NULL);
298         }
299     }
300
301     return_PTR (GpeXrupt);
302 }
303
304
305 /*******************************************************************************
306  *
307  * FUNCTION:    AcpiEvDeleteGpeXrupt
308  *
309  * PARAMETERS:  GpeXrupt        - A GPE interrupt info block
310  *
311  * RETURN:      Status
312  *
313  * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated
314  *              interrupt handler if not the SCI interrupt.
315  *
316  ******************************************************************************/
317
318 ACPI_STATUS
319 AcpiEvDeleteGpeXrupt (
320     ACPI_GPE_XRUPT_INFO     *GpeXrupt)
321 {
322     ACPI_STATUS             Status;
323     ACPI_CPU_FLAGS          Flags;
324
325
326     ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt);
327
328
329     /* We never want to remove the SCI interrupt handler */
330
331     if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt)
332     {
333         GpeXrupt->GpeBlockListHead = NULL;
334         return_ACPI_STATUS (AE_OK);
335     }
336
337     /* Disable this interrupt */
338
339     Status = AcpiOsRemoveInterruptHandler (
340                 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler);
341     if (ACPI_FAILURE (Status))
342     {
343         return_ACPI_STATUS (Status);
344     }
345
346     /* Unlink the interrupt block with lock */
347
348     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
349     if (GpeXrupt->Previous)
350     {
351         GpeXrupt->Previous->Next = GpeXrupt->Next;
352     }
353     else
354     {
355         /* No previous, update list head */
356
357         AcpiGbl_GpeXruptListHead = GpeXrupt->Next;
358     }
359
360     if (GpeXrupt->Next)
361     {
362         GpeXrupt->Next->Previous = GpeXrupt->Previous;
363     }
364     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
365
366     /* Free the block */
367
368     ACPI_FREE (GpeXrupt);
369     return_ACPI_STATUS (AE_OK);
370 }
371
372
373 /*******************************************************************************
374  *
375  * FUNCTION:    AcpiEvDeleteGpeHandlers
376  *
377  * PARAMETERS:  GpeXruptInfo        - GPE Interrupt info
378  *              GpeBlock            - Gpe Block info
379  *
380  * RETURN:      Status
381  *
382  * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
383  *              Used only prior to termination.
384  *
385  ******************************************************************************/
386
387 ACPI_STATUS
388 AcpiEvDeleteGpeHandlers (
389     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
390     ACPI_GPE_BLOCK_INFO     *GpeBlock,
391     void                    *Context)
392 {
393     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
394     ACPI_GPE_NOTIFY_INFO    *Notify;
395     ACPI_GPE_NOTIFY_INFO    *Next;
396     UINT32                  i;
397     UINT32                  j;
398
399
400     ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
401
402
403     /* Examine each GPE Register within the block */
404
405     for (i = 0; i < GpeBlock->RegisterCount; i++)
406     {
407         /* Now look at the individual GPEs in this byte register */
408
409         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
410         {
411             GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
412                 ACPI_GPE_REGISTER_WIDTH) + j];
413
414             if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
415                     ACPI_GPE_DISPATCH_HANDLER)
416             {
417                 /* Delete an installed handler block */
418
419                 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
420                 GpeEventInfo->Dispatch.Handler = NULL;
421                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
422             }
423             else if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
424                     ACPI_GPE_DISPATCH_NOTIFY)
425             {
426                 /* Delete the implicit notification device list */
427
428                 Notify = GpeEventInfo->Dispatch.NotifyList;
429                 while (Notify)
430                 {
431                     Next = Notify->Next;
432                     ACPI_FREE (Notify);
433                     Notify = Next;
434                 }
435                 GpeEventInfo->Dispatch.NotifyList = NULL;
436                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
437             }
438         }
439     }
440
441     return_ACPI_STATUS (AE_OK);
442 }
443
444 #endif /* !ACPI_REDUCED_HARDWARE */