diff options
Diffstat (limited to 'drivers/acpi/sleep/main.c')
-rw-r--r-- | drivers/acpi/sleep/main.c | 66 |
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 | ||
25 | u8 sleep_states[ACPI_S_STATE_COUNT]; | 26 | u8 sleep_states[ACPI_S_STATE_COUNT]; |
26 | 27 | ||
28 | static 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 | |||
45 | static 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 | |||
52 | static struct notifier_block tts_notifier = { | ||
53 | .notifier_call = tts_notify_reboot, | ||
54 | .next = NULL, | ||
55 | .priority = 0, | ||
56 | }; | ||
57 | |||
27 | static int acpi_sleep_prepare(u32 acpi_state) | 58 | static 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 |
49 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | 80 | static 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 |
138 | extern void do_suspend_lowlevel(void); | 169 | extern 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) | |||
313 | static int acpi_hibernation_begin(void) | 355 | static 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 | */ |
377 | static int acpi_hibernation_begin_old(void) | 420 | static 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 | } |