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