xref: /minix3/minix/drivers/power/acpi/events/evgpeblk.c (revision 29492bb71c7148a089a5afafa0c99409161218df)
1433d6423SLionel Sambuc /******************************************************************************
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * Module Name: evgpeblk - GPE block creation and initialization.
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  *****************************************************************************/
6433d6423SLionel Sambuc 
7*29492bb7SDavid van Moolenbroek /*
8*29492bb7SDavid van Moolenbroek  * Copyright (C) 2000 - 2014, Intel Corp.
9433d6423SLionel Sambuc  * All rights reserved.
10433d6423SLionel Sambuc  *
11*29492bb7SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
12*29492bb7SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
13*29492bb7SDavid van Moolenbroek  * are met:
14*29492bb7SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
15*29492bb7SDavid van Moolenbroek  *    notice, this list of conditions, and the following disclaimer,
16*29492bb7SDavid van Moolenbroek  *    without modification.
17*29492bb7SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*29492bb7SDavid van Moolenbroek  *    substantially similar to the "NO WARRANTY" disclaimer below
19*29492bb7SDavid van Moolenbroek  *    ("Disclaimer") and any redistribution must be conditioned upon
20*29492bb7SDavid van Moolenbroek  *    including a substantially similar Disclaimer requirement for further
21*29492bb7SDavid van Moolenbroek  *    binary redistribution.
22*29492bb7SDavid van Moolenbroek  * 3. Neither the names of the above-listed copyright holders nor the names
23*29492bb7SDavid van Moolenbroek  *    of any contributors may be used to endorse or promote products derived
24*29492bb7SDavid van Moolenbroek  *    from this software without specific prior written permission.
25433d6423SLionel Sambuc  *
26*29492bb7SDavid van Moolenbroek  * Alternatively, this software may be distributed under the terms of the
27*29492bb7SDavid van Moolenbroek  * GNU General Public License ("GPL") version 2 as published by the Free
28*29492bb7SDavid van Moolenbroek  * Software Foundation.
29433d6423SLionel Sambuc  *
30*29492bb7SDavid van Moolenbroek  * NO WARRANTY
31*29492bb7SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*29492bb7SDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*29492bb7SDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*29492bb7SDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*29492bb7SDavid van Moolenbroek  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*29492bb7SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*29492bb7SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*29492bb7SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*29492bb7SDavid van Moolenbroek  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*29492bb7SDavid van Moolenbroek  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*29492bb7SDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGES.
42*29492bb7SDavid van Moolenbroek  */
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc #include "acpi.h"
45433d6423SLionel Sambuc #include "accommon.h"
46433d6423SLionel Sambuc #include "acevents.h"
47433d6423SLionel Sambuc #include "acnamesp.h"
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc #define _COMPONENT          ACPI_EVENTS
50433d6423SLionel Sambuc         ACPI_MODULE_NAME    ("evgpeblk")
51433d6423SLionel Sambuc 
52*29492bb7SDavid van Moolenbroek #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
53*29492bb7SDavid van Moolenbroek 
54433d6423SLionel Sambuc /* Local prototypes */
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc static ACPI_STATUS
57433d6423SLionel Sambuc AcpiEvInstallGpeBlock (
58433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock,
59433d6423SLionel Sambuc     UINT32                  InterruptNumber);
60433d6423SLionel Sambuc 
61433d6423SLionel Sambuc static ACPI_STATUS
62433d6423SLionel Sambuc AcpiEvCreateGpeInfoBlocks (
63433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock);
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc /*******************************************************************************
67433d6423SLionel Sambuc  *
68433d6423SLionel Sambuc  * FUNCTION:    AcpiEvInstallGpeBlock
69433d6423SLionel Sambuc  *
70433d6423SLionel Sambuc  * PARAMETERS:  GpeBlock                - New GPE block
71433d6423SLionel Sambuc  *              InterruptNumber         - Xrupt to be associated with this
72433d6423SLionel Sambuc  *                                        GPE block
73433d6423SLionel Sambuc  *
74433d6423SLionel Sambuc  * RETURN:      Status
75433d6423SLionel Sambuc  *
76433d6423SLionel Sambuc  * DESCRIPTION: Install new GPE block with mutex support
77433d6423SLionel Sambuc  *
78433d6423SLionel Sambuc  ******************************************************************************/
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc static ACPI_STATUS
AcpiEvInstallGpeBlock(ACPI_GPE_BLOCK_INFO * GpeBlock,UINT32 InterruptNumber)81433d6423SLionel Sambuc AcpiEvInstallGpeBlock (
82433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock,
83433d6423SLionel Sambuc     UINT32                  InterruptNumber)
84433d6423SLionel Sambuc {
85433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *NextGpeBlock;
86433d6423SLionel Sambuc     ACPI_GPE_XRUPT_INFO     *GpeXruptBlock;
87433d6423SLionel Sambuc     ACPI_STATUS             Status;
88433d6423SLionel Sambuc     ACPI_CPU_FLAGS          Flags;
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
95433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
96433d6423SLionel Sambuc     {
97433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
98433d6423SLionel Sambuc     }
99433d6423SLionel Sambuc 
100*29492bb7SDavid van Moolenbroek     Status = AcpiEvGetGpeXruptBlock (InterruptNumber, &GpeXruptBlock);
101*29492bb7SDavid van Moolenbroek     if (ACPI_FAILURE (Status))
102433d6423SLionel Sambuc     {
103433d6423SLionel Sambuc         goto UnlockAndExit;
104433d6423SLionel Sambuc     }
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc     /* Install the new block at the end of the list with lock */
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc     Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
109433d6423SLionel Sambuc     if (GpeXruptBlock->GpeBlockListHead)
110433d6423SLionel Sambuc     {
111433d6423SLionel Sambuc         NextGpeBlock = GpeXruptBlock->GpeBlockListHead;
112433d6423SLionel Sambuc         while (NextGpeBlock->Next)
113433d6423SLionel Sambuc         {
114433d6423SLionel Sambuc             NextGpeBlock = NextGpeBlock->Next;
115433d6423SLionel Sambuc         }
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc         NextGpeBlock->Next = GpeBlock;
118433d6423SLionel Sambuc         GpeBlock->Previous = NextGpeBlock;
119433d6423SLionel Sambuc     }
120433d6423SLionel Sambuc     else
121433d6423SLionel Sambuc     {
122433d6423SLionel Sambuc         GpeXruptBlock->GpeBlockListHead = GpeBlock;
123433d6423SLionel Sambuc     }
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc     GpeBlock->XruptBlock = GpeXruptBlock;
126433d6423SLionel Sambuc     AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc UnlockAndExit:
130*29492bb7SDavid van Moolenbroek     (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
131433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
132433d6423SLionel Sambuc }
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc /*******************************************************************************
136433d6423SLionel Sambuc  *
137433d6423SLionel Sambuc  * FUNCTION:    AcpiEvDeleteGpeBlock
138433d6423SLionel Sambuc  *
139433d6423SLionel Sambuc  * PARAMETERS:  GpeBlock            - Existing GPE block
140433d6423SLionel Sambuc  *
141433d6423SLionel Sambuc  * RETURN:      Status
142433d6423SLionel Sambuc  *
143433d6423SLionel Sambuc  * DESCRIPTION: Remove a GPE block
144433d6423SLionel Sambuc  *
145433d6423SLionel Sambuc  ******************************************************************************/
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc ACPI_STATUS
AcpiEvDeleteGpeBlock(ACPI_GPE_BLOCK_INFO * GpeBlock)148433d6423SLionel Sambuc AcpiEvDeleteGpeBlock (
149433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock)
150433d6423SLionel Sambuc {
151433d6423SLionel Sambuc     ACPI_STATUS             Status;
152433d6423SLionel Sambuc     ACPI_CPU_FLAGS          Flags;
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (EvInstallGpeBlock);
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc     Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS);
159433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
160433d6423SLionel Sambuc     {
161433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
162433d6423SLionel Sambuc     }
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc     /* Disable all GPEs in this block */
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc     Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL);
167433d6423SLionel Sambuc 
168433d6423SLionel Sambuc     if (!GpeBlock->Previous && !GpeBlock->Next)
169433d6423SLionel Sambuc     {
170433d6423SLionel Sambuc         /* This is the last GpeBlock on this interrupt */
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc         Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock);
173433d6423SLionel Sambuc         if (ACPI_FAILURE (Status))
174433d6423SLionel Sambuc         {
175433d6423SLionel Sambuc             goto UnlockAndExit;
176433d6423SLionel Sambuc         }
177433d6423SLionel Sambuc     }
178433d6423SLionel Sambuc     else
179433d6423SLionel Sambuc     {
180433d6423SLionel Sambuc         /* Remove the block on this interrupt with lock */
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc         Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);
183433d6423SLionel Sambuc         if (GpeBlock->Previous)
184433d6423SLionel Sambuc         {
185433d6423SLionel Sambuc             GpeBlock->Previous->Next = GpeBlock->Next;
186433d6423SLionel Sambuc         }
187433d6423SLionel Sambuc         else
188433d6423SLionel Sambuc         {
189433d6423SLionel Sambuc             GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next;
190433d6423SLionel Sambuc         }
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc         if (GpeBlock->Next)
193433d6423SLionel Sambuc         {
194433d6423SLionel Sambuc             GpeBlock->Next->Previous = GpeBlock->Previous;
195433d6423SLionel Sambuc         }
196433d6423SLionel Sambuc         AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
197433d6423SLionel Sambuc     }
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc     AcpiCurrentGpeCount -= GpeBlock->GpeCount;
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc     /* Free the GpeBlock */
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc     ACPI_FREE (GpeBlock->RegisterInfo);
204433d6423SLionel Sambuc     ACPI_FREE (GpeBlock->EventInfo);
205433d6423SLionel Sambuc     ACPI_FREE (GpeBlock);
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc UnlockAndExit:
208433d6423SLionel Sambuc     Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS);
209433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc 
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc /*******************************************************************************
214433d6423SLionel Sambuc  *
215433d6423SLionel Sambuc  * FUNCTION:    AcpiEvCreateGpeInfoBlocks
216433d6423SLionel Sambuc  *
217433d6423SLionel Sambuc  * PARAMETERS:  GpeBlock    - New GPE block
218433d6423SLionel Sambuc  *
219433d6423SLionel Sambuc  * RETURN:      Status
220433d6423SLionel Sambuc  *
221433d6423SLionel Sambuc  * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
222433d6423SLionel Sambuc  *
223433d6423SLionel Sambuc  ******************************************************************************/
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc static ACPI_STATUS
AcpiEvCreateGpeInfoBlocks(ACPI_GPE_BLOCK_INFO * GpeBlock)226433d6423SLionel Sambuc AcpiEvCreateGpeInfoBlocks (
227433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock)
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc     ACPI_GPE_REGISTER_INFO  *GpeRegisterInfo = NULL;
230433d6423SLionel Sambuc     ACPI_GPE_EVENT_INFO     *GpeEventInfo = NULL;
231433d6423SLionel Sambuc     ACPI_GPE_EVENT_INFO     *ThisEvent;
232433d6423SLionel Sambuc     ACPI_GPE_REGISTER_INFO  *ThisRegister;
233433d6423SLionel Sambuc     UINT32                  i;
234433d6423SLionel Sambuc     UINT32                  j;
235433d6423SLionel Sambuc     ACPI_STATUS             Status;
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks);
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc     /* Allocate the GPE register information block */
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc     GpeRegisterInfo = ACPI_ALLOCATE_ZEROED (
244433d6423SLionel Sambuc                         (ACPI_SIZE) GpeBlock->RegisterCount *
245433d6423SLionel Sambuc                         sizeof (ACPI_GPE_REGISTER_INFO));
246433d6423SLionel Sambuc     if (!GpeRegisterInfo)
247433d6423SLionel Sambuc     {
248433d6423SLionel Sambuc         ACPI_ERROR ((AE_INFO,
249433d6423SLionel Sambuc             "Could not allocate the GpeRegisterInfo table"));
250433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NO_MEMORY);
251433d6423SLionel Sambuc     }
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc     /*
254433d6423SLionel Sambuc      * Allocate the GPE EventInfo block. There are eight distinct GPEs
255433d6423SLionel Sambuc      * per register. Initialization to zeros is sufficient.
256433d6423SLionel Sambuc      */
257433d6423SLionel Sambuc     GpeEventInfo = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) GpeBlock->GpeCount *
258433d6423SLionel Sambuc                     sizeof (ACPI_GPE_EVENT_INFO));
259433d6423SLionel Sambuc     if (!GpeEventInfo)
260433d6423SLionel Sambuc     {
261433d6423SLionel Sambuc         ACPI_ERROR ((AE_INFO,
262433d6423SLionel Sambuc             "Could not allocate the GpeEventInfo table"));
263433d6423SLionel Sambuc         Status = AE_NO_MEMORY;
264433d6423SLionel Sambuc         goto ErrorExit;
265433d6423SLionel Sambuc     }
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc     /* Save the new Info arrays in the GPE block */
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc     GpeBlock->RegisterInfo = GpeRegisterInfo;
270433d6423SLionel Sambuc     GpeBlock->EventInfo    = GpeEventInfo;
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc     /*
273433d6423SLionel Sambuc      * Initialize the GPE Register and Event structures. A goal of these
274433d6423SLionel Sambuc      * tables is to hide the fact that there are two separate GPE register
275433d6423SLionel Sambuc      * sets in a given GPE hardware block, the status registers occupy the
276433d6423SLionel Sambuc      * first half, and the enable registers occupy the second half.
277433d6423SLionel Sambuc      */
278433d6423SLionel Sambuc     ThisRegister = GpeRegisterInfo;
279433d6423SLionel Sambuc     ThisEvent    = GpeEventInfo;
280433d6423SLionel Sambuc 
281433d6423SLionel Sambuc     for (i = 0; i < GpeBlock->RegisterCount; i++)
282433d6423SLionel Sambuc     {
283433d6423SLionel Sambuc         /* Init the RegisterInfo for this GPE register (8 GPEs) */
284433d6423SLionel Sambuc 
285*29492bb7SDavid van Moolenbroek         ThisRegister->BaseGpeNumber = (UINT16)
286*29492bb7SDavid van Moolenbroek             (GpeBlock->BlockBaseNumber + (i * ACPI_GPE_REGISTER_WIDTH));
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc         ThisRegister->StatusAddress.Address =
289*29492bb7SDavid van Moolenbroek             GpeBlock->Address + i;
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc         ThisRegister->EnableAddress.Address =
292*29492bb7SDavid van Moolenbroek             GpeBlock->Address + i + GpeBlock->RegisterCount;
293433d6423SLionel Sambuc 
294*29492bb7SDavid van Moolenbroek         ThisRegister->StatusAddress.SpaceId   = GpeBlock->SpaceId;
295*29492bb7SDavid van Moolenbroek         ThisRegister->EnableAddress.SpaceId   = GpeBlock->SpaceId;
296433d6423SLionel Sambuc         ThisRegister->StatusAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
297433d6423SLionel Sambuc         ThisRegister->EnableAddress.BitWidth  = ACPI_GPE_REGISTER_WIDTH;
298433d6423SLionel Sambuc         ThisRegister->StatusAddress.BitOffset = 0;
299433d6423SLionel Sambuc         ThisRegister->EnableAddress.BitOffset = 0;
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc         /* Init the EventInfo for each GPE within this register */
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
304433d6423SLionel Sambuc         {
305433d6423SLionel Sambuc             ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j);
306433d6423SLionel Sambuc             ThisEvent->RegisterInfo = ThisRegister;
307433d6423SLionel Sambuc             ThisEvent++;
308433d6423SLionel Sambuc         }
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc         /* Disable all GPEs within this register */
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc         Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress);
313433d6423SLionel Sambuc         if (ACPI_FAILURE (Status))
314433d6423SLionel Sambuc         {
315433d6423SLionel Sambuc             goto ErrorExit;
316433d6423SLionel Sambuc         }
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc         /* Clear any pending GPE events within this register */
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc         Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress);
321433d6423SLionel Sambuc         if (ACPI_FAILURE (Status))
322433d6423SLionel Sambuc         {
323433d6423SLionel Sambuc             goto ErrorExit;
324433d6423SLionel Sambuc         }
325433d6423SLionel Sambuc 
326433d6423SLionel Sambuc         ThisRegister++;
327433d6423SLionel Sambuc     }
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc ErrorExit:
333433d6423SLionel Sambuc     if (GpeRegisterInfo)
334433d6423SLionel Sambuc     {
335433d6423SLionel Sambuc         ACPI_FREE (GpeRegisterInfo);
336433d6423SLionel Sambuc     }
337433d6423SLionel Sambuc     if (GpeEventInfo)
338433d6423SLionel Sambuc     {
339433d6423SLionel Sambuc         ACPI_FREE (GpeEventInfo);
340433d6423SLionel Sambuc     }
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
343433d6423SLionel Sambuc }
344433d6423SLionel Sambuc 
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc /*******************************************************************************
347433d6423SLionel Sambuc  *
348433d6423SLionel Sambuc  * FUNCTION:    AcpiEvCreateGpeBlock
349433d6423SLionel Sambuc  *
350433d6423SLionel Sambuc  * PARAMETERS:  GpeDevice           - Handle to the parent GPE block
351433d6423SLionel Sambuc  *              GpeBlockAddress     - Address and SpaceID
352433d6423SLionel Sambuc  *              RegisterCount       - Number of GPE register pairs in the block
353433d6423SLionel Sambuc  *              GpeBlockBaseNumber  - Starting GPE number for the block
354433d6423SLionel Sambuc  *              InterruptNumber     - H/W interrupt for the block
355433d6423SLionel Sambuc  *              ReturnGpeBlock      - Where the new block descriptor is returned
356433d6423SLionel Sambuc  *
357433d6423SLionel Sambuc  * RETURN:      Status
358433d6423SLionel Sambuc  *
359433d6423SLionel Sambuc  * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
360433d6423SLionel Sambuc  *              the block are disabled at exit.
361433d6423SLionel Sambuc  *              Note: Assumes namespace is locked.
362433d6423SLionel Sambuc  *
363433d6423SLionel Sambuc  ******************************************************************************/
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc ACPI_STATUS
AcpiEvCreateGpeBlock(ACPI_NAMESPACE_NODE * GpeDevice,UINT64 Address,UINT8 SpaceId,UINT32 RegisterCount,UINT16 GpeBlockBaseNumber,UINT32 InterruptNumber,ACPI_GPE_BLOCK_INFO ** ReturnGpeBlock)366433d6423SLionel Sambuc AcpiEvCreateGpeBlock (
367433d6423SLionel Sambuc     ACPI_NAMESPACE_NODE     *GpeDevice,
368*29492bb7SDavid van Moolenbroek     UINT64                  Address,
369*29492bb7SDavid van Moolenbroek     UINT8                   SpaceId,
370433d6423SLionel Sambuc     UINT32                  RegisterCount,
371*29492bb7SDavid van Moolenbroek     UINT16                  GpeBlockBaseNumber,
372433d6423SLionel Sambuc     UINT32                  InterruptNumber,
373433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     **ReturnGpeBlock)
374433d6423SLionel Sambuc {
375433d6423SLionel Sambuc     ACPI_STATUS             Status;
376433d6423SLionel Sambuc     ACPI_GPE_BLOCK_INFO     *GpeBlock;
377433d6423SLionel Sambuc     ACPI_GPE_WALK_INFO      WalkInfo;
378433d6423SLionel Sambuc 
379433d6423SLionel Sambuc 
380433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (EvCreateGpeBlock);
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc     if (!RegisterCount)
384433d6423SLionel Sambuc     {
385433d6423SLionel Sambuc         return_ACPI_STATUS (AE_OK);
386433d6423SLionel Sambuc     }
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc     /* Allocate a new GPE block */
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc     GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO));
391433d6423SLionel Sambuc     if (!GpeBlock)
392433d6423SLionel Sambuc     {
393433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NO_MEMORY);
394433d6423SLionel Sambuc     }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc     /* Initialize the new GPE block */
397433d6423SLionel Sambuc 
398*29492bb7SDavid van Moolenbroek     GpeBlock->Address = Address;
399*29492bb7SDavid van Moolenbroek     GpeBlock->SpaceId = SpaceId;
400433d6423SLionel Sambuc     GpeBlock->Node = GpeDevice;
401433d6423SLionel Sambuc     GpeBlock->GpeCount = (UINT16) (RegisterCount * ACPI_GPE_REGISTER_WIDTH);
402*29492bb7SDavid van Moolenbroek     GpeBlock->Initialized = FALSE;
403433d6423SLionel Sambuc     GpeBlock->RegisterCount = RegisterCount;
404433d6423SLionel Sambuc     GpeBlock->BlockBaseNumber = GpeBlockBaseNumber;
405433d6423SLionel Sambuc 
406433d6423SLionel Sambuc     /*
407433d6423SLionel Sambuc      * Create the RegisterInfo and EventInfo sub-structures
408433d6423SLionel Sambuc      * Note: disables and clears all GPEs in the block
409433d6423SLionel Sambuc      */
410433d6423SLionel Sambuc     Status = AcpiEvCreateGpeInfoBlocks (GpeBlock);
411433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
412433d6423SLionel Sambuc     {
413433d6423SLionel Sambuc         ACPI_FREE (GpeBlock);
414433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
415433d6423SLionel Sambuc     }
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc     /* Install the new block in the global lists */
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc     Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber);
420433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
421433d6423SLionel Sambuc     {
422*29492bb7SDavid van Moolenbroek         ACPI_FREE (GpeBlock->RegisterInfo);
423*29492bb7SDavid van Moolenbroek         ACPI_FREE (GpeBlock->EventInfo);
424433d6423SLionel Sambuc         ACPI_FREE (GpeBlock);
425433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
426433d6423SLionel Sambuc     }
427433d6423SLionel Sambuc 
428*29492bb7SDavid van Moolenbroek     AcpiGbl_AllGpesInitialized = FALSE;
429*29492bb7SDavid van Moolenbroek 
430433d6423SLionel Sambuc     /* Find all GPE methods (_Lxx or_Exx) for this block */
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc     WalkInfo.GpeBlock = GpeBlock;
433433d6423SLionel Sambuc     WalkInfo.GpeDevice = GpeDevice;
434433d6423SLionel Sambuc     WalkInfo.ExecuteByOwnerId = FALSE;
435433d6423SLionel Sambuc 
436433d6423SLionel Sambuc     Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice,
437433d6423SLionel Sambuc                 ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
438433d6423SLionel Sambuc                 AcpiEvMatchGpeMethod, NULL, &WalkInfo, NULL);
439433d6423SLionel Sambuc 
440433d6423SLionel Sambuc     /* Return the new block */
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc     if (ReturnGpeBlock)
443433d6423SLionel Sambuc     {
444433d6423SLionel Sambuc         (*ReturnGpeBlock) = GpeBlock;
445433d6423SLionel Sambuc     }
446433d6423SLionel Sambuc 
447*29492bb7SDavid van Moolenbroek     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
448*29492bb7SDavid van Moolenbroek         "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
449433d6423SLionel Sambuc         (UINT32) GpeBlock->BlockBaseNumber,
450433d6423SLionel Sambuc         (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1)),
451*29492bb7SDavid van Moolenbroek         GpeDevice->Name.Ascii, GpeBlock->RegisterCount, InterruptNumber,
452*29492bb7SDavid van Moolenbroek         InterruptNumber == AcpiGbl_FADT.SciInterrupt ? " (SCI)" : ""));
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc     /* Update global count of currently available GPEs */
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc     AcpiCurrentGpeCount += GpeBlock->GpeCount;
457433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc 
461433d6423SLionel Sambuc /*******************************************************************************
462433d6423SLionel Sambuc  *
463433d6423SLionel Sambuc  * FUNCTION:    AcpiEvInitializeGpeBlock
464433d6423SLionel Sambuc  *
465*29492bb7SDavid van Moolenbroek  * PARAMETERS:  ACPI_GPE_CALLBACK
466433d6423SLionel Sambuc  *
467433d6423SLionel Sambuc  * RETURN:      Status
468433d6423SLionel Sambuc  *
469*29492bb7SDavid van Moolenbroek  * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
470*29492bb7SDavid van Moolenbroek  *              associated methods.
471433d6423SLionel Sambuc  *              Note: Assumes namespace is locked.
472433d6423SLionel Sambuc  *
473433d6423SLionel Sambuc  ******************************************************************************/
474433d6423SLionel Sambuc 
475433d6423SLionel Sambuc ACPI_STATUS
AcpiEvInitializeGpeBlock(ACPI_GPE_XRUPT_INFO * GpeXruptInfo,ACPI_GPE_BLOCK_INFO * GpeBlock,void * Ignored)476433d6423SLionel Sambuc AcpiEvInitializeGpeBlock (
477*29492bb7SDavid van Moolenbroek     ACPI_GPE_XRUPT_INFO     *GpeXruptInfo,
478*29492bb7SDavid van Moolenbroek     ACPI_GPE_BLOCK_INFO     *GpeBlock,
479*29492bb7SDavid van Moolenbroek     void                    *Ignored)
480433d6423SLionel Sambuc {
481433d6423SLionel Sambuc     ACPI_STATUS             Status;
482433d6423SLionel Sambuc     ACPI_GPE_EVENT_INFO     *GpeEventInfo;
483433d6423SLionel Sambuc     UINT32                  GpeEnabledCount;
484433d6423SLionel Sambuc     UINT32                  GpeIndex;
485433d6423SLionel Sambuc     UINT32                  i;
486433d6423SLionel Sambuc     UINT32                  j;
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc 
489433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (EvInitializeGpeBlock);
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc 
492*29492bb7SDavid van Moolenbroek     /*
493*29492bb7SDavid van Moolenbroek      * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
494*29492bb7SDavid van Moolenbroek      * any GPE blocks that have been initialized already.
495*29492bb7SDavid van Moolenbroek      */
496*29492bb7SDavid van Moolenbroek     if (!GpeBlock || GpeBlock->Initialized)
497433d6423SLionel Sambuc     {
498433d6423SLionel Sambuc         return_ACPI_STATUS (AE_OK);
499433d6423SLionel Sambuc     }
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc     /*
502*29492bb7SDavid van Moolenbroek      * Enable all GPEs that have a corresponding method and have the
503*29492bb7SDavid van Moolenbroek      * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
504*29492bb7SDavid van Moolenbroek      * must be enabled via the acpi_enable_gpe() interface.
505433d6423SLionel Sambuc      */
506433d6423SLionel Sambuc     GpeEnabledCount = 0;
507433d6423SLionel Sambuc 
508433d6423SLionel Sambuc     for (i = 0; i < GpeBlock->RegisterCount; i++)
509433d6423SLionel Sambuc     {
510433d6423SLionel Sambuc         for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++)
511433d6423SLionel Sambuc         {
512433d6423SLionel Sambuc             /* Get the info block for this particular GPE */
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc             GpeIndex = (i * ACPI_GPE_REGISTER_WIDTH) + j;
515433d6423SLionel Sambuc             GpeEventInfo = &GpeBlock->EventInfo[GpeIndex];
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc             /*
518*29492bb7SDavid van Moolenbroek              * Ignore GPEs that have no corresponding _Lxx/_Exx method
519*29492bb7SDavid van Moolenbroek              * and GPEs that are used to wake the system
520433d6423SLionel Sambuc              */
521*29492bb7SDavid van Moolenbroek             if (((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NONE) ||
522*29492bb7SDavid van Moolenbroek                 ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) ||
523*29492bb7SDavid van Moolenbroek                 (GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
524433d6423SLionel Sambuc             {
525433d6423SLionel Sambuc                 continue;
526433d6423SLionel Sambuc             }
527433d6423SLionel Sambuc 
528*29492bb7SDavid van Moolenbroek             Status = AcpiEvAddGpeReference (GpeEventInfo);
529433d6423SLionel Sambuc             if (ACPI_FAILURE (Status))
530433d6423SLionel Sambuc             {
531433d6423SLionel Sambuc                 ACPI_EXCEPTION ((AE_INFO, Status,
532*29492bb7SDavid van Moolenbroek                     "Could not enable GPE 0x%02X",
533*29492bb7SDavid van Moolenbroek                     GpeIndex + GpeBlock->BlockBaseNumber));
534433d6423SLionel Sambuc                 continue;
535433d6423SLionel Sambuc             }
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc             GpeEnabledCount++;
538433d6423SLionel Sambuc         }
539433d6423SLionel Sambuc     }
540433d6423SLionel Sambuc 
541*29492bb7SDavid van Moolenbroek     if (GpeEnabledCount)
542433d6423SLionel Sambuc     {
543*29492bb7SDavid van Moolenbroek         ACPI_INFO ((AE_INFO,
544*29492bb7SDavid van Moolenbroek             "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount,
545*29492bb7SDavid van Moolenbroek             (UINT32) GpeBlock->BlockBaseNumber,
546*29492bb7SDavid van Moolenbroek             (UINT32) (GpeBlock->BlockBaseNumber + (GpeBlock->GpeCount - 1))));
547433d6423SLionel Sambuc     }
548433d6423SLionel Sambuc 
549*29492bb7SDavid van Moolenbroek     GpeBlock->Initialized = TRUE;
550433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
551433d6423SLionel Sambuc }
552433d6423SLionel Sambuc 
553*29492bb7SDavid van Moolenbroek #endif /* !ACPI_REDUCED_HARDWARE */
554