]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ACPICA: Avoid evaluating methods too early during system resume
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 29 Sep 2021 16:31:25 +0000 (18:31 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 26 Nov 2021 10:36:05 +0000 (11:36 +0100)
[ Upstream commit d3c4b6f64ad356c0d9ddbcf73fa471e6a841cc5c ]

ACPICA commit 0762982923f95eb652cf7ded27356b247c9774de

During wakeup from system-wide sleep states, acpi_get_sleep_type_data()
is called and it tries to get memory from the slab allocator in order
to evaluate a control method, but if KFENCE is enabled in the 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 acpi_get_sleep_type_data()
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>
Tested-by: Reik Keutterling <spielkind@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwxfsleep.c

index 1e6204518496cffb6f02953d1ee1b3a12561f22a..38712fa4dd9d2e252d87b96068d2db3b1f489bb9 100644 (file)
@@ -224,6 +224,8 @@ extern struct acpi_bit_register_info
     acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
 ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a);
 ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a_s0);
+ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b_s0);
 
 /*****************************************************************************
  *
index e0ad3f11142e47b7b919c0092f48a4dfa60b9796..9516966124ae3f1380eff5734c1364e68a68a176 100644 (file)
@@ -147,17 +147,13 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 
 acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
 {
-       acpi_status status;
        u8 sleep_type_value;
 
        ACPI_FUNCTION_TRACE(hw_extended_wake_prep);
 
-       status = acpi_get_sleep_type_data(ACPI_STATE_S0,
-                                         &acpi_gbl_sleep_type_a,
-                                         &acpi_gbl_sleep_type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
                sleep_type_value =
-                   ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+                   ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) &
                     ACPI_X_SLEEP_TYPE_MASK);
 
                (void)acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
index d8b8fc2ff5633e7406c256fc6fff3e0ee6b16f2a..f4282370947c8f1e7666df429e534be4b60c6717 100644 (file)
@@ -179,7 +179,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
 
 acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 {
-       acpi_status status;
+       acpi_status status = AE_OK;
        struct acpi_bit_register_info *sleep_type_reg_info;
        struct acpi_bit_register_info *sleep_enable_reg_info;
        u32 pm1a_control;
@@ -192,10 +192,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
         * This is unclear from the ACPI Spec, but it is required
         * by some machines.
         */
-       status = acpi_get_sleep_type_data(ACPI_STATE_S0,
-                                         &acpi_gbl_sleep_type_a,
-                                         &acpi_gbl_sleep_type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) {
                sleep_type_reg_info =
                    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
                sleep_enable_reg_info =
@@ -216,9 +213,9 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 
                        /* Insert the SLP_TYP bits */
 
-                       pm1a_control |= (acpi_gbl_sleep_type_a <<
+                       pm1a_control |= (acpi_gbl_sleep_type_a_s0 <<
                                         sleep_type_reg_info->bit_position);
-                       pm1b_control |= (acpi_gbl_sleep_type_b <<
+                       pm1b_control |= (acpi_gbl_sleep_type_b_s0 <<
                                         sleep_type_reg_info->bit_position);
 
                        /* Write the control registers and ignore any errors */
index 3f22f7dd4556de3820210f7f0800b0950dac112c..dc1e44ccaae20de0e1a0eadb7a6454c9ff3d2d9a 100644 (file)
@@ -288,6 +288,13 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
                return_ACPI_STATUS(status);
        }
 
+       status = acpi_get_sleep_type_data(ACPI_STATE_S0,
+                                         &acpi_gbl_sleep_type_a_s0,
+                                         &acpi_gbl_sleep_type_b_s0);
+       if (ACPI_FAILURE(status)) {
+               acpi_gbl_sleep_type_a_s0 = ACPI_SLEEP_TYPE_INVALID;
+       }
+
        /* Execute the _PTS method (Prepare To Sleep) */
 
        arg_list.count = 1;