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 d13194a031b..26571bafb15 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 | } |
