1 /******************************************************************************
3 * Module Name: evgpeblk - GPE block creation and initialization.
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 Status
= AcpiEvGetGpeXruptBlock (InterruptNumber
, &GpeXruptBlock
);
101 if (ACPI_FAILURE (Status
))
106 /* Install the new block at the end of the list with lock */
108 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
109 if (GpeXruptBlock
->GpeBlockListHead
)
111 NextGpeBlock
= GpeXruptBlock
->GpeBlockListHead
;
112 while (NextGpeBlock
->Next
)
114 NextGpeBlock
= NextGpeBlock
->Next
;
117 NextGpeBlock
->Next
= GpeBlock
;
118 GpeBlock
->Previous
= NextGpeBlock
;
122 GpeXruptBlock
->GpeBlockListHead
= GpeBlock
;
125 GpeBlock
->XruptBlock
= GpeXruptBlock
;
126 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
130 (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS
);
131 return_ACPI_STATUS (Status
);
135 /*******************************************************************************
137 * FUNCTION: AcpiEvDeleteGpeBlock
139 * PARAMETERS: GpeBlock - Existing GPE block
143 * DESCRIPTION: Remove a GPE block
145 ******************************************************************************/
148 AcpiEvDeleteGpeBlock (
149 ACPI_GPE_BLOCK_INFO
*GpeBlock
)
152 ACPI_CPU_FLAGS Flags
;
155 ACPI_FUNCTION_TRACE (EvInstallGpeBlock
);
158 Status
= AcpiUtAcquireMutex (ACPI_MTX_EVENTS
);
159 if (ACPI_FAILURE (Status
))
161 return_ACPI_STATUS (Status
);
164 /* Disable all GPEs in this block */
166 Status
= AcpiHwDisableGpeBlock (GpeBlock
->XruptBlock
, GpeBlock
, NULL
);
167 if (ACPI_FAILURE (Status
))
169 return_ACPI_STATUS (Status
);
172 if (!GpeBlock
->Previous
&& !GpeBlock
->Next
)
174 /* This is the last GpeBlock on this interrupt */
176 Status
= AcpiEvDeleteGpeXrupt (GpeBlock
->XruptBlock
);
177 if (ACPI_FAILURE (Status
))
184 /* Remove the block on this interrupt with lock */
186 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
187 if (GpeBlock
->Previous
)
189 GpeBlock
->Previous
->Next
= GpeBlock
->Next
;
193 GpeBlock
->XruptBlock
->GpeBlockListHead
= GpeBlock
->Next
;
198 GpeBlock
->Next
->Previous
= GpeBlock
->Previous
;
201 AcpiOsReleaseLock (AcpiGbl_GpeLock
, Flags
);
204 AcpiCurrentGpeCount
-= GpeBlock
->GpeCount
;
206 /* Free the GpeBlock */
208 ACPI_FREE (GpeBlock
->RegisterInfo
);
209 ACPI_FREE (GpeBlock
->EventInfo
);
210 ACPI_FREE (GpeBlock
);
213 Status
= AcpiUtReleaseMutex (ACPI_MTX_EVENTS
);
214 return_ACPI_STATUS (Status
);
218 /*******************************************************************************
220 * FUNCTION: AcpiEvCreateGpeInfoBlocks
222 * PARAMETERS: GpeBlock - New GPE block
226 * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block
228 ******************************************************************************/
231 AcpiEvCreateGpeInfoBlocks (
232 ACPI_GPE_BLOCK_INFO
*GpeBlock
)
234 ACPI_GPE_REGISTER_INFO
*GpeRegisterInfo
= NULL
;
235 ACPI_GPE_EVENT_INFO
*GpeEventInfo
= NULL
;
236 ACPI_GPE_EVENT_INFO
*ThisEvent
;
237 ACPI_GPE_REGISTER_INFO
*ThisRegister
;
243 ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks
);
246 /* Allocate the GPE register information block */
248 GpeRegisterInfo
= ACPI_ALLOCATE_ZEROED (
249 (ACPI_SIZE
) GpeBlock
->RegisterCount
*
250 sizeof (ACPI_GPE_REGISTER_INFO
));
251 if (!GpeRegisterInfo
)
253 ACPI_ERROR ((AE_INFO
,
254 "Could not allocate the GpeRegisterInfo table"));
255 return_ACPI_STATUS (AE_NO_MEMORY
);
259 * Allocate the GPE EventInfo block. There are eight distinct GPEs
260 * per register. Initialization to zeros is sufficient.
262 GpeEventInfo
= ACPI_ALLOCATE_ZEROED ((ACPI_SIZE
) GpeBlock
->GpeCount
*
263 sizeof (ACPI_GPE_EVENT_INFO
));
266 ACPI_ERROR ((AE_INFO
,
267 "Could not allocate the GpeEventInfo table"));
268 Status
= AE_NO_MEMORY
;
272 /* Save the new Info arrays in the GPE block */
274 GpeBlock
->RegisterInfo
= GpeRegisterInfo
;
275 GpeBlock
->EventInfo
= GpeEventInfo
;
278 * Initialize the GPE Register and Event structures. A goal of these
279 * tables is to hide the fact that there are two separate GPE register
280 * sets in a given GPE hardware block, the status registers occupy the
281 * first half, and the enable registers occupy the second half.
283 ThisRegister
= GpeRegisterInfo
;
284 ThisEvent
= GpeEventInfo
;
286 for (i
= 0; i
< GpeBlock
->RegisterCount
; i
++)
288 /* Init the RegisterInfo for this GPE register (8 GPEs) */
290 ThisRegister
->BaseGpeNumber
= (UINT16
)
291 (GpeBlock
->BlockBaseNumber
+ (i
* ACPI_GPE_REGISTER_WIDTH
));
293 ThisRegister
->StatusAddress
.Address
=
294 GpeBlock
->Address
+ i
;
296 ThisRegister
->EnableAddress
.Address
=
297 GpeBlock
->Address
+ i
+ GpeBlock
->RegisterCount
;
299 ThisRegister
->StatusAddress
.SpaceId
= GpeBlock
->SpaceId
;
300 ThisRegister
->EnableAddress
.SpaceId
= GpeBlock
->SpaceId
;
301 ThisRegister
->StatusAddress
.BitWidth
= ACPI_GPE_REGISTER_WIDTH
;
302 ThisRegister
->EnableAddress
.BitWidth
= ACPI_GPE_REGISTER_WIDTH
;
303 ThisRegister
->StatusAddress
.BitOffset
= 0;
304 ThisRegister
->EnableAddress
.BitOffset
= 0;
306 /* Init the EventInfo for each GPE within this register */
308 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++)
310 ThisEvent
->GpeNumber
= (UINT8
) (ThisRegister
->BaseGpeNumber
+ j
);
311 ThisEvent
->RegisterInfo
= ThisRegister
;
315 /* Disable all GPEs within this register */
317 Status
= AcpiHwWrite (0x00, &ThisRegister
->EnableAddress
);
318 if (ACPI_FAILURE (Status
))
323 /* Clear any pending GPE events within this register */
325 Status
= AcpiHwWrite (0xFF, &ThisRegister
->StatusAddress
);
326 if (ACPI_FAILURE (Status
))
334 return_ACPI_STATUS (AE_OK
);
340 ACPI_FREE (GpeRegisterInfo
);
344 ACPI_FREE (GpeEventInfo
);
347 return_ACPI_STATUS (Status
);
351 /*******************************************************************************
353 * FUNCTION: AcpiEvCreateGpeBlock
355 * PARAMETERS: GpeDevice - Handle to the parent GPE block
356 * GpeBlockAddress - Address and SpaceID
357 * RegisterCount - Number of GPE register pairs in the block
358 * GpeBlockBaseNumber - Starting GPE number for the block
359 * InterruptNumber - H/W interrupt for the block
360 * ReturnGpeBlock - Where the new block descriptor is returned
364 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
365 * the block are disabled at exit.
366 * Note: Assumes namespace is locked.
368 ******************************************************************************/
371 AcpiEvCreateGpeBlock (
372 ACPI_NAMESPACE_NODE
*GpeDevice
,
375 UINT32 RegisterCount
,
376 UINT16 GpeBlockBaseNumber
,
377 UINT32 InterruptNumber
,
378 ACPI_GPE_BLOCK_INFO
**ReturnGpeBlock
)
381 ACPI_GPE_BLOCK_INFO
*GpeBlock
;
382 ACPI_GPE_WALK_INFO WalkInfo
;
385 ACPI_FUNCTION_TRACE (EvCreateGpeBlock
);
390 return_ACPI_STATUS (AE_OK
);
393 /* Allocate a new GPE block */
395 GpeBlock
= ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO
));
398 return_ACPI_STATUS (AE_NO_MEMORY
);
401 /* Initialize the new GPE block */
403 GpeBlock
->Address
= Address
;
404 GpeBlock
->SpaceId
= SpaceId
;
405 GpeBlock
->Node
= GpeDevice
;
406 GpeBlock
->GpeCount
= (UINT16
) (RegisterCount
* ACPI_GPE_REGISTER_WIDTH
);
407 GpeBlock
->Initialized
= FALSE
;
408 GpeBlock
->RegisterCount
= RegisterCount
;
409 GpeBlock
->BlockBaseNumber
= GpeBlockBaseNumber
;
412 * Create the RegisterInfo and EventInfo sub-structures
413 * Note: disables and clears all GPEs in the block
415 Status
= AcpiEvCreateGpeInfoBlocks (GpeBlock
);
416 if (ACPI_FAILURE (Status
))
418 ACPI_FREE (GpeBlock
);
419 return_ACPI_STATUS (Status
);
422 /* Install the new block in the global lists */
424 Status
= AcpiEvInstallGpeBlock (GpeBlock
, InterruptNumber
);
425 if (ACPI_FAILURE (Status
))
427 ACPI_FREE (GpeBlock
->RegisterInfo
);
428 ACPI_FREE (GpeBlock
->EventInfo
);
429 ACPI_FREE (GpeBlock
);
430 return_ACPI_STATUS (Status
);
433 AcpiGbl_AllGpesInitialized
= FALSE
;
435 /* Find all GPE methods (_Lxx or_Exx) for this block */
437 WalkInfo
.GpeBlock
= GpeBlock
;
438 WalkInfo
.GpeDevice
= GpeDevice
;
439 WalkInfo
.ExecuteByOwnerId
= FALSE
;
441 (void) AcpiNsWalkNamespace (ACPI_TYPE_METHOD
, GpeDevice
,
442 ACPI_UINT32_MAX
, ACPI_NS_WALK_NO_UNLOCK
,
443 AcpiEvMatchGpeMethod
, NULL
, &WalkInfo
, NULL
);
445 /* Return the new block */
449 (*ReturnGpeBlock
) = GpeBlock
;
452 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT
,
453 " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
454 (UINT32
) GpeBlock
->BlockBaseNumber
,
455 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1)),
456 GpeDevice
->Name
.Ascii
, GpeBlock
->RegisterCount
, InterruptNumber
,
457 InterruptNumber
== AcpiGbl_FADT
.SciInterrupt
? " (SCI)" : ""));
459 /* Update global count of currently available GPEs */
461 AcpiCurrentGpeCount
+= GpeBlock
->GpeCount
;
462 return_ACPI_STATUS (AE_OK
);
466 /*******************************************************************************
468 * FUNCTION: AcpiEvInitializeGpeBlock
470 * PARAMETERS: ACPI_GPE_CALLBACK
474 * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
475 * associated methods.
476 * Note: Assumes namespace is locked.
478 ******************************************************************************/
481 AcpiEvInitializeGpeBlock (
482 ACPI_GPE_XRUPT_INFO
*GpeXruptInfo
,
483 ACPI_GPE_BLOCK_INFO
*GpeBlock
,
487 ACPI_GPE_EVENT_INFO
*GpeEventInfo
;
488 UINT32 GpeEnabledCount
;
492 BOOLEAN
*IsPollingNeeded
= Context
;
493 ACPI_ERROR_ONLY (UINT32 GpeNumber
);
496 ACPI_FUNCTION_TRACE (EvInitializeGpeBlock
);
500 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
501 * any GPE blocks that have been initialized already.
503 if (!GpeBlock
|| GpeBlock
->Initialized
)
505 return_ACPI_STATUS (AE_OK
);
509 * Enable all GPEs that have a corresponding method and have the
510 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
511 * must be enabled via the acpi_enable_gpe() interface.
515 for (i
= 0; i
< GpeBlock
->RegisterCount
; i
++)
517 for (j
= 0; j
< ACPI_GPE_REGISTER_WIDTH
; j
++)
519 /* Get the info block for this particular GPE */
521 GpeIndex
= (i
* ACPI_GPE_REGISTER_WIDTH
) + j
;
522 GpeEventInfo
= &GpeBlock
->EventInfo
[GpeIndex
];
523 ACPI_ERROR_ONLY(GpeNumber
= GpeBlock
->BlockBaseNumber
+ GpeIndex
);
524 GpeEventInfo
->Flags
|= ACPI_GPE_INITIALIZED
;
527 * Ignore GPEs that have no corresponding _Lxx/_Exx method
528 * and GPEs that are used to wake the system
530 if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) != ACPI_GPE_DISPATCH_METHOD
) ||
531 (GpeEventInfo
->Flags
& ACPI_GPE_CAN_WAKE
))
536 Status
= AcpiEvAddGpeReference (GpeEventInfo
, FALSE
);
537 if (ACPI_FAILURE (Status
))
539 ACPI_EXCEPTION ((AE_INFO
, Status
,
540 "Could not enable GPE 0x%02X",
545 GpeEventInfo
->Flags
|= ACPI_GPE_AUTO_ENABLED
;
547 if (IsPollingNeeded
&&
548 ACPI_GPE_IS_POLLING_NEEDED (GpeEventInfo
))
550 *IsPollingNeeded
= TRUE
;
560 "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount
,
561 (UINT32
) GpeBlock
->BlockBaseNumber
,
562 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1))));
565 GpeBlock
->Initialized
= TRUE
;
566 return_ACPI_STATUS (AE_OK
);
569 #endif /* !ACPI_REDUCED_HARDWARE */