aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/sleep/main.c')
-rw-r--r--drivers/acpi/sleep/main.c66
1 files changed, 61 insertions, 5 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index d13194a031bf..26571bafb158 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -15,6 +15,7 @@
15#include <linux/dmi.h> 15#include <linux/dmi.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/suspend.h> 17#include <linux/suspend.h>
18#include <linux/reboot.h>
18 19
19#include <asm/io.h> 20#include <asm/io.h>
20 21
@@ -24,6 +25,36 @@
24 25
25u8 sleep_states[ACPI_S_STATE_COUNT]; 26u8 sleep_states[ACPI_S_STATE_COUNT];
26 27
28static void acpi_sleep_tts_switch(u32 acpi_state)
29{
30 union acpi_object in_arg = { ACPI_TYPE_INTEGER };
31 struct acpi_object_list arg_list = { 1, &in_arg };
32 acpi_status status = AE_OK;
33
34 in_arg.integer.value = acpi_state;
35 status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
36 if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
37 /*
38 * OS can't evaluate the _TTS object correctly. Some warning
39 * message will be printed. But it won't break anything.
40 */
41 printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
42 }
43}
44
45static int tts_notify_reboot(struct notifier_block *this,
46 unsigned long code, void *x)
47{
48 acpi_sleep_tts_switch(ACPI_STATE_S5);
49 return NOTIFY_DONE;
50}
51
52static struct notifier_block tts_notifier = {
53 .notifier_call = tts_notify_reboot,
54 .next = NULL,
55 .priority = 0,
56};
57
27static int acpi_sleep_prepare(u32 acpi_state) 58static int acpi_sleep_prepare(u32 acpi_state)
28{ 59{
29#ifdef CONFIG_ACPI_SLEEP 60#ifdef CONFIG_ACPI_SLEEP
@@ -45,9 +76,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
45 return 0; 76 return 0;
46} 77}
47 78
48#ifdef CONFIG_PM_SLEEP 79#ifdef CONFIG_ACPI_SLEEP
49static u32 acpi_target_sleep_state = ACPI_STATE_S0; 80static u32 acpi_target_sleep_state = ACPI_STATE_S0;
50
51/* 81/*
52 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the 82 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
53 * user to request that behavior by using the 'acpi_old_suspend_ordering' 83 * user to request that behavior by using the 'acpi_old_suspend_ordering'
@@ -131,8 +161,9 @@ static void acpi_pm_end(void)
131 * failing transition to a sleep state. 161 * failing transition to a sleep state.
132 */ 162 */
133 acpi_target_sleep_state = ACPI_STATE_S0; 163 acpi_target_sleep_state = ACPI_STATE_S0;
164 acpi_sleep_tts_switch(acpi_target_sleep_state);
134} 165}
135#endif /* CONFIG_PM_SLEEP */ 166#endif /* CONFIG_ACPI_SLEEP */
136 167
137#ifdef CONFIG_SUSPEND 168#ifdef CONFIG_SUSPEND
138extern void do_suspend_lowlevel(void); 169extern void do_suspend_lowlevel(void);
@@ -155,6 +186,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
155 186
156 if (sleep_states[acpi_state]) { 187 if (sleep_states[acpi_state]) {
157 acpi_target_sleep_state = acpi_state; 188 acpi_target_sleep_state = acpi_state;
189 acpi_sleep_tts_switch(acpi_target_sleep_state);
158 } else { 190 } else {
159 printk(KERN_ERR "ACPI does not support this state: %d\n", 191 printk(KERN_ERR "ACPI does not support this state: %d\n",
160 pm_state); 192 pm_state);
@@ -200,6 +232,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
200 break; 232 break;
201 } 233 }
202 234
235 /* If ACPI is not enabled by the BIOS, we need to enable it here. */
236 acpi_enable();
203 /* Reprogram control registers and execute _BFS */ 237 /* Reprogram control registers and execute _BFS */
204 acpi_leave_sleep_state_prep(acpi_state); 238 acpi_leave_sleep_state_prep(acpi_state);
205 239
@@ -296,6 +330,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
296 DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), 330 DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
297 }, 331 },
298 }, 332 },
333 {
334 .callback = init_old_suspend_ordering,
335 .ident = "HP xw4600 Workstation",
336 .matches = {
337 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
338 DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
339 },
340 },
299 {}, 341 {},
300}; 342};
301#endif /* CONFIG_SUSPEND */ 343#endif /* CONFIG_SUSPEND */
@@ -313,6 +355,7 @@ void __init acpi_no_s4_hw_signature(void)
313static int acpi_hibernation_begin(void) 355static int acpi_hibernation_begin(void)
314{ 356{
315 acpi_target_sleep_state = ACPI_STATE_S4; 357 acpi_target_sleep_state = ACPI_STATE_S4;
358 acpi_sleep_tts_switch(acpi_target_sleep_state);
316 return 0; 359 return 0;
317} 360}
318 361
@@ -376,7 +419,15 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
376 */ 419 */
377static int acpi_hibernation_begin_old(void) 420static int acpi_hibernation_begin_old(void)
378{ 421{
379 int error = acpi_sleep_prepare(ACPI_STATE_S4); 422 int error;
423 /*
424 * The _TTS object should always be evaluated before the _PTS object.
425 * When the old_suspended_ordering is true, the _PTS object is
426 * evaluated in the acpi_sleep_prepare.
427 */
428 acpi_sleep_tts_switch(ACPI_STATE_S4);
429
430 error = acpi_sleep_prepare(ACPI_STATE_S4);
380 431
381 if (!error) 432 if (!error)
382 acpi_target_sleep_state = ACPI_STATE_S4; 433 acpi_target_sleep_state = ACPI_STATE_S4;
@@ -444,7 +495,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
444 acpi_handle handle = DEVICE_ACPI_HANDLE(dev); 495 acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
445 struct acpi_device *adev; 496 struct acpi_device *adev;
446 char acpi_method[] = "_SxD"; 497 char acpi_method[] = "_SxD";
447 unsigned long d_min, d_max; 498 unsigned long long d_min, d_max;
448 499
449 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { 500 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
450 printk(KERN_DEBUG "ACPI handle has no context!\n"); 501 printk(KERN_DEBUG "ACPI handle has no context!\n");
@@ -596,5 +647,10 @@ int __init acpi_sleep_init(void)
596 pm_power_off = acpi_power_off; 647 pm_power_off = acpi_power_off;
597 } 648 }
598 printk(")\n"); 649 printk(")\n");
650 /*
651 * Register the tts_notifier to reboot notifier list so that the _TTS
652 * object can also be evaluated when the system enters S5.
653 */
654 register_reboot_notifier(&tts_notifier);
599 return 0; 655 return 0;
600} 656}