mbox series

[0/2] Fix 2 5.19 power-off regressions caused by sys-off-handler work

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

Message

Hans de Goede July 8, 2022, 1:14 p.m. UTC
Hi All,

I noticed that my Lenovo Yoga Tablet 2 1050L was hanging on power-off again
with 5.19, even though I had implemented a workaround for this in 5.17 .

I quickly realized that this was caused by the recent sys-off-handler work
and fixed this by switching the workaround over to register_sys_off_handler
with a priority of SYS_OFF_PRIO_FIRMWARE + 1, so that the workaround runs
before acpi_power_off() get a chance to run.

This made me realize that the efi_power_off handler which sometimes is
used in preference of acpi_power_off had the same problem, so the second
patch in this series fixes that.

I plan to include patch 1/2 in a fixes pull-req to Linus soon. Ard,
if I can get your Ack for 2/2 then I can include this in the pull-req
if you want; or you can send this to Linus yourself.

Regards,

Hans


Hans de Goede (2):
  platform/x86: x86-android-tablets: Fix Lenovo Yoga Tablet 2 830/1050
    poweroff again
  efi: Fix efi_power_off() not being run before acpi_power_off() when
    necessary

 drivers/firmware/efi/reboot.c              | 21 +++++++++++----------
 drivers/platform/x86/x86-android-tablets.c | 17 +++++++++++++----
 2 files changed, 24 insertions(+), 14 deletions(-)

Comments

Dmitry Osipenko July 8, 2022, 1:29 p.m. UTC | #1
On 7/8/22 16:14, Hans de Goede wrote:
> Hi All,
> 
> I noticed that my Lenovo Yoga Tablet 2 1050L was hanging on power-off again
> with 5.19, even though I had implemented a workaround for this in 5.17 .
> 
> I quickly realized that this was caused by the recent sys-off-handler work
> and fixed this by switching the workaround over to register_sys_off_handler
> with a priority of SYS_OFF_PRIO_FIRMWARE + 1, so that the workaround runs
> before acpi_power_off() get a chance to run.
> 
> This made me realize that the efi_power_off handler which sometimes is
> used in preference of acpi_power_off had the same problem, so the second
> patch in this series fixes that.
> 
> I plan to include patch 1/2 in a fixes pull-req to Linus soon. Ard,
> if I can get your Ack for 2/2 then I can include this in the pull-req
> if you want; or you can send this to Linus yourself.
> 
> Regards,
> 
> Hans
> 
> 
> Hans de Goede (2):
>   platform/x86: x86-android-tablets: Fix Lenovo Yoga Tablet 2 830/1050
>     poweroff again
>   efi: Fix efi_power_off() not being run before acpi_power_off() when
>     necessary
> 
>  drivers/firmware/efi/reboot.c              | 21 +++++++++++----------
>  drivers/platform/x86/x86-android-tablets.c | 17 +++++++++++++----
>  2 files changed, 24 insertions(+), 14 deletions(-)
> 

Thank you for the fixes. It's great that the RC is getting more testing
since I couldn't test everything and we don't have CI for the power-off
testing.
Ard Biesheuvel July 8, 2022, 4:37 p.m. UTC | #2
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
>
Hans de Goede July 10, 2022, 3:24 p.m. UTC | #3
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
>>
>
Hans de Goede July 10, 2022, 3:27 p.m. UTC | #4
Hi,

On 7/8/22 15:14, Hans de Goede wrote:
> Hi All,
> 
> I noticed that my Lenovo Yoga Tablet 2 1050L was hanging on power-off again
> with 5.19, even though I had implemented a workaround for this in 5.17 .
> 
> I quickly realized that this was caused by the recent sys-off-handler work
> and fixed this by switching the workaround over to register_sys_off_handler
> with a priority of SYS_OFF_PRIO_FIRMWARE + 1, so that the workaround runs
> before acpi_power_off() get a chance to run.
> 
> This made me realize that the efi_power_off handler which sometimes is
> used in preference of acpi_power_off had the same problem, so the second
> patch in this series fixes that.
> 
> I plan to include patch 1/2 in a fixes pull-req to Linus soon. Ard,
> if I can get your Ack for 2/2 then I can include this in the pull-req
> if you want; or you can send this to Linus yourself.

I've added these to my review-hans (soon to be for-next) branch now
and I'll include them in my upcoming 5.19 fixes pull-req.

Regards,

Hans

> 
> Regards,
> 
> Hans
> 
> 
> Hans de Goede (2):
>   platform/x86: x86-android-tablets: Fix Lenovo Yoga Tablet 2 830/1050
>     poweroff again
>   efi: Fix efi_power_off() not being run before acpi_power_off() when
>     necessary
> 
>  drivers/firmware/efi/reboot.c              | 21 +++++++++++----------
>  drivers/platform/x86/x86-android-tablets.c | 17 +++++++++++++----
>  2 files changed, 24 insertions(+), 14 deletions(-)
>