diff options
Diffstat (limited to 'sys/contrib/dev/acpica/evgpe.c')
-rw-r--r-- | sys/contrib/dev/acpica/evgpe.c | 179 |
1 files changed, 114 insertions, 65 deletions
diff --git a/sys/contrib/dev/acpica/evgpe.c b/sys/contrib/dev/acpica/evgpe.c index d19058c..6f6402d 100644 --- a/sys/contrib/dev/acpica/evgpe.c +++ b/sys/contrib/dev/acpica/evgpe.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evgpe - General Purpose Event handling and dispatch - * $Revision: 12 $ + * $Revision: 27 $ * *****************************************************************************/ @@ -126,47 +126,68 @@ * * FUNCTION: AcpiEvGetGpeEventInfo * - * PARAMETERS: GpeNumber - Raw GPE number + * PARAMETERS: GpeDevice - Device node. NULL for GPE0/GPE1 + * GpeNumber - Raw GPE number * - * RETURN: None. + * RETURN: A GPE EventInfo struct. NULL if not a valid GPE * - * DESCRIPTION: Returns the EventInfo struct - * associated with this GPE. + * DESCRIPTION: Returns the EventInfo struct associated with this GPE. + * Validates the GpeBlock and the GpeNumber * - * TBD: this function will go away when full support of GPE block devices - * is implemented! + * Should be called only when the GPE lists are semaphore locked + * and not subject to change. * ******************************************************************************/ ACPI_GPE_EVENT_INFO * AcpiEvGetGpeEventInfo ( + ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { + ACPI_OPERAND_OBJECT *ObjDesc; ACPI_GPE_BLOCK_INFO *GpeBlock; + ACPI_NATIVE_UINT i; - /* Examine GPE Block 0 */ + ACPI_FUNCTION_ENTRY (); - GpeBlock = AcpiGbl_GpeBlockListHead; - if (!GpeBlock) - { - return (NULL); - } - if ((GpeNumber >= GpeBlock->BlockBaseNumber) && - (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8))) + /* A NULL GpeBlock means use the FADT-defined GPE block(s) */ + + if (!GpeDevice) { - return (&GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]); - } + /* Examine GPE Block 0 and 1 (These blocks are permanent) */ + + for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) + { + GpeBlock = AcpiGbl_GpeFadtBlocks[i]; + if (GpeBlock) + { + if ((GpeNumber >= GpeBlock->BlockBaseNumber) && + (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8))) + { + return (&GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]); + } + } + } - /* Examine GPE Block 1 */ + /* The GpeNumber was not in the range of either FADT GPE block */ - GpeBlock = GpeBlock->Next; - if (!GpeBlock) + return (NULL); + } + + /* + * A Non-null GpeDevice means this is a GPE Block Device. + */ + ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) GpeDevice); + if (!ObjDesc || + !ObjDesc->Device.GpeBlock) { return (NULL); } + GpeBlock = ObjDesc->Device.GpeBlock; + if ((GpeNumber >= GpeBlock->BlockBaseNumber) && (GpeNumber < GpeBlock->BlockBaseNumber + (GpeBlock->RegisterCount * 8))) { @@ -176,11 +197,13 @@ AcpiEvGetGpeEventInfo ( return (NULL); } + /******************************************************************************* * * FUNCTION: AcpiEvGpeDetect * - * PARAMETERS: None + * PARAMETERS: GpeXruptList - Interrupt block for this interrupt. + * Can have multiple GPE blocks attached. * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * @@ -190,17 +213,19 @@ AcpiEvGetGpeEventInfo ( ******************************************************************************/ UINT32 -AcpiEvGpeDetect (void) +AcpiEvGpeDetect ( + ACPI_GPE_XRUPT_INFO *GpeXruptList) { UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; - UINT32 i; - UINT32 j; UINT8 EnabledStatusByte; UINT8 BitMask; ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; UINT32 InValue; ACPI_STATUS Status; ACPI_GPE_BLOCK_INFO *GpeBlock; + UINT32 GpeNumber; + UINT32 i; + UINT32 j; ACPI_FUNCTION_NAME ("EvGpeDetect"); @@ -208,7 +233,8 @@ AcpiEvGpeDetect (void) /* Examine all GPE blocks attached to this interrupt level */ - GpeBlock = AcpiGbl_GpeBlockListHead; + AcpiOsAcquireLock (AcpiGbl_GpeLock, ACPI_ISR); + GpeBlock = GpeXruptList->GpeBlockListHead; while (GpeBlock) { /* @@ -222,28 +248,34 @@ AcpiEvGpeDetect (void) GpeRegisterInfo = &GpeBlock->RegisterInfo[i]; + /* Read the Status Register */ + Status = AcpiHwLowLevelRead (ACPI_GPE_REGISTER_WIDTH, &InValue, - &GpeRegisterInfo->StatusAddress, 0); + &GpeRegisterInfo->StatusAddress); GpeRegisterInfo->Status = (UINT8) InValue; if (ACPI_FAILURE (Status)) { - return (ACPI_INTERRUPT_NOT_HANDLED); + goto UnlockAndExit; } + /* Read the Enable Register */ + Status = AcpiHwLowLevelRead (ACPI_GPE_REGISTER_WIDTH, &InValue, - &GpeRegisterInfo->EnableAddress, 0); + &GpeRegisterInfo->EnableAddress); GpeRegisterInfo->Enable = (UINT8) InValue; if (ACPI_FAILURE (Status)) { - return (ACPI_INTERRUPT_NOT_HANDLED); + goto UnlockAndExit; } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, - "GPE block at %8.8X%8.8X - Values: Enable %02X Status %02X\n", + "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", + ACPI_HIDWORD (ACPI_GET_ADDRESS (GpeRegisterInfo->StatusAddress.Address)), + ACPI_LODWORD (ACPI_GET_ADDRESS (GpeRegisterInfo->StatusAddress.Address)), + GpeRegisterInfo->Status, ACPI_HIDWORD (ACPI_GET_ADDRESS (GpeRegisterInfo->EnableAddress.Address)), ACPI_LODWORD (ACPI_GET_ADDRESS (GpeRegisterInfo->EnableAddress.Address)), - GpeRegisterInfo->Enable, - GpeRegisterInfo->Status)); + GpeRegisterInfo->Enable)); /* First check if there is anything active at all in this register */ @@ -268,8 +300,11 @@ AcpiEvGpeDetect (void) * Found an active GPE. Dispatch the event to a handler * or method. */ + GpeNumber = (i * ACPI_GPE_REGISTER_WIDTH) + j; + IntStatus |= AcpiEvGpeDispatch ( - &GpeBlock->EventInfo[(i * ACPI_GPE_REGISTER_WIDTH) +j]); + &GpeBlock->EventInfo[GpeNumber], + GpeNumber + GpeBlock->RegisterInfo[GpeNumber].BaseGpeNumber); } } } @@ -277,6 +312,9 @@ AcpiEvGpeDetect (void) GpeBlock = GpeBlock->Next; } +UnlockAndExit: + + AcpiOsReleaseLock (AcpiGbl_GpeLock, ACPI_ISR); return (IntStatus); } @@ -285,7 +323,7 @@ AcpiEvGpeDetect (void) * * FUNCTION: AcpiEvAsynchExecuteGpeMethod * - * PARAMETERS: GpeEventInfo - Info for this GPE + * PARAMETERS: Context (GpeEventInfo) - Info for this GPE * * RETURN: None * @@ -293,7 +331,7 @@ AcpiEvGpeDetect (void) * function is called from an invocation of AcpiOsQueueForExecution * (and therefore does NOT execute at interrupt level) so that * the control method itself is not executed in the context of - * the SCI interrupt handler. + * an interrupt handler. * ******************************************************************************/ @@ -304,49 +342,60 @@ AcpiEvAsynchExecuteGpeMethod ( ACPI_GPE_EVENT_INFO *GpeEventInfo = (void *) Context; UINT32 GpeNumber = 0; ACPI_STATUS Status; + ACPI_GPE_EVENT_INFO LocalGpeEventInfo; ACPI_FUNCTION_TRACE ("EvAsynchExecuteGpeMethod"); - /* - * Take a snapshot of the GPE info for this level - we copy the - * info to prevent a race condition with RemoveHandler. - */ Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_VOID; } + /* Must revalidate the GpeNumber/GpeBlock */ + + if (!AcpiEvValidGpeEvent (GpeEventInfo)) + { + Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + return_VOID; + } + + /* + * Take a snapshot of the GPE info for this level - we copy the + * info to prevent a race condition with RemoveHandler/RemoveBlock. + */ + ACPI_MEMCPY (&LocalGpeEventInfo, GpeEventInfo, sizeof (ACPI_GPE_EVENT_INFO)); + Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_VOID; } - if (GpeEventInfo->MethodNode) + if (LocalGpeEventInfo.MethodNode) { /* * Invoke the GPE Method (_Lxx, _Exx): * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) */ - Status = AcpiNsEvaluateByHandle (GpeEventInfo->MethodNode, NULL, NULL); + Status = AcpiNsEvaluateByHandle (LocalGpeEventInfo.MethodNode, NULL, NULL); if (ACPI_FAILURE (Status)) { - ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", AcpiFormatException (Status), - GpeEventInfo->MethodNode->Name.Ascii, GpeNumber)); + LocalGpeEventInfo.MethodNode->Name.Ascii, GpeNumber)); } } - if (GpeEventInfo->Type & ACPI_EVENT_LEVEL_TRIGGERED) + if (LocalGpeEventInfo.Flags & ACPI_EVENT_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after handling * the event. */ - Status = AcpiHwClearGpe (GpeEventInfo); + Status = AcpiHwClearGpe (&LocalGpeEventInfo); if (ACPI_FAILURE (Status)) { return_VOID; @@ -355,7 +404,7 @@ AcpiEvAsynchExecuteGpeMethod ( /* Enable this GPE */ - (void) AcpiHwEnableGpe (GpeEventInfo); + (void) AcpiHwEnableGpe (&LocalGpeEventInfo); return_VOID; } @@ -364,21 +413,23 @@ AcpiEvAsynchExecuteGpeMethod ( * * FUNCTION: AcpiEvGpeDispatch * - * PARAMETERS: GpeEventInfo - info for this GPE + * PARAMETERS: GpeEventInfo - info for this GPE + * GpeNumber - Number relative to the parent GPE block * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) - * or method (e.g. _Lxx/_Exx) handler. This function executes - * at interrupt level. + * or method (e.g. _Lxx/_Exx) handler. + * + * This function executes at interrupt level. * ******************************************************************************/ UINT32 AcpiEvGpeDispatch ( - ACPI_GPE_EVENT_INFO *GpeEventInfo) + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 GpeNumber) { - UINT32 GpeNumber = 0; /* TBD: remove */ ACPI_STATUS Status; @@ -389,12 +440,12 @@ AcpiEvGpeDispatch ( * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if (GpeEventInfo->Type & ACPI_EVENT_EDGE_TRIGGERED) + if (GpeEventInfo->Flags & ACPI_EVENT_EDGE_TRIGGERED) { Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { - ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to clear GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to clear GPE[%2X]\n", GpeNumber)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } @@ -422,20 +473,19 @@ AcpiEvGpeDispatch ( Status = AcpiHwDisableGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { - ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to disable GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to disable GPE[%2X]\n", GpeNumber)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } - /* - * Execute the method associated with the GPE. - */ + /* Execute the method associated with the GPE. */ + if (ACPI_FAILURE (AcpiOsQueueForExecution (OSD_PRIORITY_GPE, AcpiEvAsynchExecuteGpeMethod, GpeEventInfo))) { ACPI_REPORT_ERROR (( - "AcpiEvGpeDispatch: Unable to queue handler for GPE[%2.2X], event is disabled\n", + "AcpiEvGpeDispatch: Unable to queue handler for GPE[%2X], event is disabled\n", GpeNumber)); } } @@ -444,7 +494,7 @@ AcpiEvGpeDispatch ( /* No handler or method to run! */ ACPI_REPORT_ERROR (( - "AcpiEvGpeDispatch: No handler or method for GPE[%2.2X], disabling event\n", + "AcpiEvGpeDispatch: No handler or method for GPE[%2X], disabling event\n", GpeNumber)); /* @@ -454,21 +504,20 @@ AcpiEvGpeDispatch ( Status = AcpiHwDisableGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { - ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to disable GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to disable GPE[%2X]\n", GpeNumber)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - /* - * It is now safe to clear level-triggered evnets. - */ - if (GpeEventInfo->Type & ACPI_EVENT_LEVEL_TRIGGERED) + /* It is now safe to clear level-triggered events. */ + + if (GpeEventInfo->Flags & ACPI_EVENT_LEVEL_TRIGGERED) { Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { - ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to clear GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to clear GPE[%2X]\n", GpeNumber)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } |