diff mbox series

[2/2] efi: Fix efi_power_off() not being run before acpi_power_off() when necessary

Message ID 20220708131412.81078-3-hdegoede@redhat.com
State Accepted
Commit d40908f2621ea7abc6132ec8c5688a2960eeee3c
Headers show
Series Fix 2 5.19 power-off regressions caused by sys-off-handler work | expand

Commit Message

Hans de Goede July 8, 2022, 1:14 p.m. UTC
Commit 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API")
switched the ACPI sleep code from directly setting the old global
pm_power_off handler to using the new register_sys_off_handler()
mechanism with a priority of SYS_OFF_PRIO_FIRMWARE.

This is a problem when the old global pm_power_off handler would later
be overwritten, such as done by the late_initcall(efi_shutdown_init):

	if (efi_poweroff_required())
		pm_power_off = efi_power_off;

The old global pm_power_off handler gets run with a priority of
SYS_OFF_PRIO_DEFAULT which is lower then SYS_OFF_PRIO_FIRMWARE, causing
acpi_power_off() to run first, changing the behavior from before
the ACPI sleep code switched to the new register_sys_off_handler().

Switch the registering of efi_power_off over to register_sys_off_handler()
with a priority of SYS_OFF_PRIO_FIRMWARE + 1 so that it will run before
acpi_power_off() as before.

Note since the new sys-off-handler code will try all handlers in
priority order, there is no more need for the EFI code to store and
call the original pm_power_off handler.

Fixes: 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API")
Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/firmware/efi/reboot.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c
index 73089a24f04b..ceae84c19d22 100644
--- a/drivers/firmware/efi/reboot.c
+++ b/drivers/firmware/efi/reboot.c
@@ -6,7 +6,7 @@ 
 #include <linux/efi.h>
 #include <linux/reboot.h>
 
-static void (*orig_pm_power_off)(void);
+static struct sys_off_handler *efi_sys_off_handler;
 
 int efi_reboot_quirk_mode = -1;
 
@@ -51,15 +51,11 @@  bool __weak efi_poweroff_required(void)
 	return false;
 }
 
-static void efi_power_off(void)
+static int efi_power_off(struct sys_off_data *data)
 {
 	efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-	/*
-	 * The above call should not return, if it does fall back to
-	 * the original power off method (typically ACPI poweroff).
-	 */
-	if (orig_pm_power_off)
-		orig_pm_power_off();
+
+	return NOTIFY_DONE;
 }
 
 static int __init efi_shutdown_init(void)
@@ -68,8 +64,13 @@  static int __init efi_shutdown_init(void)
 		return -ENODEV;
 
 	if (efi_poweroff_required()) {
-		orig_pm_power_off = pm_power_off;
-		pm_power_off = efi_power_off;
+		/* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+		efi_sys_off_handler =
+			register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+						 SYS_OFF_PRIO_FIRMWARE + 1,
+						 efi_power_off, NULL);
+		if (IS_ERR(efi_sys_off_handler))
+			return PTR_ERR(efi_sys_off_handler);
 	}
 
 	return 0;