Skip to content

Commit

Permalink
Events: Introduce AcpiMaskGpe() to implement GPE masking mechanism
Browse files Browse the repository at this point in the history
There is a facility in Linux, developers can control the enabling/disabling
of a GPE via /sys/firmware/acpi/interrupts/gpexx. This is mainly for
debugging purposes.

But many users expect to use this facility to implement quirks to mask a
specific GPE when there is a gap in Linux causing this GPE to flood. This
is not working correctly because currently this facility invokes
enabling/disabling counting based GPE driver APIs:
 AcpiEnableGpe()/AcpiDisableGpe()
and the GPE drivers can still affect the count to mess up the GPE
masking purposes.

However, most of the IRQ chip designs allow masking/unmasking IRQs via a
masking bit which is different from the enabled bit to achieve the same
purpose. But the GPE hardware doesn't contain such a feature, this brings
the trouble.

In this patch, we introduce a software mechanism to implement the GPE
masking feature, and AcpiMaskGpe() are provided to the OSPMs to
mask/unmask GPEs in the above mentioned situation instead of
AcpiEnableGpe()/AcpiDisableGpe(). ACPICA BZ 1102. Lv Zheng.

Link: https://bugs.acpica.org/show_bug.cgi?id=1102
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
  • Loading branch information
Lv Zheng committed Jun 23, 2016
1 parent f39a732 commit 23a417c
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 28 deletions.
67 changes: 67 additions & 0 deletions source/components/events/evgpe.c
Expand Up @@ -219,6 +219,70 @@ AcpiEvEnableGpe (
}


/*******************************************************************************
*
* FUNCTION: AcpiEvMaskGpe
*
* PARAMETERS: GpeEventInfo - GPE to be blocked/unblocked
* IsMasked - Whether the GPE is masked or not
*
* RETURN: Status
*
* DESCRIPTION: Unconditionally mask/unmask a GPE during runtime.
*
******************************************************************************/

ACPI_STATUS
AcpiEvMaskGpe (
ACPI_GPE_EVENT_INFO *GpeEventInfo,
BOOLEAN IsMasked)
{
ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;
UINT32 RegisterBit;


ACPI_FUNCTION_TRACE (EvMaskGpe);


GpeRegisterInfo = GpeEventInfo->RegisterInfo;
if (!GpeRegisterInfo)
{
return_ACPI_STATUS (AE_NOT_EXIST);
}

RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo);

/* Perform the action */

if (IsMasked)
{
if (RegisterBit & GpeRegisterInfo->MaskForRun)
{
return_ACPI_STATUS (AE_BAD_PARAMETER);
}

(void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
ACPI_SET_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit);
}
else
{
if (!(RegisterBit & GpeRegisterInfo->MaskForRun))
{
return_ACPI_STATUS (AE_BAD_PARAMETER);
}

ACPI_CLEAR_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit);
if (GpeEventInfo->RuntimeCount &&
!GpeEventInfo->DisableForDispatch)
{
(void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE);
}
}

return_ACPI_STATUS (AE_OK);
}


/*******************************************************************************
*
* FUNCTION: AcpiEvAddGpeReference
Expand Down Expand Up @@ -787,6 +851,7 @@ AcpiEvFinishGpe (
* in the EventInfo.
*/
(void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE);
GpeEventInfo->DisableForDispatch = FALSE;
return (AE_OK);
}

Expand Down Expand Up @@ -856,6 +921,8 @@ AcpiEvGpeDispatch (
}
}

GpeEventInfo->DisableForDispatch = TRUE;

/*
* Dispatch the GPE to either an installed handler or the control
* method associated with this GPE (_Lxx or _Exx). If a handler
Expand Down
52 changes: 52 additions & 0 deletions source/components/events/evxfgpe.c
Expand Up @@ -343,11 +343,13 @@ AcpiSetGpe (
case ACPI_GPE_ENABLE:

Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE);
GpeEventInfo->DisableForDispatch = FALSE;
break;

case ACPI_GPE_DISABLE:

Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE);
GpeEventInfo->DisableForDispatch = TRUE;
break;

default:
Expand All @@ -364,6 +366,56 @@ AcpiSetGpe (
ACPI_EXPORT_SYMBOL (AcpiSetGpe)


/*******************************************************************************
*
* FUNCTION: AcpiMaskGpe
*
* PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1
* GpeNumber - GPE level within the GPE block
* IsMasked - Whether the GPE is masked or not
*
* RETURN: Status
*
* DESCRIPTION: Unconditionally mask/unmask the an individual GPE, ex., to
* prevent a GPE flooding.
*
******************************************************************************/

