Message ID | 20220708131412.81078-3-hdegoede@redhat.com (mailing list archive) |
---|---|
State | Handled Elsewhere, archived |
Headers | show |
Series | Fix 2 5.19 power-off regressions caused by sys-off-handler work | expand |
On Fri, 8 Jul 2022 at 15:14, Hans de Goede <hdegoede@redhat.com> wrote: > > 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> Acked-by: Ard Biesheuvel <ardb@kernel.org> Note that, as far as I know, this should only affect x86 even though this is generic EFI code, and arm64 also supports ACPI boot, but it doesn't use ACPI for poweroff/reboot etc > --- > drivers/firmware/efi/reboot.c | 21 +++++++++++---------- > 1 file changed, 11 insertions(+), 10 deletions(-) > > 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; > -- > 2.36.0 >
Hi, On 7/8/22 18:37, Ard Biesheuvel wrote: > On Fri, 8 Jul 2022 at 15:14, Hans de Goede <hdegoede@redhat.com> wrote: >> >> 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> > > Acked-by: Ard Biesheuvel <ardb@kernel.org> Thanks, I'll include this in my next fixes pull-req for 5.19. Regards, Hans > > Note that, as far as I know, this should only affect x86 even though > this is generic EFI code, and arm64 also supports ACPI boot, but it > doesn't use ACPI for poweroff/reboot etc > >> --- >> drivers/firmware/efi/reboot.c | 21 +++++++++++---------- >> 1 file changed, 11 insertions(+), 10 deletions(-) >> >> 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; >> -- >> 2.36.0 >> >
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;
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(-)