1d08ca2caSLen Brown /* 2d08ca2caSLen Brown * sleep.c - ACPI sleep support. 3d08ca2caSLen Brown * 4d08ca2caSLen Brown * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> 5d08ca2caSLen Brown * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com> 6d08ca2caSLen Brown * Copyright (c) 2000-2003 Patrick Mochel 7d08ca2caSLen Brown * Copyright (c) 2003 Open Source Development Lab 8d08ca2caSLen Brown * 9d08ca2caSLen Brown * This file is released under the GPLv2. 10d08ca2caSLen Brown * 11d08ca2caSLen Brown */ 12d08ca2caSLen Brown 13d08ca2caSLen Brown #include <linux/delay.h> 14d08ca2caSLen Brown #include <linux/irq.h> 15d08ca2caSLen Brown #include <linux/dmi.h> 16d08ca2caSLen Brown #include <linux/device.h> 17d08ca2caSLen Brown #include <linux/suspend.h> 18d08ca2caSLen Brown #include <linux/reboot.h> 19d1ee4335SH. Peter Anvin #include <linux/acpi.h> 20d08ca2caSLen Brown 21d08ca2caSLen Brown #include <asm/io.h> 22d08ca2caSLen Brown 23d08ca2caSLen Brown #include <acpi/acpi_bus.h> 24d08ca2caSLen Brown #include <acpi/acpi_drivers.h> 25e60cc7a6SBjorn Helgaas 26e60cc7a6SBjorn Helgaas #include "internal.h" 27d08ca2caSLen Brown #include "sleep.h" 28d08ca2caSLen Brown 2901eac60bSStephen Hemminger static u8 sleep_states[ACPI_S_STATE_COUNT]; 30d08ca2caSLen Brown 31d08ca2caSLen Brown static void acpi_sleep_tts_switch(u32 acpi_state) 32d08ca2caSLen Brown { 33d08ca2caSLen Brown union acpi_object in_arg = { ACPI_TYPE_INTEGER }; 34d08ca2caSLen Brown struct acpi_object_list arg_list = { 1, &in_arg }; 35d08ca2caSLen Brown acpi_status status = AE_OK; 36d08ca2caSLen Brown 37d08ca2caSLen Brown in_arg.integer.value = acpi_state; 38d08ca2caSLen Brown status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL); 39d08ca2caSLen Brown if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 40d08ca2caSLen Brown /* 41d08ca2caSLen Brown * OS can't evaluate the _TTS object correctly. Some warning 42d08ca2caSLen Brown * message will be printed. But it won't break anything. 43d08ca2caSLen Brown */ 44d08ca2caSLen Brown printk(KERN_NOTICE "Failure in evaluating _TTS object\n"); 45d08ca2caSLen Brown } 46d08ca2caSLen Brown } 47d08ca2caSLen Brown 48d08ca2caSLen Brown static int tts_notify_reboot(struct notifier_block *this, 49d08ca2caSLen Brown unsigned long code, void *x) 50d08ca2caSLen Brown { 51d08ca2caSLen Brown acpi_sleep_tts_switch(ACPI_STATE_S5); 52d08ca2caSLen Brown return NOTIFY_DONE; 53d08ca2caSLen Brown } 54d08ca2caSLen Brown 55d08ca2caSLen Brown static struct notifier_block tts_notifier = { 56d08ca2caSLen Brown .notifier_call = tts_notify_reboot, 57d08ca2caSLen Brown .next = NULL, 58d08ca2caSLen Brown .priority = 0, 59d08ca2caSLen Brown }; 60d08ca2caSLen Brown 61d08ca2caSLen Brown static int acpi_sleep_prepare(u32 acpi_state) 62d08ca2caSLen Brown { 63d08ca2caSLen Brown #ifdef CONFIG_ACPI_SLEEP 64d08ca2caSLen Brown /* do we have a wakeup address for S2 and S3? */ 65d08ca2caSLen Brown if (acpi_state == ACPI_STATE_S3) { 66d08ca2caSLen Brown if (!acpi_wakeup_address) { 67d08ca2caSLen Brown return -EFAULT; 68d08ca2caSLen Brown } 69d08ca2caSLen Brown acpi_set_firmware_waking_vector( 70d08ca2caSLen Brown (acpi_physical_address)acpi_wakeup_address); 71d08ca2caSLen Brown 72d08ca2caSLen Brown } 73d08ca2caSLen Brown ACPI_FLUSH_CPU_CACHE(); 74d08ca2caSLen Brown #endif 75d08ca2caSLen Brown printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", 76d08ca2caSLen Brown acpi_state); 7778f5f023SRafael J. Wysocki acpi_enable_wakeup_devices(acpi_state); 78d08ca2caSLen Brown acpi_enter_sleep_state_prep(acpi_state); 79d08ca2caSLen Brown return 0; 80d08ca2caSLen Brown } 81d08ca2caSLen Brown 82d08ca2caSLen Brown #ifdef CONFIG_ACPI_SLEEP 83091aad6aSJan Beulich static u32 acpi_target_sleep_state = ACPI_STATE_S0; 84091aad6aSJan Beulich 85d7f0eea9SZhang Rui /* 8672ad5d77SRafael J. Wysocki * The ACPI specification wants us to save NVS memory regions during hibernation 8772ad5d77SRafael J. Wysocki * and to restore them during the subsequent resume. Windows does that also for 8872ad5d77SRafael J. Wysocki * suspend to RAM. However, it is known that this mechanism does not work on 8972ad5d77SRafael J. Wysocki * all machines, so we allow the user to disable it with the help of the 9072ad5d77SRafael J. Wysocki * 'acpi_sleep=nonvs' kernel command line option. 9172ad5d77SRafael J. Wysocki */ 9272ad5d77SRafael J. Wysocki static bool nvs_nosave; 9372ad5d77SRafael J. Wysocki 9472ad5d77SRafael J. Wysocki void __init acpi_nvs_nosave(void) 9572ad5d77SRafael J. Wysocki { 9672ad5d77SRafael J. Wysocki nvs_nosave = true; 9772ad5d77SRafael J. Wysocki } 9872ad5d77SRafael J. Wysocki 9972ad5d77SRafael J. Wysocki /* 100d08ca2caSLen Brown * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the 101d08ca2caSLen Brown * user to request that behavior by using the 'acpi_old_suspend_ordering' 102d08ca2caSLen Brown * kernel command line option that causes the following variable to be set. 103d08ca2caSLen Brown */ 104d08ca2caSLen Brown static bool old_suspend_ordering; 105d08ca2caSLen Brown 106d08ca2caSLen Brown void __init acpi_old_suspend_ordering(void) 107d08ca2caSLen Brown { 108d08ca2caSLen Brown old_suspend_ordering = true; 109d08ca2caSLen Brown } 110d08ca2caSLen Brown 111d08ca2caSLen Brown /** 112d5a64513SRafael J. Wysocki * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. 113d08ca2caSLen Brown */ 114d5a64513SRafael J. Wysocki static int acpi_pm_freeze(void) 115d08ca2caSLen Brown { 116d08ca2caSLen Brown acpi_disable_all_gpes(); 117d5a64513SRafael J. Wysocki acpi_os_wait_events_complete(NULL); 118fe955682SRafael J. Wysocki acpi_ec_block_transactions(); 119d08ca2caSLen Brown return 0; 120d08ca2caSLen Brown } 121d08ca2caSLen Brown 122d08ca2caSLen Brown /** 123c5f7a1bbSRafael J. Wysocki * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS. 124c5f7a1bbSRafael J. Wysocki */ 125c5f7a1bbSRafael J. Wysocki static int acpi_pm_pre_suspend(void) 126c5f7a1bbSRafael J. Wysocki { 127c5f7a1bbSRafael J. Wysocki acpi_pm_freeze(); 12826fcaf60SJiri Slaby return suspend_nvs_save(); 129c5f7a1bbSRafael J. Wysocki } 130c5f7a1bbSRafael J. Wysocki 131c5f7a1bbSRafael J. Wysocki /** 132d08ca2caSLen Brown * __acpi_pm_prepare - Prepare the platform to enter the target state. 133d08ca2caSLen Brown * 134d08ca2caSLen Brown * If necessary, set the firmware waking vector and do arch-specific 135d08ca2caSLen Brown * nastiness to get the wakeup code to the waking vector. 136d08ca2caSLen Brown */ 137d08ca2caSLen Brown static int __acpi_pm_prepare(void) 138d08ca2caSLen Brown { 139d08ca2caSLen Brown int error = acpi_sleep_prepare(acpi_target_sleep_state); 140d08ca2caSLen Brown if (error) 141d08ca2caSLen Brown acpi_target_sleep_state = ACPI_STATE_S0; 142c5f7a1bbSRafael J. Wysocki 143d08ca2caSLen Brown return error; 144d08ca2caSLen Brown } 145d08ca2caSLen Brown 146d08ca2caSLen Brown /** 147d08ca2caSLen Brown * acpi_pm_prepare - Prepare the platform to enter the target sleep 148d08ca2caSLen Brown * state and disable the GPEs. 149d08ca2caSLen Brown */ 150d08ca2caSLen Brown static int acpi_pm_prepare(void) 151d08ca2caSLen Brown { 152d08ca2caSLen Brown int error = __acpi_pm_prepare(); 153d08ca2caSLen Brown if (!error) 15426fcaf60SJiri Slaby error = acpi_pm_pre_suspend(); 155d5a64513SRafael J. Wysocki 156d08ca2caSLen Brown return error; 157d08ca2caSLen Brown } 158d08ca2caSLen Brown 159d08ca2caSLen Brown /** 160d08ca2caSLen Brown * acpi_pm_finish - Instruct the platform to leave a sleep state. 161d08ca2caSLen Brown * 162d08ca2caSLen Brown * This is called after we wake back up (or if entering the sleep state 163d08ca2caSLen Brown * failed). 164d08ca2caSLen Brown */ 165d08ca2caSLen Brown static void acpi_pm_finish(void) 166d08ca2caSLen Brown { 167d08ca2caSLen Brown u32 acpi_state = acpi_target_sleep_state; 168d08ca2caSLen Brown 16942de5532SLen Brown acpi_ec_unblock_transactions(); 170d551d81dSRafael J. Wysocki suspend_nvs_free(); 1712a6b6976SMatthew Garrett 172d08ca2caSLen Brown if (acpi_state == ACPI_STATE_S0) 173d08ca2caSLen Brown return; 174d08ca2caSLen Brown 175d08ca2caSLen Brown printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n", 176d08ca2caSLen Brown acpi_state); 17778f5f023SRafael J. Wysocki acpi_disable_wakeup_devices(acpi_state); 178d08ca2caSLen Brown acpi_leave_sleep_state(acpi_state); 179d08ca2caSLen Brown 180d08ca2caSLen Brown /* reset firmware waking vector */ 181d08ca2caSLen Brown acpi_set_firmware_waking_vector((acpi_physical_address) 0); 182d08ca2caSLen Brown 183d08ca2caSLen Brown acpi_target_sleep_state = ACPI_STATE_S0; 184d08ca2caSLen Brown } 185d08ca2caSLen Brown 186d08ca2caSLen Brown /** 187d08ca2caSLen Brown * acpi_pm_end - Finish up suspend sequence. 188d08ca2caSLen Brown */ 189d08ca2caSLen Brown static void acpi_pm_end(void) 190d08ca2caSLen Brown { 191d08ca2caSLen Brown /* 192d08ca2caSLen Brown * This is necessary in case acpi_pm_finish() is not called during a 193d08ca2caSLen Brown * failing transition to a sleep state. 194d08ca2caSLen Brown */ 195d08ca2caSLen Brown acpi_target_sleep_state = ACPI_STATE_S0; 196d08ca2caSLen Brown acpi_sleep_tts_switch(acpi_target_sleep_state); 197d08ca2caSLen Brown } 198d08ca2caSLen Brown #else /* !CONFIG_ACPI_SLEEP */ 199d08ca2caSLen Brown #define acpi_target_sleep_state ACPI_STATE_S0 200d08ca2caSLen Brown #endif /* CONFIG_ACPI_SLEEP */ 201d08ca2caSLen Brown 202d08ca2caSLen Brown #ifdef CONFIG_SUSPEND 203d08ca2caSLen Brown static u32 acpi_suspend_states[] = { 204d08ca2caSLen Brown [PM_SUSPEND_ON] = ACPI_STATE_S0, 205d08ca2caSLen Brown [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, 206d08ca2caSLen Brown [PM_SUSPEND_MEM] = ACPI_STATE_S3, 207d08ca2caSLen Brown [PM_SUSPEND_MAX] = ACPI_STATE_S5 208d08ca2caSLen Brown }; 209d08ca2caSLen Brown 210d08ca2caSLen Brown /** 211d08ca2caSLen Brown * acpi_suspend_begin - Set the target system sleep state to the state 212d08ca2caSLen Brown * associated with given @pm_state, if supported. 213d08ca2caSLen Brown */ 214d08ca2caSLen Brown static int acpi_suspend_begin(suspend_state_t pm_state) 215d08ca2caSLen Brown { 216d08ca2caSLen Brown u32 acpi_state = acpi_suspend_states[pm_state]; 217d08ca2caSLen Brown int error = 0; 218d08ca2caSLen Brown 21972ad5d77SRafael J. Wysocki error = nvs_nosave ? 0 : suspend_nvs_alloc(); 2202a6b6976SMatthew Garrett if (error) 2212a6b6976SMatthew Garrett return error; 2222a6b6976SMatthew Garrett 223d08ca2caSLen Brown if (sleep_states[acpi_state]) { 224d08ca2caSLen Brown acpi_target_sleep_state = acpi_state; 225d08ca2caSLen Brown acpi_sleep_tts_switch(acpi_target_sleep_state); 226d08ca2caSLen Brown } else { 227d08ca2caSLen Brown printk(KERN_ERR "ACPI does not support this state: %d\n", 228d08ca2caSLen Brown pm_state); 229d08ca2caSLen Brown error = -ENOSYS; 230d08ca2caSLen Brown } 231d08ca2caSLen Brown return error; 232d08ca2caSLen Brown } 233d08ca2caSLen Brown 234d08ca2caSLen Brown /** 235d08ca2caSLen Brown * acpi_suspend_enter - Actually enter a sleep state. 236d08ca2caSLen Brown * @pm_state: ignored 237d08ca2caSLen Brown * 238d08ca2caSLen Brown * Flush caches and go to sleep. For STR we have to call arch-specific 239d08ca2caSLen Brown * assembly, which in turn call acpi_enter_sleep_state(). 240d08ca2caSLen Brown * It's unfortunate, but it works. Please fix if you're feeling frisky. 241d08ca2caSLen Brown */ 242d08ca2caSLen Brown static int acpi_suspend_enter(suspend_state_t pm_state) 243d08ca2caSLen Brown { 244d08ca2caSLen Brown acpi_status status = AE_OK; 245d08ca2caSLen Brown u32 acpi_state = acpi_target_sleep_state; 246979f11b0SRafael J. Wysocki int error; 247d08ca2caSLen Brown 248d08ca2caSLen Brown ACPI_FLUSH_CPU_CACHE(); 249d08ca2caSLen Brown 250d08ca2caSLen Brown switch (acpi_state) { 251d08ca2caSLen Brown case ACPI_STATE_S1: 252d08ca2caSLen Brown barrier(); 253d08ca2caSLen Brown status = acpi_enter_sleep_state(acpi_state); 254d08ca2caSLen Brown break; 255d08ca2caSLen Brown 256d08ca2caSLen Brown case ACPI_STATE_S3: 257f1a2003eSRafael J. Wysocki error = acpi_suspend_lowlevel(); 258979f11b0SRafael J. Wysocki if (error) 259979f11b0SRafael J. Wysocki return error; 2607a63f08bSRafael J. Wysocki pr_info(PREFIX "Low-level resume complete\n"); 261d08ca2caSLen Brown break; 262d08ca2caSLen Brown } 263d08ca2caSLen Brown 264b6dacf63SMatthew Garrett /* This violates the spec but is required for bug compatibility. */ 26550ffba1bSBob Moore acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); 266d08ca2caSLen Brown 267d08ca2caSLen Brown /* Reprogram control registers and execute _BFS */ 268d08ca2caSLen Brown acpi_leave_sleep_state_prep(acpi_state); 269d08ca2caSLen Brown 270d08ca2caSLen Brown /* ACPI 3.0 specs (P62) says that it's the responsibility 271d08ca2caSLen Brown * of the OSPM to clear the status bit [ implying that the 272d08ca2caSLen Brown * POWER_BUTTON event should not reach userspace ] 273d08ca2caSLen Brown */ 274d08ca2caSLen Brown if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) 275d08ca2caSLen Brown acpi_clear_event(ACPI_EVENT_POWER_BUTTON); 276d08ca2caSLen Brown 277d08ca2caSLen Brown /* 278d08ca2caSLen Brown * Disable and clear GPE status before interrupt is enabled. Some GPEs 279d08ca2caSLen Brown * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. 280d08ca2caSLen Brown * acpi_leave_sleep_state will reenable specific GPEs later 281d08ca2caSLen Brown */ 282d08ca2caSLen Brown acpi_disable_all_gpes(); 283d5a64513SRafael J. Wysocki /* Allow EC transactions to happen. */ 284fe955682SRafael J. Wysocki acpi_ec_unblock_transactions_early(); 285d08ca2caSLen Brown 2862a6b6976SMatthew Garrett suspend_nvs_restore(); 2872a6b6976SMatthew Garrett 288d08ca2caSLen Brown return ACPI_SUCCESS(status) ? 0 : -EFAULT; 289d08ca2caSLen Brown } 290d08ca2caSLen Brown 291d08ca2caSLen Brown static int acpi_suspend_state_valid(suspend_state_t pm_state) 292d08ca2caSLen Brown { 293d08ca2caSLen Brown u32 acpi_state; 294d08ca2caSLen Brown 295d08ca2caSLen Brown switch (pm_state) { 296d08ca2caSLen Brown case PM_SUSPEND_ON: 297d08ca2caSLen Brown case PM_SUSPEND_STANDBY: 298d08ca2caSLen Brown case PM_SUSPEND_MEM: 299d08ca2caSLen Brown acpi_state = acpi_suspend_states[pm_state]; 300d08ca2caSLen Brown 301d08ca2caSLen Brown return sleep_states[acpi_state]; 302d08ca2caSLen Brown default: 303d08ca2caSLen Brown return 0; 304d08ca2caSLen Brown } 305d08ca2caSLen Brown } 306d08ca2caSLen Brown 3072f55ac07SLionel Debroux static const struct platform_suspend_ops acpi_suspend_ops = { 308d08ca2caSLen Brown .valid = acpi_suspend_state_valid, 309d08ca2caSLen Brown .begin = acpi_suspend_begin, 3106a7c7eafSRafael J. Wysocki .prepare_late = acpi_pm_prepare, 311d08ca2caSLen Brown .enter = acpi_suspend_enter, 312618d7fd0SRafael J. Wysocki .wake = acpi_pm_finish, 313d08ca2caSLen Brown .end = acpi_pm_end, 314d08ca2caSLen Brown }; 315d08ca2caSLen Brown 316d08ca2caSLen Brown /** 317d08ca2caSLen Brown * acpi_suspend_begin_old - Set the target system sleep state to the 318d08ca2caSLen Brown * state associated with given @pm_state, if supported, and 319d08ca2caSLen Brown * execute the _PTS control method. This function is used if the 320d08ca2caSLen Brown * pre-ACPI 2.0 suspend ordering has been requested. 321d08ca2caSLen Brown */ 322d08ca2caSLen Brown static int acpi_suspend_begin_old(suspend_state_t pm_state) 323d08ca2caSLen Brown { 324d08ca2caSLen Brown int error = acpi_suspend_begin(pm_state); 325d08ca2caSLen Brown if (!error) 326d08ca2caSLen Brown error = __acpi_pm_prepare(); 327c5f7a1bbSRafael J. Wysocki 328d08ca2caSLen Brown return error; 329d08ca2caSLen Brown } 330d08ca2caSLen Brown 331d08ca2caSLen Brown /* 332d08ca2caSLen Brown * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has 333d08ca2caSLen Brown * been requested. 334d08ca2caSLen Brown */ 3352f55ac07SLionel Debroux static const struct platform_suspend_ops acpi_suspend_ops_old = { 336d08ca2caSLen Brown .valid = acpi_suspend_state_valid, 337d08ca2caSLen Brown .begin = acpi_suspend_begin_old, 338c5f7a1bbSRafael J. Wysocki .prepare_late = acpi_pm_pre_suspend, 339d08ca2caSLen Brown .enter = acpi_suspend_enter, 340618d7fd0SRafael J. Wysocki .wake = acpi_pm_finish, 341d08ca2caSLen Brown .end = acpi_pm_end, 342d08ca2caSLen Brown .recover = acpi_pm_finish, 343d08ca2caSLen Brown }; 344d08ca2caSLen Brown 345d08ca2caSLen Brown static int __init init_old_suspend_ordering(const struct dmi_system_id *d) 346d08ca2caSLen Brown { 347d08ca2caSLen Brown old_suspend_ordering = true; 348d08ca2caSLen Brown return 0; 349d08ca2caSLen Brown } 350d08ca2caSLen Brown 35153998648SRafael J. Wysocki static int __init init_nvs_nosave(const struct dmi_system_id *d) 35253998648SRafael J. Wysocki { 35353998648SRafael J. Wysocki acpi_nvs_nosave(); 35453998648SRafael J. Wysocki return 0; 35553998648SRafael J. Wysocki } 35653998648SRafael J. Wysocki 357d08ca2caSLen Brown static struct dmi_system_id __initdata acpisleep_dmi_table[] = { 358d08ca2caSLen Brown { 359d08ca2caSLen Brown .callback = init_old_suspend_ordering, 360d08ca2caSLen Brown .ident = "Abit KN9 (nForce4 variant)", 361d08ca2caSLen Brown .matches = { 362d08ca2caSLen Brown DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), 363d08ca2caSLen Brown DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), 364d08ca2caSLen Brown }, 365d08ca2caSLen Brown }, 366d08ca2caSLen Brown { 367d08ca2caSLen Brown .callback = init_old_suspend_ordering, 368d08ca2caSLen Brown .ident = "HP xw4600 Workstation", 369d08ca2caSLen Brown .matches = { 370d08ca2caSLen Brown DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 371d08ca2caSLen Brown DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), 372d08ca2caSLen Brown }, 373d08ca2caSLen Brown }, 374d08ca2caSLen Brown { 375a1404495SAndy Whitcroft .callback = init_old_suspend_ordering, 376a1404495SAndy Whitcroft .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", 377a1404495SAndy Whitcroft .matches = { 378a1404495SAndy Whitcroft DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), 379a1404495SAndy Whitcroft DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), 380a1404495SAndy Whitcroft }, 381a1404495SAndy Whitcroft }, 38245e77988SZhang Rui { 3832a9ef8e1SZhao Yakui .callback = init_old_suspend_ordering, 3842a9ef8e1SZhao Yakui .ident = "Panasonic CF51-2L", 3852a9ef8e1SZhao Yakui .matches = { 3862a9ef8e1SZhao Yakui DMI_MATCH(DMI_BOARD_VENDOR, 3872a9ef8e1SZhao Yakui "Matsushita Electric Industrial Co.,Ltd."), 3882a9ef8e1SZhao Yakui DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), 3892a9ef8e1SZhao Yakui }, 3902a9ef8e1SZhao Yakui }, 39153998648SRafael J. Wysocki { 39253998648SRafael J. Wysocki .callback = init_nvs_nosave, 39353998648SRafael J. Wysocki .ident = "Sony Vaio VGN-SR11M", 39453998648SRafael J. Wysocki .matches = { 39553998648SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 39653998648SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), 39753998648SRafael J. Wysocki }, 39853998648SRafael J. Wysocki }, 39953998648SRafael J. Wysocki { 40053998648SRafael J. Wysocki .callback = init_nvs_nosave, 40153998648SRafael J. Wysocki .ident = "Everex StepNote Series", 40253998648SRafael J. Wysocki .matches = { 40353998648SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), 40453998648SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), 40553998648SRafael J. Wysocki }, 40653998648SRafael J. Wysocki }, 407af48931cSRafael J. Wysocki { 408af48931cSRafael J. Wysocki .callback = init_nvs_nosave, 409af48931cSRafael J. Wysocki .ident = "Sony Vaio VPCEB1Z1E", 410af48931cSRafael J. Wysocki .matches = { 411af48931cSRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 412af48931cSRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), 413af48931cSRafael J. Wysocki }, 414af48931cSRafael J. Wysocki }, 415291a73c9SRafael J. Wysocki { 416291a73c9SRafael J. Wysocki .callback = init_nvs_nosave, 417291a73c9SRafael J. Wysocki .ident = "Sony Vaio VGN-NW130D", 418291a73c9SRafael J. Wysocki .matches = { 419291a73c9SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 420291a73c9SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), 421291a73c9SRafael J. Wysocki }, 422291a73c9SRafael J. Wysocki }, 4237b330707SRafael J. Wysocki { 4247b330707SRafael J. Wysocki .callback = init_nvs_nosave, 4257b330707SRafael J. Wysocki .ident = "Averatec AV1020-ED2", 4267b330707SRafael J. Wysocki .matches = { 4277b330707SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), 4287b330707SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), 4297b330707SRafael J. Wysocki }, 4307b330707SRafael J. Wysocki }, 431bb0c5ed6SZhang Rui { 432bb0c5ed6SZhang Rui .callback = init_old_suspend_ordering, 433bb0c5ed6SZhang Rui .ident = "Asus A8N-SLI DELUXE", 434bb0c5ed6SZhang Rui .matches = { 435bb0c5ed6SZhang Rui DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 436bb0c5ed6SZhang Rui DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), 437bb0c5ed6SZhang Rui }, 438bb0c5ed6SZhang Rui }, 439bb0c5ed6SZhang Rui { 440bb0c5ed6SZhang Rui .callback = init_old_suspend_ordering, 441bb0c5ed6SZhang Rui .ident = "Asus A8N-SLI Premium", 442bb0c5ed6SZhang Rui .matches = { 443bb0c5ed6SZhang Rui DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), 444bb0c5ed6SZhang Rui DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), 445bb0c5ed6SZhang Rui }, 446bb0c5ed6SZhang Rui }, 44789e8ea12SRafael J. Wysocki { 44889e8ea12SRafael J. Wysocki .callback = init_nvs_nosave, 44989e8ea12SRafael J. Wysocki .ident = "Sony Vaio VGN-SR26GN_P", 45089e8ea12SRafael J. Wysocki .matches = { 45189e8ea12SRafael J. Wysocki DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 45289e8ea12SRafael J. Wysocki DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), 45389e8ea12SRafael J. Wysocki }, 45489e8ea12SRafael J. Wysocki }, 455*731b25a4SBogdan Radulescu { 456*731b25a4SBogdan Radulescu .callback = init_nvs_nosave, 457*731b25a4SBogdan Radulescu .ident = "Sony Vaio VGN-FW520F", 458*731b25a4SBogdan Radulescu .matches = { 459*731b25a4SBogdan Radulescu DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 460*731b25a4SBogdan Radulescu DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), 461*731b25a4SBogdan Radulescu }, 462*731b25a4SBogdan Radulescu }, 463d08ca2caSLen Brown {}, 464d08ca2caSLen Brown }; 465d08ca2caSLen Brown #endif /* CONFIG_SUSPEND */ 466d08ca2caSLen Brown 467d08ca2caSLen Brown #ifdef CONFIG_HIBERNATION 468d08ca2caSLen Brown static unsigned long s4_hardware_signature; 469d08ca2caSLen Brown static struct acpi_table_facs *facs; 470d08ca2caSLen Brown static bool nosigcheck; 471d08ca2caSLen Brown 472d08ca2caSLen Brown void __init acpi_no_s4_hw_signature(void) 473d08ca2caSLen Brown { 474d08ca2caSLen Brown nosigcheck = true; 475d08ca2caSLen Brown } 476d08ca2caSLen Brown 477d08ca2caSLen Brown static int acpi_hibernation_begin(void) 478d08ca2caSLen Brown { 479d08ca2caSLen Brown int error; 480d08ca2caSLen Brown 48172ad5d77SRafael J. Wysocki error = nvs_nosave ? 0 : suspend_nvs_alloc(); 482d08ca2caSLen Brown if (!error) { 483d08ca2caSLen Brown acpi_target_sleep_state = ACPI_STATE_S4; 484d08ca2caSLen Brown acpi_sleep_tts_switch(acpi_target_sleep_state); 485d08ca2caSLen Brown } 486d08ca2caSLen Brown 487d08ca2caSLen Brown return error; 488d08ca2caSLen Brown } 489d08ca2caSLen Brown 490d08ca2caSLen Brown static int acpi_hibernation_enter(void) 491d08ca2caSLen Brown { 492d08ca2caSLen Brown acpi_status status = AE_OK; 493d08ca2caSLen Brown 494d08ca2caSLen Brown ACPI_FLUSH_CPU_CACHE(); 495d08ca2caSLen Brown 496d08ca2caSLen Brown /* This shouldn't return. If it returns, we have a problem */ 497d08ca2caSLen Brown status = acpi_enter_sleep_state(ACPI_STATE_S4); 498d08ca2caSLen Brown /* Reprogram control registers and execute _BFS */ 499d08ca2caSLen Brown acpi_leave_sleep_state_prep(ACPI_STATE_S4); 500d08ca2caSLen Brown 501d08ca2caSLen Brown return ACPI_SUCCESS(status) ? 0 : -EFAULT; 502d08ca2caSLen Brown } 503d08ca2caSLen Brown 504d08ca2caSLen Brown static void acpi_hibernation_leave(void) 505d08ca2caSLen Brown { 506d08ca2caSLen Brown /* 507d08ca2caSLen Brown * If ACPI is not enabled by the BIOS and the boot kernel, we need to 508d08ca2caSLen Brown * enable it here. 509d08ca2caSLen Brown */ 510d08ca2caSLen Brown acpi_enable(); 511d08ca2caSLen Brown /* Reprogram control registers and execute _BFS */ 512d08ca2caSLen Brown acpi_leave_sleep_state_prep(ACPI_STATE_S4); 513d08ca2caSLen Brown /* Check the hardware signature */ 514d08ca2caSLen Brown if (facs && s4_hardware_signature != facs->hardware_signature) { 515d08ca2caSLen Brown printk(KERN_EMERG "ACPI: Hardware changed while hibernated, " 516d08ca2caSLen Brown "cannot resume!\n"); 517d08ca2caSLen Brown panic("ACPI S4 hardware signature mismatch"); 518d08ca2caSLen Brown } 519d08ca2caSLen Brown /* Restore the NVS memory area */ 520dd4c4f17SMatthew Garrett suspend_nvs_restore(); 521d5a64513SRafael J. Wysocki /* Allow EC transactions to happen. */ 522fe955682SRafael J. Wysocki acpi_ec_unblock_transactions_early(); 523d08ca2caSLen Brown } 524d08ca2caSLen Brown 525d5a64513SRafael J. Wysocki static void acpi_pm_thaw(void) 526f6bb13aaSRafael J. Wysocki { 527fe955682SRafael J. Wysocki acpi_ec_unblock_transactions(); 528d08ca2caSLen Brown acpi_enable_all_runtime_gpes(); 529d08ca2caSLen Brown } 530d08ca2caSLen Brown 531073ef1f6SLionel Debroux static const struct platform_hibernation_ops acpi_hibernation_ops = { 532d08ca2caSLen Brown .begin = acpi_hibernation_begin, 533d08ca2caSLen Brown .end = acpi_pm_end, 534c5f7a1bbSRafael J. Wysocki .pre_snapshot = acpi_pm_prepare, 5352a6b6976SMatthew Garrett .finish = acpi_pm_finish, 536d08ca2caSLen Brown .prepare = acpi_pm_prepare, 537d08ca2caSLen Brown .enter = acpi_hibernation_enter, 538d08ca2caSLen Brown .leave = acpi_hibernation_leave, 539d5a64513SRafael J. Wysocki .pre_restore = acpi_pm_freeze, 540d5a64513SRafael J. Wysocki .restore_cleanup = acpi_pm_thaw, 541d08ca2caSLen Brown }; 542d08ca2caSLen Brown 543d08ca2caSLen Brown /** 544d08ca2caSLen Brown * acpi_hibernation_begin_old - Set the target system sleep state to 545d08ca2caSLen Brown * ACPI_STATE_S4 and execute the _PTS control method. This 546d08ca2caSLen Brown * function is used if the pre-ACPI 2.0 suspend ordering has been 547d08ca2caSLen Brown * requested. 548d08ca2caSLen Brown */ 549d08ca2caSLen Brown static int acpi_hibernation_begin_old(void) 550d08ca2caSLen Brown { 551d08ca2caSLen Brown int error; 552d08ca2caSLen Brown /* 553d08ca2caSLen Brown * The _TTS object should always be evaluated before the _PTS object. 554d08ca2caSLen Brown * When the old_suspended_ordering is true, the _PTS object is 555d08ca2caSLen Brown * evaluated in the acpi_sleep_prepare. 556d08ca2caSLen Brown */ 557d08ca2caSLen Brown acpi_sleep_tts_switch(ACPI_STATE_S4); 558d08ca2caSLen Brown 559d08ca2caSLen Brown error = acpi_sleep_prepare(ACPI_STATE_S4); 560d08ca2caSLen Brown 561d08ca2caSLen Brown if (!error) { 56272ad5d77SRafael J. Wysocki if (!nvs_nosave) 563dd4c4f17SMatthew Garrett error = suspend_nvs_alloc(); 564d08ca2caSLen Brown if (!error) 565d08ca2caSLen Brown acpi_target_sleep_state = ACPI_STATE_S4; 566d08ca2caSLen Brown } 567d08ca2caSLen Brown return error; 568d08ca2caSLen Brown } 569d08ca2caSLen Brown 570d08ca2caSLen Brown /* 571d08ca2caSLen Brown * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has 572d08ca2caSLen Brown * been requested. 573d08ca2caSLen Brown */ 574073ef1f6SLionel Debroux static const struct platform_hibernation_ops acpi_hibernation_ops_old = { 575d08ca2caSLen Brown .begin = acpi_hibernation_begin_old, 576d08ca2caSLen Brown .end = acpi_pm_end, 577c5f7a1bbSRafael J. Wysocki .pre_snapshot = acpi_pm_pre_suspend, 578d5a64513SRafael J. Wysocki .prepare = acpi_pm_freeze, 5792a6b6976SMatthew Garrett .finish = acpi_pm_finish, 580d08ca2caSLen Brown .enter = acpi_hibernation_enter, 581d08ca2caSLen Brown .leave = acpi_hibernation_leave, 582d5a64513SRafael J. Wysocki .pre_restore = acpi_pm_freeze, 583d5a64513SRafael J. Wysocki .restore_cleanup = acpi_pm_thaw, 584d08ca2caSLen Brown .recover = acpi_pm_finish, 585d08ca2caSLen Brown }; 586d08ca2caSLen Brown #endif /* CONFIG_HIBERNATION */ 587d08ca2caSLen Brown 588d08ca2caSLen Brown int acpi_suspend(u32 acpi_state) 589d08ca2caSLen Brown { 590d08ca2caSLen Brown suspend_state_t states[] = { 591d08ca2caSLen Brown [1] = PM_SUSPEND_STANDBY, 592d08ca2caSLen Brown [3] = PM_SUSPEND_MEM, 593d08ca2caSLen Brown [5] = PM_SUSPEND_MAX 594d08ca2caSLen Brown }; 595d08ca2caSLen Brown 596d08ca2caSLen Brown if (acpi_state < 6 && states[acpi_state]) 597d08ca2caSLen Brown return pm_suspend(states[acpi_state]); 598d08ca2caSLen Brown if (acpi_state == 4) 599d08ca2caSLen Brown return hibernate(); 600d08ca2caSLen Brown return -EINVAL; 601d08ca2caSLen Brown } 602d08ca2caSLen Brown 603aa338601SRafael J. Wysocki #ifdef CONFIG_PM 604d08ca2caSLen Brown /** 605d08ca2caSLen Brown * acpi_pm_device_sleep_state - return preferred power state of ACPI device 606d08ca2caSLen Brown * in the system sleep state given by %acpi_target_sleep_state 607d08ca2caSLen Brown * @dev: device to examine; its driver model wakeup flags control 608d08ca2caSLen Brown * whether it should be able to wake up the system 609d08ca2caSLen Brown * @d_min_p: used to store the upper limit of allowed states range 610d08ca2caSLen Brown * Return value: preferred power state of the device on success, -ENODEV on 611d08ca2caSLen Brown * failure (ie. if there's no 'struct acpi_device' for @dev) 612d08ca2caSLen Brown * 613d08ca2caSLen Brown * Find the lowest power (highest number) ACPI device power state that 614d08ca2caSLen Brown * device @dev can be in while the system is in the sleep state represented 615d08ca2caSLen Brown * by %acpi_target_sleep_state. If @wake is nonzero, the device should be 616d08ca2caSLen Brown * able to wake up the system from this sleep state. If @d_min_p is set, 617d08ca2caSLen Brown * the highest power (lowest number) device power state of @dev allowed 618d08ca2caSLen Brown * in this system sleep state is stored at the location pointed to by it. 619d08ca2caSLen Brown * 620d08ca2caSLen Brown * The caller must ensure that @dev is valid before using this function. 621d08ca2caSLen Brown * The caller is also responsible for figuring out if the device is 622d08ca2caSLen Brown * supposed to be able to wake up the system and passing this information 623d08ca2caSLen Brown * via @wake. 624d08ca2caSLen Brown */ 625d08ca2caSLen Brown 626d08ca2caSLen Brown int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) 627d08ca2caSLen Brown { 628d08ca2caSLen Brown acpi_handle handle = DEVICE_ACPI_HANDLE(dev); 629d08ca2caSLen Brown struct acpi_device *adev; 630d08ca2caSLen Brown char acpi_method[] = "_SxD"; 631d08ca2caSLen Brown unsigned long long d_min, d_max; 632d08ca2caSLen Brown 633d08ca2caSLen Brown if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { 634d08ca2caSLen Brown printk(KERN_DEBUG "ACPI handle has no context!\n"); 635d08ca2caSLen Brown return -ENODEV; 636d08ca2caSLen Brown } 637d08ca2caSLen Brown 638d08ca2caSLen Brown acpi_method[2] = '0' + acpi_target_sleep_state; 639d08ca2caSLen Brown /* 640d08ca2caSLen Brown * If the sleep state is S0, we will return D3, but if the device has 641d08ca2caSLen Brown * _S0W, we will use the value from _S0W 642d08ca2caSLen Brown */ 643d08ca2caSLen Brown d_min = ACPI_STATE_D0; 644d08ca2caSLen Brown d_max = ACPI_STATE_D3; 645d08ca2caSLen Brown 646d08ca2caSLen Brown /* 647d08ca2caSLen Brown * If present, _SxD methods return the minimum D-state (highest power 648d08ca2caSLen Brown * state) we can use for the corresponding S-states. Otherwise, the 649d08ca2caSLen Brown * minimum D-state is D0 (ACPI 3.x). 650d08ca2caSLen Brown * 651d08ca2caSLen Brown * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer 652d08ca2caSLen Brown * provided -- that's our fault recovery, we ignore retval. 653d08ca2caSLen Brown */ 654d08ca2caSLen Brown if (acpi_target_sleep_state > ACPI_STATE_S0) 655d08ca2caSLen Brown acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); 656d08ca2caSLen Brown 657d08ca2caSLen Brown /* 658d08ca2caSLen Brown * If _PRW says we can wake up the system from the target sleep state, 659d08ca2caSLen Brown * the D-state returned by _SxD is sufficient for that (we assume a 660d08ca2caSLen Brown * wakeup-aware driver if wake is set). Still, if _SxW exists 661d08ca2caSLen Brown * (ACPI 3.x), it should return the maximum (lowest power) D-state that 662d08ca2caSLen Brown * can wake the system. _S0W may be valid, too. 663d08ca2caSLen Brown */ 664d08ca2caSLen Brown if (acpi_target_sleep_state == ACPI_STATE_S0 || 665761afb86SRafael J. Wysocki (device_may_wakeup(dev) && 666d08ca2caSLen Brown adev->wakeup.sleep_state <= acpi_target_sleep_state)) { 667d08ca2caSLen Brown acpi_status status; 668d08ca2caSLen Brown 669d08ca2caSLen Brown acpi_method[3] = 'W'; 670d08ca2caSLen Brown status = acpi_evaluate_integer(handle, acpi_method, NULL, 671d08ca2caSLen Brown &d_max); 672d08ca2caSLen Brown if (ACPI_FAILURE(status)) { 673761afb86SRafael J. Wysocki if (acpi_target_sleep_state != ACPI_STATE_S0 || 674761afb86SRafael J. Wysocki status != AE_NOT_FOUND) 675d08ca2caSLen Brown d_max = d_min; 676d08ca2caSLen Brown } else if (d_max < d_min) { 677d08ca2caSLen Brown /* Warn the user of the broken DSDT */ 678d08ca2caSLen Brown printk(KERN_WARNING "ACPI: Wrong value from %s\n", 679d08ca2caSLen Brown acpi_method); 680d08ca2caSLen Brown /* Sanitize it */ 681d08ca2caSLen Brown d_min = d_max; 682d08ca2caSLen Brown } 683d08ca2caSLen Brown } 684d08ca2caSLen Brown 685d08ca2caSLen Brown if (d_min_p) 686d08ca2caSLen Brown *d_min_p = d_min; 687d08ca2caSLen Brown return d_max; 688d08ca2caSLen Brown } 689aa338601SRafael J. Wysocki #endif /* CONFIG_PM */ 690d08ca2caSLen Brown 691761afb86SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 692d08ca2caSLen Brown /** 693d08ca2caSLen Brown * acpi_pm_device_sleep_wake - enable or disable the system wake-up 694d08ca2caSLen Brown * capability of given device 695d08ca2caSLen Brown * @dev: device to handle 696d08ca2caSLen Brown * @enable: 'true' - enable, 'false' - disable the wake-up capability 697d08ca2caSLen Brown */ 698d08ca2caSLen Brown int acpi_pm_device_sleep_wake(struct device *dev, bool enable) 699d08ca2caSLen Brown { 700d08ca2caSLen Brown acpi_handle handle; 701d08ca2caSLen Brown struct acpi_device *adev; 702df8db91fSRafael J. Wysocki int error; 703d08ca2caSLen Brown 7040baed8daSRafael J. Wysocki if (!device_can_wakeup(dev)) 705d08ca2caSLen Brown return -EINVAL; 706d08ca2caSLen Brown 707d08ca2caSLen Brown handle = DEVICE_ACPI_HANDLE(dev); 708d08ca2caSLen Brown if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { 709df8db91fSRafael J. Wysocki dev_dbg(dev, "ACPI handle has no context in %s!\n", __func__); 710d08ca2caSLen Brown return -ENODEV; 711d08ca2caSLen Brown } 712d08ca2caSLen Brown 713e8b6f970SRafael J. Wysocki error = enable ? 714e8b6f970SRafael J. Wysocki acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : 715e8b6f970SRafael J. Wysocki acpi_disable_wakeup_device_power(adev); 716df8db91fSRafael J. Wysocki if (!error) 717df8db91fSRafael J. Wysocki dev_info(dev, "wake-up capability %s by ACPI\n", 718df8db91fSRafael J. Wysocki enable ? "enabled" : "disabled"); 719df8db91fSRafael J. Wysocki 720df8db91fSRafael J. Wysocki return error; 721d08ca2caSLen Brown } 722761afb86SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 723d08ca2caSLen Brown 724d08ca2caSLen Brown static void acpi_power_off_prepare(void) 725d08ca2caSLen Brown { 726d08ca2caSLen Brown /* Prepare to power off the system */ 727d08ca2caSLen Brown acpi_sleep_prepare(ACPI_STATE_S5); 728d08ca2caSLen Brown acpi_disable_all_gpes(); 729d08ca2caSLen Brown } 730d08ca2caSLen Brown 731d08ca2caSLen Brown static void acpi_power_off(void) 732d08ca2caSLen Brown { 733d08ca2caSLen Brown /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ 7344d939155SFrank Seidel printk(KERN_DEBUG "%s called\n", __func__); 735d08ca2caSLen Brown local_irq_disable(); 736d08ca2caSLen Brown acpi_enter_sleep_state(ACPI_STATE_S5); 737d08ca2caSLen Brown } 738d08ca2caSLen Brown 73996f15efcSLen Brown /* 74096f15efcSLen Brown * ACPI 2.0 created the optional _GTS and _BFS, 74196f15efcSLen Brown * but industry adoption has been neither rapid nor broad. 74296f15efcSLen Brown * 74396f15efcSLen Brown * Linux gets into trouble when it executes poorly validated 74496f15efcSLen Brown * paths through the BIOS, so disable _GTS and _BFS by default, 74596f15efcSLen Brown * but do speak up and offer the option to enable them. 74696f15efcSLen Brown */ 74701eac60bSStephen Hemminger static void __init acpi_gts_bfs_check(void) 74896f15efcSLen Brown { 74996f15efcSLen Brown acpi_handle dummy; 75096f15efcSLen Brown 75196f15efcSLen Brown if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__GTS, &dummy))) 75296f15efcSLen Brown { 75396f15efcSLen Brown printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n"); 75496f15efcSLen Brown printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, " 75596f15efcSLen Brown "please notify linux-acpi@vger.kernel.org\n"); 75696f15efcSLen Brown } 75796f15efcSLen Brown if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_NAME__BFS, &dummy))) 75896f15efcSLen Brown { 75996f15efcSLen Brown printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n"); 76096f15efcSLen Brown printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, " 76196f15efcSLen Brown "please notify linux-acpi@vger.kernel.org\n"); 76296f15efcSLen Brown } 76396f15efcSLen Brown } 76496f15efcSLen Brown 765d08ca2caSLen Brown int __init acpi_sleep_init(void) 766d08ca2caSLen Brown { 767d08ca2caSLen Brown acpi_status status; 768d08ca2caSLen Brown u8 type_a, type_b; 769d08ca2caSLen Brown #ifdef CONFIG_SUSPEND 770d08ca2caSLen Brown int i = 0; 771d08ca2caSLen Brown 772d08ca2caSLen Brown dmi_check_system(acpisleep_dmi_table); 773d08ca2caSLen Brown #endif 774d08ca2caSLen Brown 775d08ca2caSLen Brown if (acpi_disabled) 776d08ca2caSLen Brown return 0; 777d08ca2caSLen Brown 778d08ca2caSLen Brown sleep_states[ACPI_STATE_S0] = 1; 779d08ca2caSLen Brown printk(KERN_INFO PREFIX "(supports S0"); 780d08ca2caSLen Brown 781d08ca2caSLen Brown #ifdef CONFIG_SUSPEND 782d08ca2caSLen Brown for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) { 783d08ca2caSLen Brown status = acpi_get_sleep_type_data(i, &type_a, &type_b); 784d08ca2caSLen Brown if (ACPI_SUCCESS(status)) { 785d08ca2caSLen Brown sleep_states[i] = 1; 786d08ca2caSLen Brown printk(" S%d", i); 787d08ca2caSLen Brown } 788d08ca2caSLen Brown } 789d08ca2caSLen Brown 790d08ca2caSLen Brown suspend_set_ops(old_suspend_ordering ? 791d08ca2caSLen Brown &acpi_suspend_ops_old : &acpi_suspend_ops); 792d08ca2caSLen Brown #endif 793d08ca2caSLen Brown 794d08ca2caSLen Brown #ifdef CONFIG_HIBERNATION 795d08ca2caSLen Brown status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b); 796d08ca2caSLen Brown if (ACPI_SUCCESS(status)) { 797d08ca2caSLen Brown hibernation_set_ops(old_suspend_ordering ? 798d08ca2caSLen Brown &acpi_hibernation_ops_old : &acpi_hibernation_ops); 799d08ca2caSLen Brown sleep_states[ACPI_STATE_S4] = 1; 800d08ca2caSLen Brown printk(" S4"); 801d08ca2caSLen Brown if (!nosigcheck) { 802d08ca2caSLen Brown acpi_get_table(ACPI_SIG_FACS, 1, 803d08ca2caSLen Brown (struct acpi_table_header **)&facs); 804d08ca2caSLen Brown if (facs) 805d08ca2caSLen Brown s4_hardware_signature = 806d08ca2caSLen Brown facs->hardware_signature; 807d08ca2caSLen Brown } 808d08ca2caSLen Brown } 809d08ca2caSLen Brown #endif 810d08ca2caSLen Brown status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); 811d08ca2caSLen Brown if (ACPI_SUCCESS(status)) { 812d08ca2caSLen Brown sleep_states[ACPI_STATE_S5] = 1; 813d08ca2caSLen Brown printk(" S5"); 814d08ca2caSLen Brown pm_power_off_prepare = acpi_power_off_prepare; 815d08ca2caSLen Brown pm_power_off = acpi_power_off; 816d08ca2caSLen Brown } 817d08ca2caSLen Brown printk(")\n"); 818d08ca2caSLen Brown /* 819d08ca2caSLen Brown * Register the tts_notifier to reboot notifier list so that the _TTS 820d08ca2caSLen Brown * object can also be evaluated when the system enters S5. 821d08ca2caSLen Brown */ 822d08ca2caSLen Brown register_reboot_notifier(&tts_notifier); 82396f15efcSLen Brown acpi_gts_bfs_check(); 824d08ca2caSLen Brown return 0; 825d08ca2caSLen Brown } 826