xref: /freebsd/sys/contrib/dev/acpica/components/events/evgpeblk.c (revision a159c266a93c3c4f229864954c5f963acd8f60f2)
1*a159c266SJung-uk Kim /******************************************************************************
2*a159c266SJung-uk Kim  *
3*a159c266SJung-uk Kim  * Module Name: evgpeblk - GPE block creation and initialization.
4*a159c266SJung-uk Kim  *
5*a159c266SJung-uk Kim  *****************************************************************************/
6*a159c266SJung-uk Kim 
7*a159c266SJung-uk Kim /*
8*a159c266SJung-uk Kim  * Copyright (C) 2000 - 2012, Intel Corp.
9*a159c266SJung-uk Kim  * All rights reserved.
10*a159c266SJung-uk Kim  *
11*a159c266SJung-uk Kim  * Redistribution and use in source and binary forms, with or without
12*a159c266SJung-uk Kim  * modification, are permitted provided that the following conditions
13*a159c266SJung-uk Kim  * are met:
14*a159c266SJung-uk Kim  * 1. Redistributions of source code must retain the above copyright
15*a159c266SJung-uk Kim  *    notice, this list of conditions, and the following disclaimer,
16*a159c266SJung-uk Kim  *    without modification.
17*a159c266SJung-uk Kim  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*a159c266SJung-uk Kim  *    substantially similar to the "NO WARRANTY" disclaimer below
19*a159c266SJung-uk Kim  *    ("Disclaimer") and any redistribution must be conditioned upon
20*a159c266SJung-uk Kim  *    including a substantially similar Disclaimer requirement for further
21*a159c266SJung-uk Kim  *    binary redistribution.
22*a159c266SJung-uk Kim  * 3. Neither the names of the above-listed copyright holders nor the names
23*a159c266SJung-uk Kim  *    of any contributors may be used to endorse or promote products derived
24*a159c266SJung-uk Kim  *    from this software without specific prior written permission.
25*a159c266SJung-uk Kim  *
26*a159c266SJung-uk Kim  * Alternatively, this software may be distributed under the terms of the
27*a159c266SJung-uk Kim  * GNU General Public License ("GPL") version 2 as published by the Free
28*a159c266SJung-uk Kim  * Software Foundation.
29*a159c266SJung-uk Kim  *
30*a159c266SJung-uk Kim  * NO WARRANTY
31*a159c266SJung-uk Kim  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*a159c266SJung-uk Kim  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*a159c266SJung-uk Kim  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*a159c266SJung-uk Kim  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*a159c266SJung-uk Kim  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*a159c266SJung-uk Kim  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*a159c266SJung-uk Kim  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*a159c266SJung-uk Kim  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*a159c266SJung-uk Kim  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*a159c266SJung-uk Kim  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*a159c266SJung-uk Kim  * POSSIBILITY OF SUCH DAMAGES.
42*a159c266SJung-uk Kim  */
43*a159c266SJung-uk Kim 
44*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
45*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
46*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acevents.h>
47*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acnamesp.h>
48*a159c266SJung-uk Kim 
49*a159c266SJung-uk Kim #define _COMPONENT          ACPI_EVENTS
50*a159c266SJung-uk Kim         ACPI_MODULE_NAME    ("evgpeblk")
51*a159c266SJung-uk Kim 
52*a159c266SJung-uk Kim #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53*a159c266SJung-uk Kim 
54*a159c266SJung-uk Kim /* Local prototypes */
55*a159c266SJung-uk Kim 
56*a159c266SJung-uk Kim static ACPI_STATUS
57*a159c266SJung-uk Kim AcpiEvInstallGpeBlock (
58*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock,
59*a159c266SJung-uk Kim     UINT32                  InterruptNumber);
60*a159c266SJung-uk Kim 
61*a159c266SJung-uk Kim static ACPI_STATUS
62*a159c266SJung-uk Kim AcpiEvCreateGpeInfoBlocks (
63*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock);
64*a159c266SJung-uk Kim 
65*a159c266SJung-uk Kim 
66*a159c266SJung-uk Kim /*******************************************************************************
67*a159c266SJung-uk Kim  *
68*a159c266SJung-uk Kim  * FUNCTION:    AcpiEvInstallGpeBlock
69*a159c266SJung-uk Kim  *
70*a159c266SJung-uk Kim  * PARAMETERS:  GpeBlock                - New GPE block
71*a159c266SJung-uk Kim  *              InterruptNumber         - Xrupt to be associated with this
72*a159c266SJung-uk Kim  *                                        GPE block
73*a159c266SJung-uk Kim  *
74*a159c266SJung-uk Kim  * RETURN:      Status
75*a159c266SJung-uk Kim  *
76*a159c266SJung-uk Kim  * DESCRIPTION: Install new GPE block with mutex support
77*a159c266SJung-uk Kim  *
78*a159c266SJung-uk Kim  ******************************************************************************/
79*a159c266SJung-uk Kim 
80*a159c266SJung-uk Kim static ACPI_STATUS
81*a159c266SJung-uk Kim AcpiEvInstallGpeBlock (
82*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock,
83*a159c266SJung-uk Kim     UINT32                  InterruptNumber)
84*a159c266SJung-uk Kim {
85*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *NextGpeBlock;
86*a159c266SJung-uk Kim     ACPI_GPE_XRUPT_INFO     *GpeXruptBlock;
87*a159c266SJung-uk Kim     ACPI_STATUS             Status;
88*a159c266SJung-uk Kim     ACPI_CPU_FLAGS          Flags;
89*a159c266SJung-uk Kim 
90*a159c266SJung-uk Kim 
91*a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
92*a159c266SJung-uk Kim 
93*a159c266SJung-uk Kim 
94*a159c266SJung-uk Kim     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
95*a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
96*a159c266SJung-uk Kim     {
97*a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
98*a159c266SJung-uk Kim     }
99*a159c266SJung-uk Kim 
100*a159c266SJung-uk Kim     GpeXruptBlock = AcpiEvGetGpeXruptBlock (InterruptNumber);
101*a159c266SJung-uk Kim     if (!GpeXruptBlock)
102*a159c266SJung-uk Kim     {
103*a159c266SJung-uk Kim         Status = AE_NO_MEMORY;
104*a159c266SJung-uk Kim         goto UnlockAndExit;
105*a159c266SJung-uk Kim     }
106*a159c266SJung-uk Kim 
107*a159c266SJung-uk Kim     /* Install the new block at the end of the list with lock */
108*a159c266SJung-uk Kim 
109*a159c266SJung-uk Kim     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
110*a159c266SJung-uk Kim     if (GpeXruptBlock->GpeBlockListHead)
111*a159c266SJung-uk Kim     {
112*a159c266SJung-uk Kim         NextGpeBlock = GpeXruptBlock->GpeBlockListHead;
113*a159c266SJung-uk Kim         while (NextGpeBlock->Next)
114*a159c266SJung-uk Kim         {
115*a159c266SJung-uk Kim             NextGpeBlock = NextGpeBlock->Next;
116*a159c266SJung-uk Kim         }
117*a159c266SJung-uk Kim 
118*a159c266SJung-uk Kim         NextGpeBlock->Next = GpeBlock;
119*a159c266SJung-uk Kim         GpeBlock->Previous = NextGpeBlock;
120*a159c266SJung-uk Kim     }
121*a159c266SJung-uk Kim     else
122*a159c266SJung-uk Kim     {
123*a159c266SJung-uk Kim         GpeXruptBlock->GpeBlockListHead = GpeBlock;
124*a159c266SJung-uk Kim     }
125*a159c266SJung-uk Kim 
126*a159c266SJung-uk Kim     GpeBlock->XruptBlock = GpeXruptBlock;
127*a159c266SJung-uk Kim     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
128*a159c266SJung-uk Kim 
129*a159c266SJung-uk Kim 
130*a159c266SJung-uk Kim UnlockAndExit:
131*a159c266SJung-uk Kim     Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
132*a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
133*a159c266SJung-uk Kim }
134*a159c266SJung-uk Kim 
135*a159c266SJung-uk Kim 
136*a159c266SJung-uk Kim /*******************************************************************************
137*a159c266SJung-uk Kim  *
138*a159c266SJung-uk Kim  * FUNCTION:    AcpiEvDeleteGpeBlock
139*a159c266SJung-uk Kim  *
140*a159c266SJung-uk Kim  * PARAMETERS:  GpeBlock            - Existing GPE block
141*a159c266SJung-uk Kim  *
142*a159c266SJung-uk Kim  * RETURN:      Status
143*a159c266SJung-uk Kim  *
144*a159c266SJung-uk Kim  * DESCRIPTION: Remove a GPE block
145*a159c266SJung-uk Kim  *
146*a159c266SJung-uk Kim  ******************************************************************************/
147*a159c266SJung-uk Kim 
148*a159c266SJung-uk Kim ACPI_STATUS
149*a159c266SJung-uk Kim AcpiEvDeleteGpeBlock (
150*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock)
151*a159c266SJung-uk Kim {
152*a159c266SJung-uk Kim     ACPI_STATUS             Status;
153*a159c266SJung-uk Kim     ACPI_CPU_FLAGS          Flags;
154*a159c266SJung-uk Kim 
155*a159c266SJung-uk Kim 
156*a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
157*a159c266SJung-uk Kim 
158*a159c266SJung-uk Kim 
159*a159c266SJung-uk Kim     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
160*a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
161*a159c266SJung-uk Kim     {
162*a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
163*a159c266SJung-uk Kim     }
164*a159c266SJung-uk Kim 
165*a159c266SJung-uk Kim     /* Disable all GPEs in this block */
166*a159c266SJung-uk Kim 
167*a159c266SJung-uk Kim     Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL);
168*a159c266SJung-uk Kim 
169*a159c266SJung-uk Kim     if (!GpeBlock->Previous && !GpeBlock->Next)
170*a159c266SJung-uk Kim     {
171*a159c266SJung-uk Kim         /* This is the last GpeBlock on this interrupt */
172*a159c266SJung-uk Kim 
173*a159c266SJung-uk Kim         Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock);
174*a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
175*a159c266SJung-uk Kim         {
176*a159c266SJung-uk Kim             goto UnlockAndExit;
177*a159c266SJung-uk Kim         }
178*a159c266SJung-uk Kim     }
179*a159c266SJung-uk Kim     else
180*a159c266SJung-uk Kim     {
181*a159c266SJung-uk Kim         /* Remove the block on this interrupt with lock */
182*a159c266SJung-uk Kim 
183*a159c266SJung-uk Kim         Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
184*a159c266SJung-uk Kim         if (GpeBlock->Previous)
185*a159c266SJung-uk Kim         {
186*a159c266SJung-uk Kim             GpeBlock->Previous->Next = GpeBlock->Next;
187*a159c266SJung-uk Kim         }
188*a159c266SJung-uk Kim         else
189*a159c266SJung-uk Kim         {
190*a159c266SJung-uk Kim             GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next;
191*a159c266SJung-uk Kim         }
192*a159c266SJung-uk Kim 
193*a159c266SJung-uk Kim         if (GpeBlock->Next)
194*a159c266SJung-uk Kim         {
195*a159c266SJung-uk Kim             GpeBlock->Next->Previous = GpeBlock->Previous;
196*a159c266SJung-uk Kim         }
197*a159c266SJung-uk Kim         AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
198*a159c266SJung-uk Kim     }
199*a159c266SJung-uk Kim 
200*a159c266SJung-uk Kim     AcpiCurrentGpeCount -= GpeBlock->GpeCount;
201*a159c266SJung-uk Kim 
202*a159c266SJung-uk Kim     /* Free the GpeBlock */
203*a159c266SJung-uk Kim 
204*a159c266SJung-uk Kim     ACPI_FREE (GpeBlock->RegisterInfo);
205*a159c266SJung-uk Kim     ACPI_FREE (GpeBlock->EventInfo);
206*a159c266SJung-uk Kim     ACPI_FREE (GpeBlock);
207*a159c266SJung-uk Kim 
208*a159c266SJung-uk Kim UnlockAndExit:
209*a159c266SJung-uk Kim     Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
210*a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
211*a159c266SJung-uk Kim }
212*a159c266SJung-uk Kim 
213*a159c266SJung-uk Kim 
214*a159c266SJung-uk Kim /*******************************************************************************
215*a159c266SJung-uk Kim  *
216*a159c266SJung-uk Kim  * FUNCTION:    AcpiEvCreateGpeInfoBlocks
217*a159c266SJung-uk Kim  *
218*a159c266SJung-uk Kim  * PARAMETERS:  GpeBlock    - New GPE block
219*a159c266SJung-uk Kim  *
220*a159c266SJung-uk Kim  * RETURN:      Status
221*a159c266SJung-uk Kim  *
222*a159c266SJung-uk Kim  * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
223*a159c266SJung-uk Kim  *
224*a159c266SJung-uk Kim  ******************************************************************************/
225*a159c266SJung-uk Kim 
226*a159c266SJung-uk Kim static ACPI_STATUS
227*a159c266SJung-uk Kim AcpiEvCreateGpeInfoBlocks (
228*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock)
229*a159c266SJung-uk Kim {
230*a159c266SJung-uk Kim     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo = NULL;
231*a159c266SJung-uk Kim     ACPI_GPE_EVENT_INFO     *GpeEventInfo = NULL;
232*a159c266SJung-uk Kim     ACPI_GPE_EVENT_INFO     *ThisEvent;
233*a159c266SJung-uk Kim     ACPI_GPE_REGISTER_INFO  *ThisRegister;
234*a159c266SJung-uk Kim     UINT32                  i;
235*a159c266SJung-uk Kim     UINT32                  j;
236*a159c266SJung-uk Kim     ACPI_STATUS             Status;
237*a159c266SJung-uk Kim 
238*a159c266SJung-uk Kim 
239*a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks);
240*a159c266SJung-uk Kim 
241*a159c266SJung-uk Kim 
242*a159c266SJung-uk Kim     /* Allocate the GPE register information block */
243*a159c266SJung-uk Kim 
244*a159c266SJung-uk Kim     GpeRegisterInfo = ACPI_ALLOCATE_ZEROED (
245*a159c266SJung-uk Kim                         (ACPI_SIZE) GpeBlock->RegisterCount *
246*a159c266SJung-uk Kim                         sizeof (ACPI_GPE_REGISTER_INFO));
247*a159c266SJung-uk Kim     if (!GpeRegisterInfo)
248*a159c266SJung-uk Kim     {
249*a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
250*a159c266SJung-uk Kim             "Could not allocate the GpeRegisterInfo table"));
251*a159c266SJung-uk Kim         return_ACPI_STATUS (AE_NO_MEMORY);
252*a159c266SJung-uk Kim     }
253*a159c266SJung-uk Kim 
254*a159c266SJung-uk Kim     /*
255*a159c266SJung-uk Kim      * Allocate the GPE EventInfo block. There are eight distinct GPEs
256*a159c266SJung-uk Kim      * per register. Initialization to zeros is sufficient.
257*a159c266SJung-uk Kim      */
258*a159c266SJung-uk Kim     GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount *
259*a159c266SJung-uk Kim                     sizeof (ACPI_GPE_EVENT_INFO));
260*a159c266SJung-uk Kim     if (!GpeEventInfo)
261*a159c266SJung-uk Kim     {
262*a159c266SJung-uk Kim         ACPI_ERROR ((AE_INFO,
263*a159c266SJung-uk Kim             "Could not allocate the GpeEventInfo table"));
264*a159c266SJung-uk Kim         Status = AE_NO_MEMORY;
265*a159c266SJung-uk Kim         goto ErrorExit;
266*a159c266SJung-uk Kim     }
267*a159c266SJung-uk Kim 
268*a159c266SJung-uk Kim     /* Save the new Info arrays in the GPE block */
269*a159c266SJung-uk Kim 
270*a159c266SJung-uk Kim     GpeBlock->RegisterInfo = GpeRegisterInfo;
271*a159c266SJung-uk Kim     GpeBlock->EventInfo    = GpeEventInfo;
272*a159c266SJung-uk Kim 
273*a159c266SJung-uk Kim     /*
274*a159c266SJung-uk Kim      * Initialize the GPE Register and Event structures. A goal of these
275*a159c266SJung-uk Kim      * tables is to hide the fact that there are two separate GPE register
276*a159c266SJung-uk Kim      * sets in a given GPE hardware block, the status registers occupy the
277*a159c266SJung-uk Kim      * first half, and the enable registers occupy the second half.
278*a159c266SJung-uk Kim      */
279*a159c266SJung-uk Kim     ThisRegister = GpeRegisterInfo;
280*a159c266SJung-uk Kim     ThisEvent    = GpeEventInfo;
281*a159c266SJung-uk Kim 
282*a159c266SJung-uk Kim     for (i = 0; i < GpeBlock->RegisterCount; i++)
283*a159c266SJung-uk Kim     {
284*a159c266SJung-uk Kim         /* Init the RegisterInfo for this GPE register (8 GPEs) */
285*a159c266SJung-uk Kim 
286*a159c266SJung-uk Kim         ThisRegister->BaseGpeNumber = (UINT8) (GpeBlock->BlockBaseNumber +
287*a159c266SJung-uk Kim                                              (i * ACPI_GPE_REGISTER_WIDTH));
288*a159c266SJung-uk Kim 
289*a159c266SJung-uk Kim         ThisRegister->StatusAddress.Address =
290*a159c266SJung-uk Kim             GpeBlock->BlockAddress.Address + i;
291*a159c266SJung-uk Kim 
292*a159c266SJung-uk Kim         ThisRegister->EnableAddress.Address =
293*a159c266SJung-uk Kim             GpeBlock->BlockAddress.Address + i + GpeBlock->RegisterCount;
294*a159c266SJung-uk Kim 
295*a159c266SJung-uk Kim         ThisRegister->StatusAddress.SpaceId   = GpeBlock->BlockAddress.SpaceId;
296*a159c266SJung-uk Kim         ThisRegister->EnableAddress.SpaceId   = GpeBlock->BlockAddress.SpaceId;
297*a159c266SJung-uk Kim         ThisRegister->StatusAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
298*a159c266SJung-uk Kim         ThisRegister->EnableAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
299*a159c266SJung-uk Kim         ThisRegister->StatusAddress.BitOffset = 0;
300*a159c266SJung-uk Kim         ThisRegister->EnableAddress.BitOffset = 0;
301*a159c266SJung-uk Kim 
302*a159c266SJung-uk Kim         /* Init the EventInfo for each GPE within this register */
303*a159c266SJung-uk Kim 
304*a159c266SJung-uk Kim         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
305*a159c266SJung-uk Kim         {
306*a159c266SJung-uk Kim             ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j);
307*a159c266SJung-uk Kim             ThisEvent->RegisterInfo = ThisRegister;
308*a159c266SJung-uk Kim             ThisEvent++;
309*a159c266SJung-uk Kim         }
310*a159c266SJung-uk Kim 
311*a159c266SJung-uk Kim         /* Disable all GPEs within this register */
312*a159c266SJung-uk Kim 
313*a159c266SJung-uk Kim         Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress);
314*a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
315*a159c266SJung-uk Kim         {
316*a159c266SJung-uk Kim             goto ErrorExit;
317*a159c266SJung-uk Kim         }
318*a159c266SJung-uk Kim 
319*a159c266SJung-uk Kim         /* Clear any pending GPE events within this register */
320*a159c266SJung-uk Kim 
321*a159c266SJung-uk Kim         Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress);
322*a159c266SJung-uk Kim         if (ACPI_FAILURE (Status))
323*a159c266SJung-uk Kim         {
324*a159c266SJung-uk Kim             goto ErrorExit;
325*a159c266SJung-uk Kim         }
326*a159c266SJung-uk Kim 
327*a159c266SJung-uk Kim         ThisRegister++;
328*a159c266SJung-uk Kim     }
329*a159c266SJung-uk Kim 
330*a159c266SJung-uk Kim     return_ACPI_STATUS (AE_OK);
331*a159c266SJung-uk Kim 
332*a159c266SJung-uk Kim 
333*a159c266SJung-uk Kim ErrorExit:
334*a159c266SJung-uk Kim     if (GpeRegisterInfo)
335*a159c266SJung-uk Kim     {
336*a159c266SJung-uk Kim         ACPI_FREE (GpeRegisterInfo);
337*a159c266SJung-uk Kim     }
338*a159c266SJung-uk Kim     if (GpeEventInfo)
339*a159c266SJung-uk Kim     {
340*a159c266SJung-uk Kim         ACPI_FREE (GpeEventInfo);
341*a159c266SJung-uk Kim     }
342*a159c266SJung-uk Kim 
343*a159c266SJung-uk Kim     return_ACPI_STATUS (Status);
344*a159c266SJung-uk Kim }
345*a159c266SJung-uk Kim 
346*a159c266SJung-uk Kim 
347*a159c266SJung-uk Kim /*******************************************************************************
348*a159c266SJung-uk Kim  *
349*a159c266SJung-uk Kim  * FUNCTION:    AcpiEvCreateGpeBlock
350*a159c266SJung-uk Kim  *
351*a159c266SJung-uk Kim  * PARAMETERS:  GpeDevice           - Handle to the parent GPE block
352*a159c266SJung-uk Kim  *              GpeBlockAddress     - Address and SpaceID
353*a159c266SJung-uk Kim  *              RegisterCount       - Number of GPE register pairs in the block
354*a159c266SJung-uk Kim  *              GpeBlockBaseNumber  - Starting GPE number for the block
355*a159c266SJung-uk Kim  *              InterruptNumber     - H/W interrupt for the block
356*a159c266SJung-uk Kim  *              ReturnGpeBlock      - Where the new block descriptor is returned
357*a159c266SJung-uk Kim  *
358*a159c266SJung-uk Kim  * RETURN:      Status
359*a159c266SJung-uk Kim  *
360*a159c266SJung-uk Kim  * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
361*a159c266SJung-uk Kim  *              the block are disabled at exit.
362*a159c266SJung-uk Kim  *              Note: Assumes namespace is locked.
363*a159c266SJung-uk Kim  *
364*a159c266SJung-uk Kim  ******************************************************************************/
365*a159c266SJung-uk Kim 
366*a159c266SJung-uk Kim ACPI_STATUS
367*a159c266SJung-uk Kim AcpiEvCreateGpeBlock (
368*a159c266SJung-uk Kim     ACPI_NAMESPACE_NODE     *GpeDevice,
369*a159c266SJung-uk Kim     ACPI_GENERIC_ADDRESS    *GpeBlockAddress,
370*a159c266SJung-uk Kim     UINT32                  RegisterCount,
371*a159c266SJung-uk Kim     UINT8                   GpeBlockBaseNumber,
372*a159c266SJung-uk Kim     UINT32                  InterruptNumber,
373*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     **ReturnGpeBlock)
374*a159c266SJung-uk Kim {
375*a159c266SJung-uk Kim     ACPI_STATUS             Status;
376*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock;
377*a159c266SJung-uk Kim     ACPI_GPE_WALK_INFO      WalkInfo;
378*a159c266SJung-uk Kim 
379*a159c266SJung-uk Kim 
380*a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (EvCreateGpeBlock);
381*a159c266SJung-uk Kim 
382*a159c266SJung-uk Kim 
383*a159c266SJung-uk Kim     if (!RegisterCount)
384*a159c266SJung-uk Kim     {
385*a159c266SJung-uk Kim         return_ACPI_STATUS (AE_OK);
386*a159c266SJung-uk Kim     }
387*a159c266SJung-uk Kim 
388*a159c266SJung-uk Kim     /* Allocate a new GPE block */
389*a159c266SJung-uk Kim 
390*a159c266SJung-uk Kim     GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO));
391*a159c266SJung-uk Kim     if (!GpeBlock)
392*a159c266SJung-uk Kim     {
393*a159c266SJung-uk Kim         return_ACPI_STATUS (AE_NO_MEMORY);
394*a159c266SJung-uk Kim     }
395*a159c266SJung-uk Kim 
396*a159c266SJung-uk Kim     /* Initialize the new GPE block */
397*a159c266SJung-uk Kim 
398*a159c266SJung-uk Kim     GpeBlock->Node = GpeDevice;
399*a159c266SJung-uk Kim     GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH);
400*a159c266SJung-uk Kim     GpeBlock->Initialized = FALSE;
401*a159c266SJung-uk Kim     GpeBlock->RegisterCount = RegisterCount;
402*a159c266SJung-uk Kim     GpeBlock->BlockBaseNumber = GpeBlockBaseNumber;
403*a159c266SJung-uk Kim 
404*a159c266SJung-uk Kim     ACPI_MEMCPY (&GpeBlock->BlockAddress, GpeBlockAddress,
405*a159c266SJung-uk Kim         sizeof (ACPI_GENERIC_ADDRESS));
406*a159c266SJung-uk Kim 
407*a159c266SJung-uk Kim     /*
408*a159c266SJung-uk Kim      * Create the RegisterInfo and EventInfo sub-structures
409*a159c266SJung-uk Kim      * Note: disables and clears all GPEs in the block
410*a159c266SJung-uk Kim      */
411*a159c266SJung-uk Kim     Status = AcpiEvCreateGpeInfoBlocks (GpeBlock);
412*a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
413*a159c266SJung-uk Kim     {
414*a159c266SJung-uk Kim         ACPI_FREE (GpeBlock);
415*a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
416*a159c266SJung-uk Kim     }
417*a159c266SJung-uk Kim 
418*a159c266SJung-uk Kim     /* Install the new block in the global lists */
419*a159c266SJung-uk Kim 
420*a159c266SJung-uk Kim     Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber);
421*a159c266SJung-uk Kim     if (ACPI_FAILURE (Status))
422*a159c266SJung-uk Kim     {
423*a159c266SJung-uk Kim         ACPI_FREE (GpeBlock);
424*a159c266SJung-uk Kim         return_ACPI_STATUS (Status);
425*a159c266SJung-uk Kim     }
426*a159c266SJung-uk Kim 
427*a159c266SJung-uk Kim     AcpiGbl_AllGpesInitialized = FALSE;
428*a159c266SJung-uk Kim 
429*a159c266SJung-uk Kim     /* Find all GPE methods (_Lxx or_Exx) for this block */
430*a159c266SJung-uk Kim 
431*a159c266SJung-uk Kim     WalkInfo.GpeBlock = GpeBlock;
432*a159c266SJung-uk Kim     WalkInfo.GpeDevice = GpeDevice;
433*a159c266SJung-uk Kim     WalkInfo.ExecuteByOwnerId = FALSE;
434*a159c266SJung-uk Kim 
435*a159c266SJung-uk Kim     Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice,
436*a159c266SJung-uk Kim                 ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
437*a159c266SJung-uk Kim                 AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL);
438*a159c266SJung-uk Kim 
439*a159c266SJung-uk Kim     /* Return the new block */
440*a159c266SJung-uk Kim 
441*a159c266SJung-uk Kim     if (ReturnGpeBlock)
442*a159c266SJung-uk Kim     {
443*a159c266SJung-uk Kim         (*ReturnGpeBlock) = GpeBlock;
444*a159c266SJung-uk Kim     }
445*a159c266SJung-uk Kim 
446*a159c266SJung-uk Kim     ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
447*a159c266SJung-uk Kim         "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
448*a159c266SJung-uk Kim         (UINT32) GpeBlock->BlockBaseNumber,
449*a159c266SJung-uk Kim         (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)),
450*a159c266SJung-uk Kim         GpeDevice->Name.Ascii, GpeBlock->RegisterCount,
451*a159c266SJung-uk Kim         InterruptNumber));
452*a159c266SJung-uk Kim 
453*a159c266SJung-uk Kim     /* Update global count of currently available GPEs */
454*a159c266SJung-uk Kim 
455*a159c266SJung-uk Kim     AcpiCurrentGpeCount += GpeBlock->GpeCount;
456*a159c266SJung-uk Kim     return_ACPI_STATUS (AE_OK);
457*a159c266SJung-uk Kim }
458*a159c266SJung-uk Kim 
459*a159c266SJung-uk Kim 
460*a159c266SJung-uk Kim /*******************************************************************************
461*a159c266SJung-uk Kim  *
462*a159c266SJung-uk Kim  * FUNCTION:    AcpiEvInitializeGpeBlock
463*a159c266SJung-uk Kim  *
464*a159c266SJung-uk Kim  * PARAMETERS:  ACPI_GPE_CALLBACK
465*a159c266SJung-uk Kim  *
466*a159c266SJung-uk Kim  * RETURN:      Status
467*a159c266SJung-uk Kim  *
468*a159c266SJung-uk Kim  * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
469*a159c266SJung-uk Kim  *              associated methods.
470*a159c266SJung-uk Kim  *              Note: Assumes namespace is locked.
471*a159c266SJung-uk Kim  *
472*a159c266SJung-uk Kim  ******************************************************************************/
473*a159c266SJung-uk Kim 
474*a159c266SJung-uk Kim ACPI_STATUS
475*a159c266SJung-uk Kim AcpiEvInitializeGpeBlock (
476*a159c266SJung-uk Kim     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
477*a159c266SJung-uk Kim     ACPI_GPE_BLOCK_INFO     *GpeBlock,
478*a159c266SJung-uk Kim     void                    *Ignored)
479*a159c266SJung-uk Kim {
480*a159c266SJung-uk Kim     ACPI_STATUS             Status;
481*a159c266SJung-uk Kim     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
482*a159c266SJung-uk Kim     UINT32                  GpeEnabledCount;
483*a159c266SJung-uk Kim     UINT32                  GpeIndex;
484*a159c266SJung-uk Kim     UINT32                  i;
485*a159c266SJung-uk Kim     UINT32                  j;
486*a159c266SJung-uk Kim 
487*a159c266SJung-uk Kim 
488*a159c266SJung-uk Kim     ACPI_FUNCTION_TRACE (EvInitializeGpeBlock);
489*a159c266SJung-uk Kim 
490*a159c266SJung-uk Kim 
491*a159c266SJung-uk Kim     /*
492*a159c266SJung-uk Kim      * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
493*a159c266SJung-uk Kim      * any GPE blocks that have been initialized already.
494*a159c266SJung-uk Kim      */
495*a159c266SJung-uk Kim     if (!GpeBlock || GpeBlock->Initialized)
496*a159c266SJung-uk Kim     {
497*a159c266SJung-uk Kim         return_ACPI_STATUS (AE_OK);
498*a159c266SJung-uk Kim     }
499*a159c266SJung-uk Kim 
500*a159c266SJung-uk Kim     /*
501*a159c266SJung-uk Kim      * Enable all GPEs that have a corresponding method and have the
502*a159c266SJung-uk Kim      * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
503*a159c266SJung-uk Kim      * must be enabled via the acpi_enable_gpe() interface.
504*a159c266SJung-uk Kim      */
505*a159c266SJung-uk Kim     GpeEnabledCount = 0;
506*a159c266SJung-uk Kim 
507*a159c266SJung-uk Kim     for (i = 0; i < GpeBlock->RegisterCount; i++)
508*a159c266SJung-uk Kim     {
509*a159c266SJung-uk Kim         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
510*a159c266SJung-uk Kim         {
511*a159c266SJung-uk Kim             /* Get the info block for this particular GPE */
512*a159c266SJung-uk Kim 
513*a159c266SJung-uk Kim             GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j;
514*a159c266SJung-uk Kim             GpeEventInfo = &GpeBlock->EventInfo[GpeIndex];
515*a159c266SJung-uk Kim 
516*a159c266SJung-uk Kim             /*
517*a159c266SJung-uk Kim              * Ignore GPEs that have no corresponding _Lxx/_Exx method
518*a159c266SJung-uk Kim              * and GPEs that are used to wake the system
519*a159c266SJung-uk Kim              */
520*a159c266SJung-uk Kim             if (((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NONE) ||
521*a159c266SJung-uk Kim                 ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) ||
522*a159c266SJung-uk Kim                 (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
523*a159c266SJung-uk Kim             {
524*a159c266SJung-uk Kim                 continue;
525*a159c266SJung-uk Kim             }
526*a159c266SJung-uk Kim 
527*a159c266SJung-uk Kim             Status = AcpiEvAddGpeReference (GpeEventInfo);
528*a159c266SJung-uk Kim             if (ACPI_FAILURE (Status))
529*a159c266SJung-uk Kim             {
530*a159c266SJung-uk Kim                 ACPI_EXCEPTION ((AE_INFO, Status,
531*a159c266SJung-uk Kim                     "Could not enable GPE 0x%02X",
532*a159c266SJung-uk Kim                     GpeIndex + GpeBlock->BlockBaseNumber));
533*a159c266SJung-uk Kim                 continue;
534*a159c266SJung-uk Kim             }
535*a159c266SJung-uk Kim 
536*a159c266SJung-uk Kim             GpeEnabledCount++;
537*a159c266SJung-uk Kim         }
538*a159c266SJung-uk Kim     }
539*a159c266SJung-uk Kim 
540*a159c266SJung-uk Kim     if (GpeEnabledCount)
541*a159c266SJung-uk Kim     {
542*a159c266SJung-uk Kim         ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
543*a159c266SJung-uk Kim             "Enabled %u GPEs in this block\n", GpeEnabledCount));
544*a159c266SJung-uk Kim     }
545*a159c266SJung-uk Kim 
546*a159c266SJung-uk Kim     GpeBlock->Initialized = TRUE;
547*a159c266SJung-uk Kim     return_ACPI_STATUS (AE_OK);
548*a159c266SJung-uk Kim }
549*a159c266SJung-uk Kim 
550*a159c266SJung-uk Kim #endif /* !ACPI_REDUCED_HARDWARE */
551