summaryrefslogtreecommitdiffstats
path: root/sys/contrib/dev/acpica/evgpe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/dev/acpica/evgpe.c')
-rw-r--r--sys/contrib/dev/acpica/evgpe.c179
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);
}
OpenPOWER on IntegriCloud