ACPI_STATUS
AcpiMaskGpe (
ACPI_HANDLE GpeDevice,
UINT32 GpeNumber,
BOOLEAN IsMasked)
{
ACPI_GPE_EVENT_INFO *GpeEventInfo;
ACPI_STATUS Status;
ACPI_CPU_FLAGS Flags;


ACPI_FUNCTION_TRACE (AcpiMaskGpe);


Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);

/* Ensure that we have a valid GPE number */

GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
if (!GpeEventInfo)
{
Status = AE_BAD_PARAMETER;
goto UnlockAndExit;
}

Status = AcpiEvMaskGpe (GpeEventInfo, IsMasked);

UnlockAndExit:
AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
return_ACPI_STATUS (Status);
}

ACPI_EXPORT_SYMBOL (AcpiMaskGpe)


/*******************************************************************************
*
* FUNCTION: AcpiMarkGpeForWake
Expand Down
22 changes: 17 additions & 5 deletions source/components/hardware/hwgpe.c
Expand Up @@ -180,7 +180,7 @@ AcpiHwLowSetGpe (
UINT32 Action)
{
ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;
ACPI_STATUS Status;
ACPI_STATUS Status = AE_OK;
UINT32 EnableMask;
UINT32 RegisterBit;

Expand Down Expand Up @@ -236,9 +236,12 @@ AcpiHwLowSetGpe (
return (AE_BAD_PARAMETER);
}

/* Write the updated enable mask */
if (!(RegisterBit & GpeRegisterInfo->MaskForRun))
{
/* Write the updated enable mask */

Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress);
}
return (Status);
}

Expand Down Expand Up @@ -341,6 +344,13 @@ AcpiHwGetGpeStatus (
LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED;
}

/* GPE currently masked? (masked for runtime?) */

if (RegisterBit & GpeRegisterInfo->MaskForRun)
{
LocalEventStatus |= ACPI_EVENT_FLAG_MASKED;
}

/* GPE enabled for wake? */

