Skip to content

Commit d40908f

Browse files
committed
efi: Fix efi_power_off() not being run before acpi_power_off() when necessary
Commit 98f30d0 ("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: 98f30d0 ("ACPI: power: Switch to sys-off handler API") Cc: Dmitry Osipenko <dmitry.osipenko@collabora.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Ard Biesheuvel <ardb@kernel.org> Link: https://lore.kernel.org/r/20220708131412.81078-3-hdegoede@redhat.com
1 parent 4ce8f4c commit d40908f

1 file changed

Lines changed: 11 additions & 10 deletions

File tree

drivers/firmware/efi/reboot.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <linux/efi.h>
77
#include <linux/reboot.h>
88

9-
static void (*orig_pm_power_off)(void);
9+
static struct sys_off_handler *efi_sys_off_handler;
1010

1111
int efi_reboot_quirk_mode = -1;
1212

@@ -51,15 +51,11 @@ bool __weak efi_poweroff_required(void)
5151
return false;
5252
}
5353

54-
static void efi_power_off(void)
54+
static int efi_power_off(struct sys_off_data *data)
5555
{
5656
efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
57-
/*
58-
* The above call should not return, if it does fall back to
59-
* the original power off method (typically ACPI poweroff).
60-
*/
61-
if (orig_pm_power_off)
62-
orig_pm_power_off();
57+
58+
return NOTIFY_DONE;
6359
}
6460

6561
static int __init efi_shutdown_init(void)
@@ -68,8 +64,13 @@ static int __init efi_shutdown_init(void)
6864
return -ENODEV;
6965

7066
if (efi_poweroff_required()) {
71-
orig_pm_power_off = pm_power_off;
72-
pm_power_off = efi_power_off;
67+
/* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
68+
efi_sys_off_handler =
69+
register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
70+
SYS_OFF_PRIO_FIRMWARE + 1,
71+
efi_power_off, NULL);
72+
if (IS_ERR(efi_sys_off_handler))
73+
return PTR_ERR(efi_sys_off_handler);
7374
}
7475

7576
return 0;

0 commit comments

Comments
 (0)