| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * sleep.c - ACPI sleep support. |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com> |
|---|
| 6 | 7 | * Copyright (c) 2000-2003 Patrick Mochel |
|---|
| 7 | 8 | * Copyright (c) 2003 Open Source Development Lab |
|---|
| 8 | | - * |
|---|
| 9 | | - * This file is released under the GPLv2. |
|---|
| 10 | | - * |
|---|
| 11 | 9 | */ |
|---|
| 12 | 10 | |
|---|
| 13 | 11 | #include <linux/delay.h> |
|---|
| .. | .. |
|---|
| 63 | 61 | static int acpi_sleep_prepare(u32 acpi_state) |
|---|
| 64 | 62 | { |
|---|
| 65 | 63 | #ifdef CONFIG_ACPI_SLEEP |
|---|
| 64 | + unsigned long acpi_wakeup_address; |
|---|
| 65 | + |
|---|
| 66 | 66 | /* do we have a wakeup address for S2 and S3? */ |
|---|
| 67 | 67 | if (acpi_state == ACPI_STATE_S3) { |
|---|
| 68 | + acpi_wakeup_address = acpi_get_wakeup_address(); |
|---|
| 68 | 69 | if (!acpi_wakeup_address) |
|---|
| 69 | 70 | return -EFAULT; |
|---|
| 70 | 71 | acpi_set_waking_vector(acpi_wakeup_address); |
|---|
| .. | .. |
|---|
| 79 | 80 | return 0; |
|---|
| 80 | 81 | } |
|---|
| 81 | 82 | |
|---|
| 82 | | -static bool acpi_sleep_state_supported(u8 sleep_state) |
|---|
| 83 | +bool acpi_sleep_state_supported(u8 sleep_state) |
|---|
| 83 | 84 | { |
|---|
| 84 | 85 | acpi_status status; |
|---|
| 85 | 86 | u8 type_a, type_b; |
|---|
| .. | .. |
|---|
| 91 | 92 | } |
|---|
| 92 | 93 | |
|---|
| 93 | 94 | #ifdef CONFIG_ACPI_SLEEP |
|---|
| 95 | +static bool sleep_no_lps0 __read_mostly; |
|---|
| 96 | +module_param(sleep_no_lps0, bool, 0644); |
|---|
| 97 | +MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); |
|---|
| 98 | + |
|---|
| 94 | 99 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; |
|---|
| 95 | 100 | |
|---|
| 96 | 101 | u32 acpi_target_system_state(void) |
|---|
| .. | .. |
|---|
| 160 | 165 | return 0; |
|---|
| 161 | 166 | } |
|---|
| 162 | 167 | |
|---|
| 163 | | -static bool acpi_sleep_no_lps0; |
|---|
| 168 | +static bool acpi_sleep_default_s3; |
|---|
| 164 | 169 | |
|---|
| 165 | | -static int __init init_no_lps0(const struct dmi_system_id *d) |
|---|
| 170 | +static int __init init_default_s3(const struct dmi_system_id *d) |
|---|
| 166 | 171 | { |
|---|
| 167 | | - acpi_sleep_no_lps0 = true; |
|---|
| 172 | + acpi_sleep_default_s3 = true; |
|---|
| 168 | 173 | return 0; |
|---|
| 169 | 174 | } |
|---|
| 170 | 175 | |
|---|
| .. | .. |
|---|
| 359 | 364 | DMI_MATCH(DMI_PRODUCT_NAME, "80E3"), |
|---|
| 360 | 365 | }, |
|---|
| 361 | 366 | }, |
|---|
| 362 | | - /* |
|---|
| 363 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=196907 |
|---|
| 364 | | - * Some Dell XPS13 9360 cannot do suspend-to-idle using the Low Power |
|---|
| 365 | | - * S0 Idle firmware interface. |
|---|
| 366 | | - */ |
|---|
| 367 | 367 | { |
|---|
| 368 | | - .callback = init_no_lps0, |
|---|
| 369 | | - .ident = "Dell XPS13 9360", |
|---|
| 368 | + .callback = init_nvs_save_s3, |
|---|
| 369 | + .ident = "Lenovo G40-45", |
|---|
| 370 | 370 | .matches = { |
|---|
| 371 | | - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
|---|
| 372 | | - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"), |
|---|
| 371 | + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
|---|
| 372 | + DMI_MATCH(DMI_PRODUCT_NAME, "80E1"), |
|---|
| 373 | 373 | }, |
|---|
| 374 | 374 | }, |
|---|
| 375 | 375 | /* |
|---|
| .. | .. |
|---|
| 378 | 378 | * https://bugzilla.kernel.org/show_bug.cgi?id=199057). |
|---|
| 379 | 379 | */ |
|---|
| 380 | 380 | { |
|---|
| 381 | | - .callback = init_no_lps0, |
|---|
| 381 | + .callback = init_default_s3, |
|---|
| 382 | 382 | .ident = "ThinkPad X1 Tablet(2016)", |
|---|
| 383 | 383 | .matches = { |
|---|
| 384 | 384 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
|---|
| 385 | 385 | DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"), |
|---|
| 386 | + }, |
|---|
| 387 | + }, |
|---|
| 388 | + /* |
|---|
| 389 | + * ASUS B1400CEAE hangs on resume from suspend (see |
|---|
| 390 | + * https://bugzilla.kernel.org/show_bug.cgi?id=215742). |
|---|
| 391 | + */ |
|---|
| 392 | + { |
|---|
| 393 | + .callback = init_default_s3, |
|---|
| 394 | + .ident = "ASUS B1400CEAE", |
|---|
| 395 | + .matches = { |
|---|
| 396 | + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
|---|
| 397 | + DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"), |
|---|
| 386 | 398 | }, |
|---|
| 387 | 399 | }, |
|---|
| 388 | 400 | {}, |
|---|
| .. | .. |
|---|
| 454 | 466 | return error; |
|---|
| 455 | 467 | } |
|---|
| 456 | 468 | |
|---|
| 457 | | -static int find_powerf_dev(struct device *dev, void *data) |
|---|
| 458 | | -{ |
|---|
| 459 | | - struct acpi_device *device = to_acpi_device(dev); |
|---|
| 460 | | - const char *hid = acpi_device_hid(device); |
|---|
| 461 | | - |
|---|
| 462 | | - return !strcmp(hid, ACPI_BUTTON_HID_POWERF); |
|---|
| 463 | | -} |
|---|
| 464 | | - |
|---|
| 465 | 469 | /** |
|---|
| 466 | 470 | * acpi_pm_finish - Instruct the platform to leave a sleep state. |
|---|
| 467 | 471 | * |
|---|
| .. | .. |
|---|
| 470 | 474 | */ |
|---|
| 471 | 475 | static void acpi_pm_finish(void) |
|---|
| 472 | 476 | { |
|---|
| 473 | | - struct device *pwr_btn_dev; |
|---|
| 477 | + struct acpi_device *pwr_btn_adev; |
|---|
| 474 | 478 | u32 acpi_state = acpi_target_sleep_state; |
|---|
| 475 | 479 | |
|---|
| 476 | 480 | acpi_ec_unblock_transactions(); |
|---|
| .. | .. |
|---|
| 501 | 505 | return; |
|---|
| 502 | 506 | |
|---|
| 503 | 507 | pwr_btn_event_pending = false; |
|---|
| 504 | | - pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, |
|---|
| 505 | | - find_powerf_dev); |
|---|
| 506 | | - if (pwr_btn_dev) { |
|---|
| 507 | | - pm_wakeup_event(pwr_btn_dev, 0); |
|---|
| 508 | | - put_device(pwr_btn_dev); |
|---|
| 508 | + pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, |
|---|
| 509 | + NULL, -1); |
|---|
| 510 | + if (pwr_btn_adev) { |
|---|
| 511 | + pm_wakeup_event(&pwr_btn_adev->dev, 0); |
|---|
| 512 | + acpi_dev_put(pwr_btn_adev); |
|---|
| 509 | 513 | } |
|---|
| 510 | 514 | } |
|---|
| 511 | 515 | |
|---|
| .. | .. |
|---|
| 534 | 538 | acpi_sleep_tts_switch(acpi_target_sleep_state); |
|---|
| 535 | 539 | } |
|---|
| 536 | 540 | #else /* !CONFIG_ACPI_SLEEP */ |
|---|
| 541 | +#define sleep_no_lps0 (1) |
|---|
| 537 | 542 | #define acpi_target_sleep_state ACPI_STATE_S0 |
|---|
| 538 | | -#define acpi_sleep_no_lps0 (false) |
|---|
| 543 | +#define acpi_sleep_default_s3 (1) |
|---|
| 539 | 544 | static inline void acpi_sleep_dmi_check(void) {} |
|---|
| 540 | 545 | #endif /* CONFIG_ACPI_SLEEP */ |
|---|
| 541 | 546 | |
|---|
| .. | .. |
|---|
| 701 | 706 | .recover = acpi_pm_finish, |
|---|
| 702 | 707 | }; |
|---|
| 703 | 708 | |
|---|
| 704 | | -static bool s2idle_in_progress; |
|---|
| 705 | 709 | static bool s2idle_wakeup; |
|---|
| 706 | 710 | |
|---|
| 707 | 711 | /* |
|---|
| .. | .. |
|---|
| 914 | 918 | if (lps0_device_handle) |
|---|
| 915 | 919 | return 0; |
|---|
| 916 | 920 | |
|---|
| 917 | | - if (acpi_sleep_no_lps0) { |
|---|
| 918 | | - acpi_handle_info(adev->handle, |
|---|
| 919 | | - "Low Power S0 Idle interface disabled\n"); |
|---|
| 920 | | - return 0; |
|---|
| 921 | | - } |
|---|
| 922 | | - |
|---|
| 923 | 921 | if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) |
|---|
| 924 | 922 | return 0; |
|---|
| 925 | 923 | |
|---|
| 926 | 924 | guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid); |
|---|
| 927 | 925 | /* Check if the _DSM is present and as expected. */ |
|---|
| 928 | 926 | out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL); |
|---|
| 929 | | - if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { |
|---|
| 930 | | - char bitmask = *(char *)out_obj->buffer.pointer; |
|---|
| 931 | | - |
|---|
| 932 | | - lps0_dsm_func_mask = bitmask; |
|---|
| 933 | | - lps0_device_handle = adev->handle; |
|---|
| 934 | | - /* |
|---|
| 935 | | - * Use suspend-to-idle by default if the default |
|---|
| 936 | | - * suspend mode was not set from the command line. |
|---|
| 937 | | - */ |
|---|
| 938 | | - if (mem_sleep_default > PM_SUSPEND_MEM) |
|---|
| 939 | | - mem_sleep_current = PM_SUSPEND_TO_IDLE; |
|---|
| 940 | | - |
|---|
| 941 | | - acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", |
|---|
| 942 | | - bitmask); |
|---|
| 943 | | - |
|---|
| 944 | | - acpi_ec_mark_gpe_for_wake(); |
|---|
| 945 | | - } else { |
|---|
| 927 | + if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) { |
|---|
| 946 | 928 | acpi_handle_debug(adev->handle, |
|---|
| 947 | 929 | "_DSM function 0 evaluation failed\n"); |
|---|
| 930 | + return 0; |
|---|
| 948 | 931 | } |
|---|
| 932 | + |
|---|
| 933 | + lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer; |
|---|
| 934 | + |
|---|
| 949 | 935 | ACPI_FREE(out_obj); |
|---|
| 950 | 936 | |
|---|
| 937 | + acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", |
|---|
| 938 | + lps0_dsm_func_mask); |
|---|
| 939 | + |
|---|
| 940 | + lps0_device_handle = adev->handle; |
|---|
| 941 | + |
|---|
| 951 | 942 | lpi_device_get_constraints(); |
|---|
| 943 | + |
|---|
| 944 | + /* |
|---|
| 945 | + * Use suspend-to-idle by default if the default suspend mode was not |
|---|
| 946 | + * set from the command line. |
|---|
| 947 | + */ |
|---|
| 948 | + if (mem_sleep_default > PM_SUSPEND_MEM && !acpi_sleep_default_s3) |
|---|
| 949 | + mem_sleep_current = PM_SUSPEND_TO_IDLE; |
|---|
| 950 | + |
|---|
| 951 | + /* |
|---|
| 952 | + * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the |
|---|
| 953 | + * EC GPE to be enabled while suspended for certain wakeup devices to |
|---|
| 954 | + * work, so mark it as wakeup-capable. |
|---|
| 955 | + */ |
|---|
| 956 | + acpi_ec_mark_gpe_for_wake(); |
|---|
| 952 | 957 | |
|---|
| 953 | 958 | return 0; |
|---|
| 954 | 959 | } |
|---|
| .. | .. |
|---|
| 961 | 966 | static int acpi_s2idle_begin(void) |
|---|
| 962 | 967 | { |
|---|
| 963 | 968 | acpi_scan_lock_acquire(); |
|---|
| 964 | | - s2idle_in_progress = true; |
|---|
| 965 | 969 | return 0; |
|---|
| 966 | 970 | } |
|---|
| 967 | 971 | |
|---|
| 968 | 972 | static int acpi_s2idle_prepare(void) |
|---|
| 969 | 973 | { |
|---|
| 970 | | - if (lps0_device_handle) { |
|---|
| 971 | | - acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); |
|---|
| 972 | | - acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); |
|---|
| 973 | | - |
|---|
| 974 | + if (acpi_sci_irq_valid()) { |
|---|
| 975 | + enable_irq_wake(acpi_sci_irq); |
|---|
| 974 | 976 | acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE); |
|---|
| 975 | 977 | } |
|---|
| 976 | | - |
|---|
| 977 | | - if (acpi_sci_irq_valid()) |
|---|
| 978 | | - enable_irq_wake(acpi_sci_irq); |
|---|
| 979 | 978 | |
|---|
| 980 | 979 | acpi_enable_wakeup_devices(ACPI_STATE_S0); |
|---|
| 981 | 980 | |
|---|
| 982 | 981 | /* Change the configuration of GPEs to avoid spurious wakeup. */ |
|---|
| 983 | 982 | acpi_enable_all_wakeup_gpes(); |
|---|
| 984 | 983 | acpi_os_wait_events_complete(); |
|---|
| 984 | + |
|---|
| 985 | + s2idle_wakeup = true; |
|---|
| 985 | 986 | return 0; |
|---|
| 986 | 987 | } |
|---|
| 987 | 988 | |
|---|
| 988 | | -static void acpi_s2idle_wake(void) |
|---|
| 989 | +static int acpi_s2idle_prepare_late(void) |
|---|
| 989 | 990 | { |
|---|
| 991 | + if (!lps0_device_handle || sleep_no_lps0) |
|---|
| 992 | + return 0; |
|---|
| 990 | 993 | |
|---|
| 991 | 994 | if (pm_debug_messages_on) |
|---|
| 992 | 995 | lpi_check_constraints(); |
|---|
| 993 | 996 | |
|---|
| 994 | | - /* |
|---|
| 995 | | - * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means |
|---|
| 996 | | - * that the SCI has triggered while suspended, so cancel the wakeup in |
|---|
| 997 | | - * case it has not been a wakeup event (the GPEs will be checked later). |
|---|
| 998 | | - */ |
|---|
| 999 | | - if (acpi_sci_irq_valid() && |
|---|
| 1000 | | - !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { |
|---|
| 1001 | | - pm_system_cancel_wakeup(); |
|---|
| 1002 | | - s2idle_wakeup = true; |
|---|
| 1003 | | - /* |
|---|
| 1004 | | - * On some platforms with the LPS0 _DSM device noirq resume |
|---|
| 1005 | | - * takes too much time for EC wakeup events to survive, so look |
|---|
| 1006 | | - * for them now. |
|---|
| 1007 | | - */ |
|---|
| 1008 | | - if (lps0_device_handle) |
|---|
| 1009 | | - acpi_ec_dispatch_gpe(); |
|---|
| 1010 | | - } |
|---|
| 997 | + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); |
|---|
| 998 | + acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); |
|---|
| 999 | + |
|---|
| 1000 | + return 0; |
|---|
| 1011 | 1001 | } |
|---|
| 1012 | 1002 | |
|---|
| 1013 | | -static void acpi_s2idle_sync(void) |
|---|
| 1003 | +static bool acpi_s2idle_wake(void) |
|---|
| 1014 | 1004 | { |
|---|
| 1015 | | - /* |
|---|
| 1016 | | - * Process all pending events in case there are any wakeup ones. |
|---|
| 1017 | | - * |
|---|
| 1018 | | - * The EC driver uses the system workqueue and an additional special |
|---|
| 1019 | | - * one, so those need to be flushed too. |
|---|
| 1020 | | - */ |
|---|
| 1021 | | - acpi_os_wait_events_complete(); /* synchronize SCI IRQ handling */ |
|---|
| 1022 | | - acpi_ec_flush_work(); |
|---|
| 1023 | | - acpi_os_wait_events_complete(); /* synchronize Notify handling */ |
|---|
| 1024 | | - s2idle_wakeup = false; |
|---|
| 1005 | + if (!acpi_sci_irq_valid()) |
|---|
| 1006 | + return pm_wakeup_pending(); |
|---|
| 1007 | + |
|---|
| 1008 | + while (pm_wakeup_pending()) { |
|---|
| 1009 | + /* |
|---|
| 1010 | + * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the |
|---|
| 1011 | + * SCI has not triggered while suspended, so bail out (the |
|---|
| 1012 | + * wakeup is pending anyway and the SCI is not the source of |
|---|
| 1013 | + * it). |
|---|
| 1014 | + */ |
|---|
| 1015 | + if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) { |
|---|
| 1016 | + pm_pr_dbg("Wakeup unrelated to ACPI SCI\n"); |
|---|
| 1017 | + return true; |
|---|
| 1018 | + } |
|---|
| 1019 | + |
|---|
| 1020 | + /* |
|---|
| 1021 | + * If the status bit of any enabled fixed event is set, the |
|---|
| 1022 | + * wakeup is regarded as valid. |
|---|
| 1023 | + */ |
|---|
| 1024 | + if (acpi_any_fixed_event_status_set()) { |
|---|
| 1025 | + pm_pr_dbg("ACPI fixed event wakeup\n"); |
|---|
| 1026 | + return true; |
|---|
| 1027 | + } |
|---|
| 1028 | + |
|---|
| 1029 | + /* Check wakeups from drivers sharing the SCI. */ |
|---|
| 1030 | + if (acpi_check_wakeup_handlers()) { |
|---|
| 1031 | + pm_pr_dbg("ACPI custom handler wakeup\n"); |
|---|
| 1032 | + return true; |
|---|
| 1033 | + } |
|---|
| 1034 | + |
|---|
| 1035 | + /* Check non-EC GPE wakeups and dispatch the EC GPE. */ |
|---|
| 1036 | + if (acpi_ec_dispatch_gpe()) { |
|---|
| 1037 | + pm_pr_dbg("ACPI non-EC GPE wakeup\n"); |
|---|
| 1038 | + return true; |
|---|
| 1039 | + } |
|---|
| 1040 | + |
|---|
| 1041 | + /* |
|---|
| 1042 | + * Cancel the SCI wakeup and process all pending events in case |
|---|
| 1043 | + * there are any wakeup ones in there. |
|---|
| 1044 | + * |
|---|
| 1045 | + * Note that if any non-EC GPEs are active at this point, the |
|---|
| 1046 | + * SCI will retrigger after the rearming below, so no events |
|---|
| 1047 | + * should be missed by canceling the wakeup here. |
|---|
| 1048 | + */ |
|---|
| 1049 | + pm_system_cancel_wakeup(); |
|---|
| 1050 | + acpi_os_wait_events_complete(); |
|---|
| 1051 | + |
|---|
| 1052 | + /* |
|---|
| 1053 | + * The SCI is in the "suspended" state now and it cannot produce |
|---|
| 1054 | + * new wakeup events till the rearming below, so if any of them |
|---|
| 1055 | + * are pending here, they must be resulting from the processing |
|---|
| 1056 | + * of EC events above or coming from somewhere else. |
|---|
| 1057 | + */ |
|---|
| 1058 | + if (pm_wakeup_pending()) { |
|---|
| 1059 | + pm_pr_dbg("Wakeup after ACPI Notify sync\n"); |
|---|
| 1060 | + return true; |
|---|
| 1061 | + } |
|---|
| 1062 | + |
|---|
| 1063 | + pm_wakeup_clear(acpi_sci_irq); |
|---|
| 1064 | + rearm_wake_irq(acpi_sci_irq); |
|---|
| 1065 | + } |
|---|
| 1066 | + |
|---|
| 1067 | + return false; |
|---|
| 1068 | +} |
|---|
| 1069 | + |
|---|
| 1070 | +static void acpi_s2idle_restore_early(void) |
|---|
| 1071 | +{ |
|---|
| 1072 | + if (!lps0_device_handle || sleep_no_lps0) |
|---|
| 1073 | + return; |
|---|
| 1074 | + |
|---|
| 1075 | + acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); |
|---|
| 1076 | + acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); |
|---|
| 1025 | 1077 | } |
|---|
| 1026 | 1078 | |
|---|
| 1027 | 1079 | static void acpi_s2idle_restore(void) |
|---|
| 1028 | 1080 | { |
|---|
| 1081 | + /* |
|---|
| 1082 | + * Drain pending events before restoring the working-state configuration |
|---|
| 1083 | + * of GPEs. |
|---|
| 1084 | + */ |
|---|
| 1085 | + acpi_os_wait_events_complete(); /* synchronize GPE processing */ |
|---|
| 1086 | + acpi_ec_flush_work(); /* flush the EC driver's workqueues */ |
|---|
| 1087 | + acpi_os_wait_events_complete(); /* synchronize Notify handling */ |
|---|
| 1088 | + |
|---|
| 1089 | + s2idle_wakeup = false; |
|---|
| 1090 | + |
|---|
| 1029 | 1091 | acpi_enable_all_runtime_gpes(); |
|---|
| 1030 | 1092 | |
|---|
| 1031 | 1093 | acpi_disable_wakeup_devices(ACPI_STATE_S0); |
|---|
| 1032 | 1094 | |
|---|
| 1033 | | - if (acpi_sci_irq_valid()) |
|---|
| 1034 | | - disable_irq_wake(acpi_sci_irq); |
|---|
| 1035 | | - |
|---|
| 1036 | | - if (lps0_device_handle) { |
|---|
| 1095 | + if (acpi_sci_irq_valid()) { |
|---|
| 1037 | 1096 | acpi_ec_set_gpe_wake_mask(ACPI_GPE_DISABLE); |
|---|
| 1038 | | - |
|---|
| 1039 | | - acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); |
|---|
| 1040 | | - acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); |
|---|
| 1097 | + disable_irq_wake(acpi_sci_irq); |
|---|
| 1041 | 1098 | } |
|---|
| 1042 | 1099 | } |
|---|
| 1043 | 1100 | |
|---|
| 1044 | 1101 | static void acpi_s2idle_end(void) |
|---|
| 1045 | 1102 | { |
|---|
| 1046 | | - s2idle_in_progress = false; |
|---|
| 1047 | 1103 | acpi_scan_lock_release(); |
|---|
| 1048 | 1104 | } |
|---|
| 1049 | 1105 | |
|---|
| 1050 | 1106 | static const struct platform_s2idle_ops acpi_s2idle_ops = { |
|---|
| 1051 | 1107 | .begin = acpi_s2idle_begin, |
|---|
| 1052 | 1108 | .prepare = acpi_s2idle_prepare, |
|---|
| 1109 | + .prepare_late = acpi_s2idle_prepare_late, |
|---|
| 1053 | 1110 | .wake = acpi_s2idle_wake, |
|---|
| 1054 | | - .sync = acpi_s2idle_sync, |
|---|
| 1111 | + .restore_early = acpi_s2idle_restore_early, |
|---|
| 1055 | 1112 | .restore = acpi_s2idle_restore, |
|---|
| 1056 | 1113 | .end = acpi_s2idle_end, |
|---|
| 1057 | 1114 | }; |
|---|
| .. | .. |
|---|
| 1072 | 1129 | } |
|---|
| 1073 | 1130 | |
|---|
| 1074 | 1131 | #else /* !CONFIG_SUSPEND */ |
|---|
| 1075 | | -#define s2idle_in_progress (false) |
|---|
| 1076 | 1132 | #define s2idle_wakeup (false) |
|---|
| 1077 | 1133 | #define lps0_device_handle (NULL) |
|---|
| 1078 | 1134 | static inline void acpi_sleep_suspend_setup(void) {} |
|---|
| .. | .. |
|---|
| 1081 | 1137 | bool acpi_s2idle_wakeup(void) |
|---|
| 1082 | 1138 | { |
|---|
| 1083 | 1139 | return s2idle_wakeup; |
|---|
| 1084 | | -} |
|---|
| 1085 | | - |
|---|
| 1086 | | -bool acpi_sleep_no_ec_events(void) |
|---|
| 1087 | | -{ |
|---|
| 1088 | | - return !s2idle_in_progress || !lps0_device_handle; |
|---|
| 1089 | 1140 | } |
|---|
| 1090 | 1141 | |
|---|
| 1091 | 1142 | #ifdef CONFIG_PM_SLEEP |
|---|
| .. | .. |
|---|
| 1131 | 1182 | nosigcheck = true; |
|---|
| 1132 | 1183 | } |
|---|
| 1133 | 1184 | |
|---|
| 1134 | | -static int acpi_hibernation_begin(void) |
|---|
| 1185 | +static int acpi_hibernation_begin(pm_message_t stage) |
|---|
| 1135 | 1186 | { |
|---|
| 1136 | | - int error; |
|---|
| 1187 | + if (!nvs_nosave) { |
|---|
| 1188 | + int error = suspend_nvs_alloc(); |
|---|
| 1189 | + if (error) |
|---|
| 1190 | + return error; |
|---|
| 1191 | + } |
|---|
| 1137 | 1192 | |
|---|
| 1138 | | - error = nvs_nosave ? 0 : suspend_nvs_alloc(); |
|---|
| 1139 | | - if (!error) |
|---|
| 1140 | | - acpi_pm_start(ACPI_STATE_S4); |
|---|
| 1193 | + if (stage.event == PM_EVENT_HIBERNATE) |
|---|
| 1194 | + pm_set_suspend_via_firmware(); |
|---|
| 1141 | 1195 | |
|---|
| 1142 | | - return error; |
|---|
| 1196 | + acpi_pm_start(ACPI_STATE_S4); |
|---|
| 1197 | + return 0; |
|---|
| 1143 | 1198 | } |
|---|
| 1144 | 1199 | |
|---|
| 1145 | 1200 | static int acpi_hibernation_enter(void) |
|---|
| .. | .. |
|---|
| 1199 | 1254 | * function is used if the pre-ACPI 2.0 suspend ordering has been |
|---|
| 1200 | 1255 | * requested. |
|---|
| 1201 | 1256 | */ |
|---|
| 1202 | | -static int acpi_hibernation_begin_old(void) |
|---|
| 1257 | +static int acpi_hibernation_begin_old(pm_message_t stage) |
|---|
| 1203 | 1258 | { |
|---|
| 1204 | 1259 | int error; |
|---|
| 1205 | 1260 | /* |
|---|
| .. | .. |
|---|
| 1210 | 1265 | acpi_sleep_tts_switch(ACPI_STATE_S4); |
|---|
| 1211 | 1266 | |
|---|
| 1212 | 1267 | error = acpi_sleep_prepare(ACPI_STATE_S4); |
|---|
| 1268 | + if (error) |
|---|
| 1269 | + return error; |
|---|
| 1213 | 1270 | |
|---|
| 1214 | | - if (!error) { |
|---|
| 1215 | | - if (!nvs_nosave) |
|---|
| 1216 | | - error = suspend_nvs_alloc(); |
|---|
| 1217 | | - if (!error) { |
|---|
| 1218 | | - acpi_target_sleep_state = ACPI_STATE_S4; |
|---|
| 1219 | | - acpi_scan_lock_acquire(); |
|---|
| 1220 | | - } |
|---|
| 1271 | + if (!nvs_nosave) { |
|---|
| 1272 | + error = suspend_nvs_alloc(); |
|---|
| 1273 | + if (error) |
|---|
| 1274 | + return error; |
|---|
| 1221 | 1275 | } |
|---|
| 1222 | | - return error; |
|---|
| 1276 | + |
|---|
| 1277 | + if (stage.event == PM_EVENT_HIBERNATE) |
|---|
| 1278 | + pm_set_suspend_via_firmware(); |
|---|
| 1279 | + |
|---|
| 1280 | + acpi_target_sleep_state = ACPI_STATE_S4; |
|---|
| 1281 | + acpi_scan_lock_acquire(); |
|---|
| 1282 | + return 0; |
|---|
| 1223 | 1283 | } |
|---|
| 1224 | 1284 | |
|---|
| 1225 | 1285 | /* |
|---|