if (RegisterBit & GpeRegisterInfo->EnableForWake)
Expand Down Expand Up @@ -512,6 +522,7 @@ AcpiHwEnableRuntimeGpeBlock (
UINT32 i;
ACPI_STATUS Status;
ACPI_GPE_REGISTER_INFO *GpeRegisterInfo;
UINT32 EnableMask;


/* NOTE: assumes that all GPEs are currently disabled */
Expand All @@ -528,8 +539,9 @@ AcpiHwEnableRuntimeGpeBlock (

/* Enable all "runtime" GPEs in this register */

Status = AcpiHwGpeEnableWrite (GpeRegisterInfo->EnableForRun,
GpeRegisterInfo);
EnableMask = GpeRegisterInfo->EnableForRun &
~GpeRegisterInfo->MaskForRun;
Status = AcpiHwGpeEnableWrite (EnableMask, GpeRegisterInfo);
if (ACPI_FAILURE (Status))
{
return (Status);
Expand Down
5 changes: 5 additions & 0 deletions source/include/acevents.h
Expand Up @@ -187,6 +187,11 @@ ACPI_STATUS
AcpiEvEnableGpe (
ACPI_GPE_EVENT_INFO *GpeEventInfo);

ACPI_STATUS
AcpiEvMaskGpe (
ACPI_GPE_EVENT_INFO *GpeEventInfo,
BOOLEAN IsMasked);

ACPI_STATUS
AcpiEvAddGpeReference (
ACPI_GPE_EVENT_INFO *GpeEventInfo);
Expand Down
12 changes: 7 additions & 5 deletions source/include/aclocal.h
Expand Up @@ -622,11 +622,12 @@ typedef union acpi_gpe_dispatch_info
*/
typedef struct acpi_gpe_event_info
{
union acpi_gpe_dispatch_info Dispatch; /* Either Method, Handler, or NotifyList */
struct acpi_gpe_register_info *RegisterInfo; /* Backpointer to register info */
UINT8 Flags; /* Misc info about this GPE */
UINT8 GpeNumber; /* This GPE */
UINT8 RuntimeCount; /* References to a run GPE */
union acpi_gpe_dispatch_info Dispatch; /* Either Method, Handler, or NotifyList */
struct acpi_gpe_register_info *RegisterInfo; /* Backpointer to register info */
UINT8 Flags; /* Misc info about this GPE */
UINT8 GpeNumber; /* This GPE */
UINT8 RuntimeCount; /* References to a run GPE */
BOOLEAN DisableForDispatch; /* Masked during dispatching */

} ACPI_GPE_EVENT_INFO;

Expand All @@ -639,6 +640,7 @@ typedef struct acpi_gpe_register_info
UINT16 BaseGpeNumber; /* Base GPE number for this register */
UINT8 EnableForWake; /* GPEs to keep enabled when sleeping */
UINT8 EnableForRun; /* GPEs to keep enabled when running */
UINT8 MaskForRun; /* GPEs to keep masked when running */
UINT8 EnableMask; /* Current mask of enabled GPEs */

} ACPI_GPE_REGISTER_INFO;
Expand Down
7 changes: 7 additions & 0 deletions source/include/acpixf.h
Expand Up @@ -979,6 +979,13 @@ AcpiFinishGpe (
ACPI_HANDLE GpeDevice,
UINT32 GpeNumber))

ACPI_HW_DEPENDENT_RETURN_STATUS (
ACPI_STATUS
AcpiMaskGpe (
ACPI_HANDLE GpeDevice,
UINT32 GpeNumber,
BOOLEAN IsMasked))

ACPI_HW_DEPENDENT_RETURN_STATUS (
ACPI_STATUS
AcpiMarkGpeForWake (
Expand Down
39 changes: 21 additions & 18 deletions source/include/actypes.h
Expand Up @@ -817,16 +817,17 @@ typedef UINT32 ACPI_EVENT_TYPE;
* The encoding of ACPI_EVENT_STATUS is illustrated below.
* Note that a set bit (1) indicates the property is TRUE
* (e.g. if bit 0 is set then the event is enabled).
* +-------------+-+-+-+-+-+
* | Bits 31:5 |4|3|2|1|0|
* +-------------+-+-+-+-+-+
* | | | | | |
* | | | | | +- Enabled?
* | | | | +--- Enabled for wake?
* | | | +----- Status bit set?
* | | +------- Enable bit set?
* | +--------- Has a handler?
* +--------------- <Reserved>
* +-------------+-+-+-+-+-+-+
* | Bits 31:6 |5|4|3|2|1|0|
* +-------------+-+-+-+-+-+-+
* | | | | | | |
* | | | | | | +- Enabled?
* | | | | | +--- Enabled for wake?
* | | | | +----- Status bit set?
* | | | +------- Enable bit set?
* | | +--------- Has a handler?
* | +----------- Masked?
* +----------------- <Reserved>
*/
typedef UINT32 ACPI_EVENT_STATUS;

Expand All @@ -836,6 +837,7 @@ typedef UINT32 ACPI_EVENT_STATUS;
#define ACPI_EVENT_FLAG_STATUS_SET (ACPI_EVENT_STATUS) 0x04
#define ACPI_EVENT_FLAG_ENABLE_SET (ACPI_EVENT_STATUS) 0x08
#define ACPI_EVENT_FLAG_HAS_HANDLER (ACPI_EVENT_STATUS) 0x10
#define ACPI_EVENT_FLAG_MASKED (ACPI_EVENT_STATUS) 0x20
#define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET

/* Actions for AcpiSetGpe, AcpiGpeWakeup, AcpiHwLowSetGpe */
Expand All @@ -846,14 +848,15 @@ typedef UINT32 ACPI_EVENT_STATUS;

/*
* GPE info flags - Per GPE
* +-------+-+-+---+
* | 7:5 |4|3|2:0|
* +-------+-+-+---+
* | | | |
* | | | +-- Type of dispatch:to method, handler, notify, or none
* | | +----- Interrupt type: edge or level triggered
* | +------- Is a Wake GPE
* +------------ <Reserved>
* +---+-+-+-+---+
* |7:6|5|4|3|2:0|
* +---+-+-+-+---+
* | | | | |
* | | | | +-- Type of dispatch:to method, handler, notify, or none
* | | | +----- Interrupt type: edge or level triggered
* | | +------- Is a Wake GPE
* | +--------- Is GPE masked by the software GPE masking machanism
* +------------ <Reserved>
*/
#define ACPI_GPE_DISPATCH_NONE (UINT8) 0x00
#define ACPI_GPE_DISPATCH_METHOD (UINT8) 0x01
Expand Down

0 comments on commit 23a417c

Please sign in to comment.