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 in special cases where the old global pm_power_off handler later gets overwritten, such as the Lenovo Tab2 poweroff bugfix in x86-android-tablets. 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 the troublesome ACPI poweroff (which freezes the system) to run first. Switch the registering of lenovo_yoga_tab2_830_1050_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() to fix this.
Unified · Split
| @@ -27,8 +27,8 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <linux/pinctrl/machine.h> |
| 28 | 28 | #include <linux/platform_data/lp855x.h> |
| 29 | 29 | #include <linux/platform_device.h> |
| 30 | −#include <linux/pm.h> | |
| 31 | 30 | #include <linux/power/bq24190_charger.h> |
| 31 | +#include <linux/reboot.h> | |
| 32 | 32 | #include <linux/rmi.h> |
| 33 | 33 | #include <linux/serdev.h> |
| 34 | 34 | #include <linux/spi/spi.h> |
| @@ -889,6 +889,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map = · 854 unmodified lines | ||
| 889 | 889 | "INT33FC:02", "pmu_clk2_grp", "pmu_clk"); |
| 890 | 890 | |
| 891 | 891 | static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl; |
| 892 | +static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler; | |
| 892 | 893 | |
| 893 | 894 | static int __init lenovo_yoga_tab2_830_1050_init_codec(void) |
| 894 | 895 | { |
| @@ -933,9 +934,11 @@ err_put_device: · 38 unmodified lines | ||
| 933 | 934 | * followed by a normal 3 second press to recover. Avoid this by doing an EFI |
| 934 | 935 | * poweroff instead. |
| 935 | 936 | */ |
| 936 | −static void lenovo_yoga_tab2_830_1050_power_off(void) | |
| 937 | +static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data) | |
| 937 | 938 | { |
| 938 | 939 | efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); |
| 940 | + | |
| 941 | + return NOTIFY_DONE; | |
| 939 | 942 | } |
| 940 | 943 | |
| 941 | 944 | static int __init lenovo_yoga_tab2_830_1050_init(void) |
| @@ -950,13 +953,19 @@ static int __init lenovo_yoga_tab2_830_1050_init(void) · 8 unmodified lines | ||
| 950 | 953 | if (ret) |
| 951 | 954 | return ret; |
| 952 | 955 | |
| 953 | − pm_power_off = lenovo_yoga_tab2_830_1050_power_off; | |
| 956 | + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ | |
| 957 | + lenovo_yoga_tab2_830_1050_sys_off_handler = | |
| 958 | + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1, | |
| 959 | + lenovo_yoga_tab2_830_1050_power_off, NULL); | |
| 960 | + if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler)) | |
| 961 | + return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler); | |
| 962 | + | |
| 954 | 963 | return 0; |
| 955 | 964 | } |
| 956 | 965 | |
| 957 | 966 | static void lenovo_yoga_tab2_830_1050_exit(void) |
| 958 | 967 | { |
| 959 | − pm_power_off = NULL; /* Just turn poweroff into halt on module unload */ | |
| 968 | + unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler); | |
| 960 | 969 | |
| 961 | 970 | if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { |
| 962 | 971 | pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); |