summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2021-09-29 16:55:33 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2021-09-29 16:55:33 +0200
commit0762982923f95eb652cf7ded27356b247c9774de (patch)
tree6f9f2674ec431117348870ac879eb8a8eca9a1d3 /source
parentb9c69f81a05c45611c91ea9cbce8756078d76233 (diff)
downloadacpica-0762982923f95eb652cf7ded27356b247c9774de.tar.gz
Hardware: Avoid evaluating methods too early during system resume
During wakeup from system-wide sleep states, AcpiGetSleepTypeData() is called and it tries to get memory from the OS in order to evaluate a control method, but if KFENCE is enabled in the Linux kernel, the memory allocation attempt causes an IRQ work to be queued and a self-IPI to be sent to the CPU running the code which requires the memory controller to be ready, so if that happens too early in the wakeup path, it doesn't work. Prevent that from taking place by calling AcpiGetSleepTypeData() for S0 upfront, when preparing to enter a given sleep state, and saving the data obtained by it for later use during system wakeup. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214271 Reported-by: Reik Keutterling <spielkind@gmail.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'source')
-rw-r--r--source/components/hardware/hwesleep.c7
-rw-r--r--source/components/hardware/hwsleep.c10
-rw-r--r--source/components/hardware/hwxfsleep.c6
-rw-r--r--source/include/acglobal.h2
4 files changed, 14 insertions, 11 deletions
diff --git a/source/components/hardware/hwesleep.c b/source/components/hardware/hwesleep.c
index fcc28581e..e8db4d26d 100644
--- a/source/components/hardware/hwesleep.c
+++ b/source/components/hardware/hwesleep.c
@@ -312,18 +312,15 @@ ACPI_STATUS
AcpiHwExtendedWakePrep (
UINT8 SleepState)
{
- ACPI_STATUS Status;
UINT8 SleepTypeValue;
ACPI_FUNCTION_TRACE (HwExtendedWakePrep);
- Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
- &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
- if (ACPI_SUCCESS (Status))
+ if (AcpiGbl_SleepTypeAS0 != ACPI_SLEEP_TYPE_INVALID)
{
- SleepTypeValue = ((AcpiGbl_SleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) &
+ SleepTypeValue = ((AcpiGbl_SleepTypeAS0 << ACPI_X_SLEEP_TYPE_POSITION) &
ACPI_X_SLEEP_TYPE_MASK);
(void) AcpiWrite ((UINT64) (SleepTypeValue | ACPI_X_SLEEP_ENABLE),
diff --git a/source/components/hardware/hwsleep.c b/source/components/hardware/hwsleep.c
index d85d04785..2b857d970 100644
--- a/source/components/hardware/hwsleep.c
+++ b/source/components/hardware/hwsleep.c
@@ -339,7 +339,7 @@ ACPI_STATUS
AcpiHwLegacyWakePrep (
UINT8 SleepState)
{
- ACPI_STATUS Status;
+ ACPI_STATUS Status = AE_OK;
ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
UINT32 Pm1aControl;
@@ -353,9 +353,7 @@ AcpiHwLegacyWakePrep (
* This is unclear from the ACPI Spec, but it is required
* by some machines.
*/
- Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
- &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
- if (ACPI_SUCCESS (Status))
+ if (AcpiGbl_SleepTypeAS0 != ACPI_SLEEP_TYPE_INVALID)
{
SleepTypeRegInfo =
AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
@@ -376,9 +374,9 @@ AcpiHwLegacyWakePrep (
/* Insert the SLP_TYP bits */
- Pm1aControl |= (AcpiGbl_SleepTypeA <<
+ Pm1aControl |= (AcpiGbl_SleepTypeAS0 <<
SleepTypeRegInfo->BitPosition);
- Pm1bControl |= (AcpiGbl_SleepTypeB <<
+ Pm1aControl |= (AcpiGbl_SleepTypeBS0 <<
SleepTypeRegInfo->BitPosition);
/* Write the control registers and ignore any errors */
diff --git a/source/components/hardware/hwxfsleep.c b/source/components/hardware/hwxfsleep.c
index 26b48ccbe..f1a1344c7 100644
--- a/source/components/hardware/hwxfsleep.c
+++ b/source/components/hardware/hwxfsleep.c
@@ -471,6 +471,12 @@ AcpiEnterSleepStatePrep (
return_ACPI_STATUS (Status);
}
+ Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
+ &AcpiGbl_SleepTypeAS0, &AcpiGbl_SleepTypeBS0);
+ if (ACPI_FAILURE (Status)) {
+ AcpiGbl_SleepTypeAS0 = ACPI_SLEEP_TYPE_INVALID;
+ }
+
/* Execute the _PTS method (Prepare To Sleep) */
ArgList.Count = 1;
diff --git a/source/include/acglobal.h b/source/include/acglobal.h
index c2107df0e..354268655 100644
--- a/source/include/acglobal.h
+++ b/source/include/acglobal.h
@@ -365,6 +365,8 @@ ACPI_INIT_GLOBAL (ACPI_COMMENT_NODE, *AcpiGbl_LastListHead, NULL);
extern ACPI_BIT_REGISTER_INFO AcpiGbl_BitRegisterInfo[ACPI_NUM_BITREG];
ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeA);
ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeB);
+ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeAS0);
+ACPI_GLOBAL (UINT8, AcpiGbl_SleepTypeBS0);
/*****************************************************************************