diff options
Diffstat (limited to 'sys/contrib/dev/acpica/evgpeblk.c')
-rw-r--r-- | sys/contrib/dev/acpica/evgpeblk.c | 256 |
1 files changed, 221 insertions, 35 deletions
diff --git a/sys/contrib/dev/acpica/evgpeblk.c b/sys/contrib/dev/acpica/evgpeblk.c index 75eed44..c28f621 100644 --- a/sys/contrib/dev/acpica/evgpeblk.c +++ b/sys/contrib/dev/acpica/evgpeblk.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evgpeblk - GPE block creation and initialization. - * $Revision: 27 $ + * $Revision: 29 $ * *****************************************************************************/ @@ -247,11 +247,11 @@ UnlockAndExit: * information for quick lookup during GPE dispatch * * The name of each GPE control method is of the form: - * "_Lnn" or "_Enn" - * Where: - * L - means that the GPE is level triggered - * E - means that the GPE is edge triggered - * nn - is the GPE number [in HEX] + * "_Lxx" or "_Exx" + * Where: + * L - means that the GPE is level triggered + * E - means that the GPE is edge triggered + * xx - is the GPE number [in HEX] * ******************************************************************************/ @@ -267,37 +267,42 @@ AcpiEvSaveMethodInfo ( UINT32 GpeNumber; char Name[ACPI_NAME_SIZE + 1]; UINT8 Type; - ACPI_STATUS Status; ACPI_FUNCTION_TRACE ("EvSaveMethodInfo"); - /* Extract the name from the object and convert to a string */ - + /* + * _Lxx and _Exx GPE method support + * + * 1) Extract the name from the object and convert to a string + */ ACPI_MOVE_32_TO_32 (Name, &((ACPI_NAMESPACE_NODE *) ObjHandle)->Name.Integer); Name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd character - * of the method name + * 2) Edge/Level determination is based on the 2nd character + * of the method name + * + * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a + * _PRW object is found that points to this GPE. */ switch (Name[1]) { case 'L': - Type = ACPI_EVENT_LEVEL_TRIGGERED; + Type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; break; case 'E': - Type = ACPI_EVENT_EDGE_TRIGGERED; + Type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; break; default: /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n", + "Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n", Name)); return_ACPI_STATUS (AE_OK); } @@ -310,7 +315,7 @@ AcpiEvSaveMethodInfo ( /* Conversion failed; invalid method, just ignore it */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n", + "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n", Name)); return_ACPI_STATUS (AE_OK); } @@ -337,17 +342,130 @@ AcpiEvSaveMethodInfo ( GpeEventInfo->Flags = Type; GpeEventInfo->MethodNode = (ACPI_NAMESPACE_NODE *) ObjHandle; - /* Enable the GPE (SCIs should be disabled at this point) */ + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, + "Registered GPE method %s as GPE number 0x%.2X\n", + Name, GpeNumber)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvGetGpeType + * + * PARAMETERS: Callback from WalkNamespace + * + * RETURN: Status + * + * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a + * Device. Run the _PRW method. If present, extract the GPE + * number and mark the GPE as a WAKE GPE. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiEvGetGpeType ( + ACPI_HANDLE ObjHandle, + UINT32 Level, + void *Info, + void **ReturnValue) +{ + ACPI_GPE_WALK_INFO *GpeInfo = (void *) Info; + ACPI_NAMESPACE_NODE *GpeDevice; + ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_NAMESPACE_NODE *TargetGpeDevice; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_OPERAND_OBJECT *PkgDesc; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 GpeNumber; + ACPI_STATUS Status; + - Status = AcpiHwEnableGpe (GpeEventInfo); + ACPI_FUNCTION_TRACE ("EvGetGpeType"); + + + /* Check for a _PRW method under this device */ + + Status = AcpiUtEvaluateObject (ObjHandle, METHOD_NAME__PRW, + ACPI_BTYPE_PACKAGE, &PkgDesc); if (ACPI_FAILURE (Status)) { - return_ACPI_STATUS (Status); + /* Ignore all errors from _PRW, we don't want to abort the subsystem */ + + return_ACPI_STATUS (AE_OK); } - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, - "Registered GPE method %s as GPE number 0x%.2X\n", - Name, GpeNumber)); + /* The returned _PRW package must have at least two elements */ + + if (PkgDesc->Package.Count < 2) + { + goto Cleanup; + } + + /* Extract pointers from the input context */ + + GpeDevice = GpeInfo->GpeDevice; + GpeBlock = GpeInfo->GpeBlock; + + /* + * The _PRW object must return a package, we are only interested + * in the first element + */ + ObjDesc = PkgDesc->Package.Elements[0]; + + if (ACPI_GET_OBJECT_TYPE (ObjDesc) == ACPI_TYPE_INTEGER) + { + /* Use FADT-defined GPE device (from definition of _PRW) */ + + TargetGpeDevice = AcpiGbl_FadtGpeDevice; + + /* Integer is the GPE number in the FADT described GPE blocks */ + + GpeNumber = (UINT32) ObjDesc->Integer.Value; + } + else if (ACPI_GET_OBJECT_TYPE (ObjDesc) == ACPI_TYPE_PACKAGE) + { + /* Package contains a GPE reference and GPE number within a GPE block */ + + if ((ObjDesc->Package.Count < 2) || + (ACPI_GET_OBJECT_TYPE (ObjDesc->Package.Elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) || + (ACPI_GET_OBJECT_TYPE (ObjDesc->Package.Elements[1]) != ACPI_TYPE_INTEGER)) + { + goto Cleanup; + } + + /* Get GPE block reference and decode */ + + TargetGpeDevice = ObjDesc->Package.Elements[0]->Reference.Node; + GpeNumber = (UINT32) ObjDesc->Package.Elements[1]->Integer.Value; + } + else + { + /* Unknown type, just ignore it */ + + goto Cleanup; + } + + /* + * Is this GPE within this block? + * + * TRUE iff these conditions are true: + * 1) The GPE devices match. + * 2) The GPE index(number) is within the range of the Gpe Block + * associated with the GPE device. + */ + if ((GpeDevice == TargetGpeDevice) && + (GpeNumber >= GpeBlock->BlockBaseNumber) && + (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8))) + { + /* Mark GPE for WAKE but DISABLED (even for wake) */ + + GpeEventInfo = &GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]; + GpeEventInfo->Flags |= ACPI_GPE_TYPE_WAKE; + } + +Cleanup: + AcpiUtRemoveReference (PkgDesc); return_ACPI_STATUS (AE_OK); } @@ -810,8 +928,13 @@ AcpiEvCreateGpeBlock ( ACPI_GPE_BLOCK_INFO **ReturnGpeBlock) { ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_GPE_EVENT_INFO *GpeEventInfo; + ACPI_NATIVE_UINT i; + ACPI_NATIVE_UINT j; + UINT32 WakeGpeCount; + UINT32 GpeEnabledCount; ACPI_STATUS Status; - + ACPI_GPE_WALK_INFO GpeInfo; ACPI_FUNCTION_TRACE ("EvCreateGpeBlock"); @@ -856,7 +979,8 @@ AcpiEvCreateGpeBlock ( /* Dump info about this GPE block */ - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", GpeBlock->BlockBaseNumber, (UINT32) (GpeBlock->BlockBaseNumber + ((GpeBlock->RegisterCount * ACPI_GPE_REGISTER_WIDTH) -1)), @@ -868,8 +992,66 @@ AcpiEvCreateGpeBlock ( /* Find all GPE methods (_Lxx, _Exx) for this block */ Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice, - ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, AcpiEvSaveMethodInfo, - GpeBlock, NULL); + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, AcpiEvSaveMethodInfo, + GpeBlock, NULL); + + /* + * Runtime option: Should Wake GPEs be enabled at runtime? The default is + * No,they should only be enabled just as the machine goes to sleep. + */ + if (AcpiGbl_LeaveWakeGpesDisabled) + { + /* + * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each + * GPE that has one or more _PRWs that reference it is by definition a + * WAKE GPE and will not be enabled while the machine is running.) + */ + GpeInfo.GpeBlock = GpeBlock; + GpeInfo.GpeDevice = GpeDevice; + + Status = AcpiNsWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, AcpiEvGetGpeType, + &GpeInfo, NULL); + } + + /* + * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have + * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via + * the AcpiEnableGpe() external interface. + */ + WakeGpeCount = 0; + GpeEnabledCount = 0; + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + for (j = 0; j < 8; j++) + { + /* Get the info block for this particular GPE */ + + GpeEventInfo = &GpeBlock->EventInfo[(i * ACPI_GPE_REGISTER_WIDTH) + j]; + if ((GpeEventInfo->MethodNode) && + ((GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) + { + /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */ + + Status = AcpiHwEnableGpe (GpeEventInfo); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + GpeEnabledCount++; + } + + if ((GpeEventInfo->Flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) + { + WakeGpeCount++; + } + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Found %u Wake, Enabled %u Runtime GPEs in this block\n", + WakeGpeCount, GpeEnabledCount)); /* Return the new block */ @@ -895,28 +1077,26 @@ AcpiEvCreateGpeBlock ( ******************************************************************************/ ACPI_STATUS -AcpiEvGpeInitialize (void) +AcpiEvGpeInitialize ( + void) { UINT32 RegisterCount0 = 0; UINT32 RegisterCount1 = 0; UINT32 GpeNumberMax = 0; - ACPI_HANDLE GpeDevice; ACPI_STATUS Status; ACPI_FUNCTION_TRACE ("EvGpeInitialize"); - /* Get a handle to the predefined _GPE object */ - - Status = AcpiGetHandle (NULL, "\\_GPE", &GpeDevice); + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* - * Initialize the GPE Blocks defined in the FADT + * Initialize the GPE Block(s) defined in the FADT * * Why the GPE register block lengths are divided by 2: From the ACPI Spec, * section "General-Purpose Event Registers", we have: @@ -951,8 +1131,9 @@ AcpiEvGpeInitialize (void) /* Install GPE Block 0 */ - Status = AcpiEvCreateGpeBlock (GpeDevice, &AcpiGbl_FADT->XGpe0Blk, + Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, &AcpiGbl_FADT->XGpe0Blk, RegisterCount0, 0, AcpiGbl_FADT->SciInt, &AcpiGbl_GpeFadtBlocks[0]); + if (ACPI_FAILURE (Status)) { ACPI_REPORT_ERROR (( @@ -987,9 +1168,10 @@ AcpiEvGpeInitialize (void) { /* Install GPE Block 1 */ - Status = AcpiEvCreateGpeBlock (GpeDevice, &AcpiGbl_FADT->XGpe1Blk, + Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, &AcpiGbl_FADT->XGpe1Blk, RegisterCount1, AcpiGbl_FADT->Gpe1Base, AcpiGbl_FADT->SciInt, &AcpiGbl_GpeFadtBlocks[1]); + if (ACPI_FAILURE (Status)) { ACPI_REPORT_ERROR (( @@ -1013,7 +1195,8 @@ AcpiEvGpeInitialize (void) /* GPEs are not required by ACPI, this is OK */ ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n")); - return_ACPI_STATUS (AE_OK); + Status = AE_OK; + goto Cleanup; } /* Check for Max GPE number out-of-range */ @@ -1022,9 +1205,12 @@ AcpiEvGpeInitialize (void) { ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n", GpeNumberMax)); - return_ACPI_STATUS (AE_BAD_VALUE); + Status = AE_BAD_VALUE; + goto Cleanup; } +Cleanup: + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_OK); } |