xref: /titanic_52/usr/src/uts/intel/io/acpica/events/evgpeutil.c (revision 2c2d21e98a95cba5687ec6574c974a5c6c4a6adb)
1 /******************************************************************************
2  *
3  * Module Name: evgpeutil - GPE utilities
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2011, 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 
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acevents.h"
48 
49 #define _COMPONENT          ACPI_EVENTS
50         ACPI_MODULE_NAME    ("evgpeutil")
51 
52 
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     UINT32                  i;
395     UINT32                  j;
396 
397 
398     ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers);
399 
400 
401     /* Examine each GPE Register within the block */
402 
403     for (i = 0; i < GpeBlock->RegisterCount; i++)
404     {
405         /* Now look at the individual GPEs in this byte register */
406 
407         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
408         {
409             GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i *
410                 ACPI_GPE_REGISTER_WIDTH) + j];
411 
412             if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) ==
413                     ACPI_GPE_DISPATCH_HANDLER)
414             {
415                 ACPI_FREE (GpeEventInfo->Dispatch.Handler);
416                 GpeEventInfo->Dispatch.Handler = NULL;
417                 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK;
418             }
419         }
420     }
421 
422     return_ACPI_STATUS (AE_OK);
423 }
424 
425