From 23a417ca406a527e7ae1710893e59a8b6db30e14 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 16 Jun 2014 21:34:23 +0800 Subject: [PATCH] Events: Introduce AcpiMaskGpe() to implement GPE masking mechanism 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 --- source/components/events/evgpe.c | 67 ++++++++++++++++++++++++++++++ source/components/events/evxfgpe.c | 52 +++++++++++++++++++++++ source/components/hardware/hwgpe.c | 22 +++++++--- source/include/acevents.h | 5 +++ source/include/aclocal.h | 12 +++--- source/include/acpixf.h | 7 ++++ source/include/actypes.h | 39 +++++++++-------- 7 files changed, 176 insertions(+), 28 deletions(-) diff --git a/source/components/events/evgpe.c b/source/components/events/evgpe.c index 9adedb8794..c37b9978e6 100644 --- a/source/components/events/evgpe.c +++ b/source/components/events/evgpe.c @@ -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 @@ -787,6 +851,7 @@ AcpiEvFinishGpe ( * in the EventInfo. */ (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); + GpeEventInfo->DisableForDispatch = FALSE; return (AE_OK); } @@ -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 diff --git a/source/components/events/evxfgpe.c b/source/components/events/evxfgpe.c index 2d5afd6fd8..0c86647c52 100644 --- a/source/components/events/evxfgpe.c +++ b/source/components/events/evxfgpe.c @@ -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: @@ -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 diff --git a/source/components/hardware/hwgpe.c b/source/components/hardware/hwgpe.c index db250b9296..cceabde3c2 100644 --- a/source/components/hardware/hwgpe.c +++ b/source/components/hardware/hwgpe.c @@ -180,7 +180,7 @@ AcpiHwLowSetGpe ( UINT32 Action) { ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; - ACPI_STATUS Status; + ACPI_STATUS Status = AE_OK; UINT32 EnableMask; UINT32 RegisterBit; @@ -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); } @@ -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) @@ -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 */ @@ -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); diff --git a/source/include/acevents.h b/source/include/acevents.h index 912c9403d5..8a40d28109 100644 --- a/source/include/acevents.h +++ b/source/include/acevents.h @@ -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); diff --git a/source/include/aclocal.h b/source/include/aclocal.h index 660dccd33d..c5dc19abc2 100644 --- a/source/include/aclocal.h +++ b/source/include/aclocal.h @@ -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; @@ -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; diff --git a/source/include/acpixf.h b/source/include/acpixf.h index f2278dcfd6..6b5db707f2 100644 --- a/source/include/acpixf.h +++ b/source/include/acpixf.h @@ -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 ( diff --git a/source/include/actypes.h b/source/include/actypes.h index 039d71a5ab..690c1d207e 100644 --- a/source/include/actypes.h +++ b/source/include/actypes.h @@ -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? - * +--------------- + * +-------------+-+-+-+-+-+-+ + * | Bits 31:6 |5|4|3|2|1|0| + * +-------------+-+-+-+-+-+-+ + * | | | | | | | + * | | | | | | +- Enabled? + * | | | | | +--- Enabled for wake? + * | | | | +----- Status bit set? + * | | | +------- Enable bit set? + * | | +--------- Has a handler? + * | +----------- Masked? + * +----------------- */ typedef UINT32 ACPI_EVENT_STATUS; @@ -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 */ @@ -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 - * +------------ + * +---+-+-+-+---+ + * |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 + * +------------ */ #define ACPI_GPE_DISPATCH_NONE (UINT8) 0x00 #define ACPI_GPE_DISPATCH_METHOD (UINT8) 0x01