1 /******************************************************************************
3 * Module Name: evgpeblk - GPE block creation and initialization.
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, 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 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
);
168 if (!GpeBlock
->Previous
&& !GpeBlock
->Next
)
170 /* This is the last GpeBlock on this interrupt */
172 Status
= AcpiEvDeleteGpeXrupt (GpeBlock
->XruptBlock
);
173 if (ACPI_FAILURE (Status
))
180 /* Remove the block on this interrupt with lock */
182 Flags
= AcpiOsAcquireLock (AcpiGbl_GpeLock
);
183 if (GpeBlock
->Previous
)
185 GpeBlock
->Previous
->Next
= GpeBlock
->Next
;
189 GpeBlock
->XruptBlock
->GpeBlockListHead
= GpeBlock
->Next
;
194 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
= (UINT16
)
287 (GpeBlock
->BlockBaseNumber
+ (i
* ACPI_GPE_REGISTER_WIDTH
));
289 ThisRegister
->StatusAddress
.Address
=
290 GpeBlock
->Address
+ i
;
292 ThisRegister
->EnableAddress
.Address
=
293 GpeBlock
->Address
+ i
+ GpeBlock
->RegisterCount
;
295 ThisRegister
->StatusAddress
.SpaceId
= GpeBlock
->SpaceId
;
296 ThisRegister
->EnableAddress
.SpaceId
= GpeBlock
->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
,
371 UINT32 RegisterCount
,
372 UINT16 GpeBlockBaseNumber
,
373 UINT32 InterruptNumber
,
374 ACPI_GPE_BLOCK_INFO
**ReturnGpeBlock
)
377 ACPI_GPE_BLOCK_INFO
*GpeBlock
;
378 ACPI_GPE_WALK_INFO WalkInfo
;
381 ACPI_FUNCTION_TRACE (EvCreateGpeBlock
);
386 return_ACPI_STATUS (AE_OK
);
389 /* Allocate a new GPE block */
391 GpeBlock
= ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO
));
394 return_ACPI_STATUS (AE_NO_MEMORY
);
397 /* Initialize the new GPE block */
399 GpeBlock
->Address
= Address
;
400 GpeBlock
->SpaceId
= SpaceId
;
401 GpeBlock
->Node
= GpeDevice
;
402 GpeBlock
->GpeCount
= (UINT16
) (RegisterCount
* ACPI_GPE_REGISTER_WIDTH
);
403 GpeBlock
->Initialized
= FALSE
;
404 GpeBlock
->RegisterCount
= RegisterCount
;
405 GpeBlock
->BlockBaseNumber
= GpeBlockBaseNumber
;
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%s\n",
450 (UINT32
) GpeBlock
->BlockBaseNumber
,
451 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1)),
452 GpeDevice
->Name
.Ascii
, GpeBlock
->RegisterCount
, InterruptNumber
,
453 InterruptNumber
== AcpiGbl_FADT
.SciInterrupt
? " (SCI)" : ""));
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 ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) == ACPI_GPE_DISPATCH_NONE
) ||
523 (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) == ACPI_GPE_DISPATCH_HANDLER
) ||
524 (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo
->Flags
) == ACPI_GPE_DISPATCH_RAW_HANDLER
) ||
525 (GpeEventInfo
->Flags
& ACPI_GPE_CAN_WAKE
))
530 Status
= AcpiEvAddGpeReference (GpeEventInfo
);
531 if (ACPI_FAILURE (Status
))
533 ACPI_EXCEPTION ((AE_INFO
, Status
,
534 "Could not enable GPE 0x%02X",
535 GpeIndex
+ GpeBlock
->BlockBaseNumber
));
546 "Enabled %u GPEs in block %02X to %02X", GpeEnabledCount
,
547 (UINT32
) GpeBlock
->BlockBaseNumber
,
548 (UINT32
) (GpeBlock
->BlockBaseNumber
+ (GpeBlock
->GpeCount
- 1))));
551 GpeBlock
->Initialized
= TRUE
;
552 return_ACPI_STATUS (AE_OK
);
555 #endif /* !ACPI_REDUCED_HARDWARE */