1 /******************************************************************************
3 * Module Name: evgpeblk - GPE block creation and initialization.
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
49 #define _COMPONENT ACPI_EVENTS
50 ACPI_MODULE_NAME ("evgpeblk")
52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
54 /* Local prototypes */
57 AcpiEvInstallGpeBlock (
58 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
59 UINT32 InterruptNumber
);
62 AcpiEvCreateGpeInfoBlocks (
63 ACPI_GPE_BLOCK_INFO
*GpeBlock
);
66 /*******************************************************************************
68 * FUNCTION: AcpiEvInstallGpeBlock
70 * PARAMETERS: GpeBlock - New GPE block
71 * InterruptNumber - Xrupt to be associated with this
76 * DESCRIPTION: Install new GPE block with mutex support
78 ******************************************************************************/
81 AcpiEvInstallGpeBlock (
82 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
83 UINT32 InterruptNumber
)
85 ACPI_GPE_BLOCK_INFO
*NextGpeBlock
;
86 ACPI_GPE_XRUPT_INFO
*GpeXruptBlock
;
91 ACPI_FUNCTION_TRACE (EvInstallGpeBlock
);
94 Status
= AcpiUtAcquireMutex (ACPI_MTX_EVENTS
);
95 if (ACPI_FAILURE (Status
))
97 return_ACPI_STATUS (Status
);
100 GpeXruptBlock
= AcpiEvGetGpeXruptBlock (InterruptNumber
);
103 Status
= AE_NO_MEMORY
;
107 /* Install the new block at the end of the list with lock */
109 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
110 if (GpeXruptBlock
->GpeBlockListHead
)
112 NextGpeBlock
= GpeXruptBlock
->GpeBlockListHead
;
113 while (NextGpeBlock
->Next
)
115 NextGpeBlock
= NextGpeBlock
->Next
;
118 NextGpeBlock
->Next
= GpeBlock
;
119 GpeBlock
->Previous
= NextGpeBlock
;
123 GpeXruptBlock
->GpeBlockListHead
= GpeBlock
;
126 GpeBlock
->XruptBlock
= GpeXruptBlock
;
127 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
131 Status
= AcpiUtReleaseMutex (ACPI_MTX_EVENTS
);
132 return_ACPI_STATUS (Status
);
136 /*******************************************************************************
138 * FUNCTION: AcpiEvDeleteGpeBlock
140 * PARAMETERS: GpeBlock - Existing GPE block
144 * DESCRIPTION: Remove a GPE block
146 ******************************************************************************/
149 AcpiEvDeleteGpeBlock (
150 ACPI_GPE_BLOCK_INFO
*GpeBlock
)
153 ACPI_CPU_FLAGS Flags
;
156 ACPI_FUNCTION_TRACE (EvInstallGpeBlock
);
159 Status
= AcpiUtAcquireMutex (ACPI_MTX_EVENTS
);
160 if (ACPI_FAILURE (Status
))
162 return_ACPI_STATUS (Status
);
165 /* Disable all GPEs in this block */
167 Status
= AcpiHwDisableGpeBlock (GpeBlock
->XruptBlock
, GpeBlock
, NULL
);
169 if (!GpeBlock
->Previous
&& !GpeBlock
->Next
)
171 /* This is the last GpeBlock on this interrupt */
173 Status
= AcpiEvDeleteGpeXrupt (GpeBlock
->XruptBlock
);
174 if (ACPI_FAILURE (Status
))
181 /* Remove the block on this interrupt with lock */
183 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
184 if (GpeBlock
->Previous
)
186 GpeBlock
->Previous
->Next
= GpeBlock
->Next
;
190 GpeBlock
->XruptBlock
->GpeBlockListHead
= GpeBlock
->Next
;
195 GpeBlock
->Next
->Previous
= GpeBlock
->Previous
;
197 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
200 AcpiCurrentGpeCount
-= GpeBlock
->GpeCount
;
202 /* Free the GpeBlock */
204 ACPI_FREE (GpeBlock
->RegisterInfo
);
205 ACPI_FREE (GpeBlock
->EventInfo
);
206 ACPI_FREE (GpeBlock
);
209 Status
= AcpiUtReleaseMutex (ACPI_MTX_EVENTS
);
210 return_ACPI_STATUS (Status
);
214 /*******************************************************************************
216 * FUNCTION: AcpiEvCreateGpeInfoBlocks
218 * PARAMETERS: GpeBlock - New GPE block
222 * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
224 ******************************************************************************/
227 AcpiEvCreateGpeInfoBlocks (
228 ACPI_GPE_BLOCK_INFO
*GpeBlock
)
230 ACPI_GPE_REGISTER_INFO
*GpeRegisterInfo
= NULL
;
231 ACPI_GPE_EVENT_INFO
*GpeEventInfo
= NULL
;
232 ACPI_GPE_EVENT_INFO
*ThisEvent
;
233 ACPI_GPE_REGISTER_INFO
*ThisRegister
;
239 ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks
);
242 /* Allocate the GPE register information block */
244 GpeRegisterInfo
= ACPI_ALLOCATE_ZEROED (
245 (ACPI_SIZE
) GpeBlock
->RegisterCount
*
246 sizeof (ACPI_GPE_REGISTER_INFO
));
247 if (!GpeRegisterInfo
)
249 ACPI_ERROR ((AE_INFO
,
250 "Could not allocate the GpeRegisterInfo table"));
251 return_ACPI_STATUS (AE_NO_MEMORY
);
255 * Allocate the GPE EventInfo block. There are eight distinct GPEs
256 * per register. Initialization to zeros is sufficient.
258 GpeEventInfo
= ACPI_ALLOCATE_ZEROED ((ACPI_SIZE
) GpeBlock
->GpeCount
*
259 sizeof (ACPI_GPE_EVENT_INFO
));
262 ACPI_ERROR ((AE_INFO
,
263 "Could not allocate the GpeEventInfo table"));
264 Status
= AE_NO_MEMORY
;
268 /* Save the new Info arrays in the GPE block */
270 GpeBlock
->RegisterInfo
= GpeRegisterInfo
;
271 GpeBlock
->EventInfo
= GpeEventInfo
;
274 * Initialize the GPE Register and Event structures. A goal of these
275 * tables is to hide the fact that there are two separate GPE register
276 * sets in a given GPE hardware block, the status registers occupy the
277 * first half, and the enable registers occupy the second half.
279 ThisRegister
= GpeRegisterInfo
;
280 ThisEvent
= GpeEventInfo
;
282 for (i
= 0; i
< GpeBlock
->RegisterCount
; i
++)
284 /* Init the RegisterInfo for this GPE register (8 GPEs) */
286 ThisRegister
->BaseGpeNumber
= (UINT8
) (GpeBlock
->BlockBaseNumber
+
287 (i
* ACPI_GPE_REGISTER_WIDTH
));
289 ThisRegister
->StatusAddress
.Address
=
290 GpeBlock
->BlockAddress
.Address
+ i
;
292 ThisRegister
->EnableAddress
.Address
=
293 GpeBlock
->BlockAddress
.Address
+ i
+ GpeBlock
->RegisterCount
;
295 ThisRegister
->StatusAddress
.SpaceId
= GpeBlock
->BlockAddress
.SpaceId
;
296 ThisRegister
->EnableAddress
.SpaceId
= GpeBlock
->BlockAddress
.SpaceId
;
297 ThisRegister
->StatusAddress
.BitWidth
= ACPI_GPE_REGISTER_WIDTH
;
298 ThisRegister
->EnableAddress
.BitWidth
= ACPI_GPE_REGISTER_WIDTH
;
299 ThisRegister
->StatusAddress
.BitOffset
= 0;
300 ThisRegister
->EnableAddress
.BitOffset
= 0;
302 /* Init the EventInfo for each GPE within this register */
304 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++)
306 ThisEvent
->GpeNumber
= (UINT8
) (ThisRegister
->BaseGpeNumber
+ j
);
307 ThisEvent
->RegisterInfo
= ThisRegister
;
311 /* Disable all GPEs within this register */
313 Status
= AcpiHwWrite (0x00, &ThisRegister
->EnableAddress
);
314 if (ACPI_FAILURE (Status
))
319 /* Clear any pending GPE events within this register */
321 Status
= AcpiHwWrite (0xFF, &ThisRegister
->StatusAddress
);
322 if (ACPI_FAILURE (Status
))
330 return_ACPI_STATUS (AE_OK
);
336 ACPI_FREE (GpeRegisterInfo
);
340 ACPI_FREE (GpeEventInfo
);
343 return_ACPI_STATUS (Status
);
347 /*******************************************************************************
349 * FUNCTION: AcpiEvCreateGpeBlock
351 * PARAMETERS: GpeDevice - Handle to the parent GPE block
352 * GpeBlockAddress - Address and SpaceID
353 * RegisterCount - Number of GPE register pairs in the block
354 * GpeBlockBaseNumber - Starting GPE number for the block
355 * InterruptNumber - H/W interrupt for the block
356 * ReturnGpeBlock - Where the new block descriptor is returned
360 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
361 * the block are disabled at exit.
362 * Note: Assumes namespace is locked.
364 ******************************************************************************/
367 AcpiEvCreateGpeBlock (
368 ACPI_NAMESPACE_NODE
*GpeDevice
,
369 ACPI_GENERIC_ADDRESS
*GpeBlockAddress
,
370 UINT32 RegisterCount
,
371 UINT8 GpeBlockBaseNumber
,
372 UINT32 InterruptNumber
,
373 ACPI_GPE_BLOCK_INFO
**ReturnGpeBlock
)
376 ACPI_GPE_BLOCK_INFO
*GpeBlock
;
377 ACPI_GPE_WALK_INFO WalkInfo
;
380 ACPI_FUNCTION_TRACE (EvCreateGpeBlock
);
385 return_ACPI_STATUS (AE_OK
);
388 /* Allocate a new GPE block */
390 GpeBlock
= ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO
));
393 return_ACPI_STATUS (AE_NO_MEMORY
);
396 /* Initialize the new GPE block */
398 GpeBlock
->Node
= GpeDevice
;
399 GpeBlock
->GpeCount
= (UINT16
) (RegisterCount
* ACPI_GPE_REGISTER_WIDTH
);
400 GpeBlock
->Initialized
= FALSE
;
401 GpeBlock
->RegisterCount
= RegisterCount
;
402 GpeBlock
->BlockBaseNumber
= GpeBlockBaseNumber
;
404 ACPI_MEMCPY (&GpeBlock
->BlockAddress
, GpeBlockAddress
,
405 sizeof (ACPI_GENERIC_ADDRESS
));
408 * Create the RegisterInfo and EventInfo sub-structures
409 * Note: disables and clears all GPEs in the block
411 Status
= AcpiEvCreateGpeInfoBlocks (GpeBlock
);
412 if (ACPI_FAILURE (Status
))
414 ACPI_FREE (GpeBlock
);
415 return_ACPI_STATUS (Status
);
418 /* Install the new block in the global lists */
420 Status
= AcpiEvInstallGpeBlock (GpeBlock
, InterruptNumber
);
421 if (ACPI_FAILURE (Status
))
423 ACPI_FREE (GpeBlock
->RegisterInfo
);
424 ACPI_FREE (GpeBlock
->EventInfo
);
425 ACPI_FREE (GpeBlock
);
426 return_ACPI_STATUS (Status
);
429 AcpiGbl_AllGpesInitialized
= FALSE
;
431 /* Find all GPE methods (_Lxx or_Exx) for this block */
433 WalkInfo
.GpeBlock
= GpeBlock
;
434 WalkInfo
.GpeDevice
= GpeDevice
;
435 WalkInfo
.ExecuteByOwnerId
= FALSE
;
437 Status
= AcpiNsWalkNamespace (ACPI_TYPE_METHOD
, GpeDevice
,
438 ACPI_UINT32_MAX
, ACPI_NS_WALK_NO_UNLOCK
,
439 AcpiEvMatchGpeMethod
, NULL
, &WalkInfo
, NULL
);
441 /* Return the new block */
445 (*ReturnGpeBlock
) = GpeBlock
;
448 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT
,
449 " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n",
450 (UINT32
) GpeBlock
->BlockBaseNumber
,
451 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1)),
452 GpeDevice
->Name
.Ascii
, GpeBlock
->RegisterCount
,
455 /* Update global count of currently available GPEs */
457 AcpiCurrentGpeCount
+= GpeBlock
->GpeCount
;
458 return_ACPI_STATUS (AE_OK
);
462 /*******************************************************************************
464 * FUNCTION: AcpiEvInitializeGpeBlock
466 * PARAMETERS: ACPI_GPE_CALLBACK
470 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
471 * associated methods.
472 * Note: Assumes namespace is locked.
474 ******************************************************************************/
477 AcpiEvInitializeGpeBlock (
478 ACPI_GPE_XRUPT_INFO
*GpeXruptInfo
,
479 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
483 ACPI_GPE_EVENT_INFO
*GpeEventInfo
;
484 UINT32 GpeEnabledCount
;
490 ACPI_FUNCTION_TRACE (EvInitializeGpeBlock
);
494 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
495 * any GPE blocks that have been initialized already.
497 if (!GpeBlock
|| GpeBlock
->Initialized
)
499 return_ACPI_STATUS (AE_OK
);
503 * Enable all GPEs that have a corresponding method and have the
504 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
505 * must be enabled via the acpi_enable_gpe() interface.
509 for (i
= 0; i
< GpeBlock
->RegisterCount
; i
++)
511 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++)
513 /* Get the info block for this particular GPE */
515 GpeIndex
= (i
* ACPI_GPE_REGISTER_WIDTH
) + j
;
516 GpeEventInfo
= &GpeBlock
->EventInfo
[GpeIndex
];
519 * Ignore GPEs that have no corresponding _Lxx/_Exx method
520 * and GPEs that are used to wake the system
522 if (((GpeEventInfo
->Flags
& ACPI_GPE_DISPATCH_MASK
) == ACPI_GPE_DISPATCH_NONE
) ||
523 ((GpeEventInfo
->Flags
& ACPI_GPE_DISPATCH_MASK
) == ACPI_GPE_DISPATCH_HANDLER
) ||
524 (GpeEventInfo
->Flags
& ACPI_GPE_CAN_WAKE
))
529 Status
= AcpiEvAddGpeReference (GpeEventInfo
);
530 if (ACPI_FAILURE (Status
))
532 ACPI_EXCEPTION ((AE_INFO
, Status
,
533 "Could not enable GPE 0x%02X",
534 GpeIndex
+ GpeBlock
->BlockBaseNumber
));
545 "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount
,
546 (UINT32
) GpeBlock
->BlockBaseNumber
,
547 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1))));
550 GpeBlock
->Initialized
= TRUE
;
551 return_ACPI_STATUS (AE_OK
);
554 #endif /* !ACPI_REDUCED_HARDWARE */