diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/sleep/main.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 198ff8a1529a..c37c4ead95c9 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -26,6 +26,21 @@ u8 sleep_states[ACPI_S_STATE_COUNT]; | |||
26 | 26 | ||
27 | #ifdef CONFIG_PM_SLEEP | 27 | #ifdef CONFIG_PM_SLEEP |
28 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; | 28 | static u32 acpi_target_sleep_state = ACPI_STATE_S0; |
29 | static bool acpi_sleep_finish_wake_up; | ||
30 | |||
31 | /* | ||
32 | * ACPI 2.0 and later want us to execute _PTS after suspending devices, so we | ||
33 | * allow the user to request that behavior by using the 'acpi_new_pts_ordering' | ||
34 | * kernel command line option that causes the following variable to be set. | ||
35 | */ | ||
36 | static bool new_pts_ordering; | ||
37 | |||
38 | static int __init acpi_new_pts_ordering(char *str) | ||
39 | { | ||
40 | new_pts_ordering = true; | ||
41 | return 1; | ||
42 | } | ||
43 | __setup("acpi_new_pts_ordering", acpi_new_pts_ordering); | ||
29 | #endif | 44 | #endif |
30 | 45 | ||
31 | int acpi_sleep_prepare(u32 acpi_state) | 46 | int acpi_sleep_prepare(u32 acpi_state) |
@@ -74,6 +89,14 @@ static int acpi_pm_begin(suspend_state_t pm_state) | |||
74 | 89 | ||
75 | if (sleep_states[acpi_state]) { | 90 | if (sleep_states[acpi_state]) { |
76 | acpi_target_sleep_state = acpi_state; | 91 | acpi_target_sleep_state = acpi_state; |
92 | if (new_pts_ordering) | ||
93 | return 0; | ||
94 | |||
95 | error = acpi_sleep_prepare(acpi_state); | ||
96 | if (error) | ||
97 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
98 | else | ||
99 | acpi_sleep_finish_wake_up = true; | ||
77 | } else { | 100 | } else { |
78 | printk(KERN_ERR "ACPI does not support this state: %d\n", | 101 | printk(KERN_ERR "ACPI does not support this state: %d\n", |
79 | pm_state); | 102 | pm_state); |
@@ -91,15 +114,17 @@ static int acpi_pm_begin(suspend_state_t pm_state) | |||
91 | 114 | ||
92 | static int acpi_pm_prepare(void) | 115 | static int acpi_pm_prepare(void) |
93 | { | 116 | { |
94 | int error; | 117 | if (new_pts_ordering) { |
118 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | ||
95 | 119 | ||
96 | error = acpi_sleep_prepare(acpi_target_sleep_state); | 120 | if (error) { |
97 | if (error) | 121 | acpi_target_sleep_state = ACPI_STATE_S0; |
98 | acpi_target_sleep_state = ACPI_STATE_S0; | 122 | return error; |
99 | else if (!ACPI_SUCCESS(acpi_hw_disable_all_gpes())) | 123 | } |
100 | error = -EFAULT; | 124 | acpi_sleep_finish_wake_up = true; |
125 | } | ||
101 | 126 | ||
102 | return error; | 127 | return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; |
103 | } | 128 | } |
104 | 129 | ||
105 | /** | 130 | /** |
@@ -123,10 +148,8 @@ static int acpi_pm_enter(suspend_state_t pm_state) | |||
123 | if (acpi_state == ACPI_STATE_S3) { | 148 | if (acpi_state == ACPI_STATE_S3) { |
124 | int error = acpi_save_state_mem(); | 149 | int error = acpi_save_state_mem(); |
125 | 150 | ||
126 | if (error) { | 151 | if (error) |
127 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
128 | return error; | 152 | return error; |
129 | } | ||
130 | } | 153 | } |
131 | 154 | ||
132 | local_irq_save(flags); | 155 | local_irq_save(flags); |
@@ -187,6 +210,7 @@ static void acpi_pm_finish(void) | |||
187 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 210 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
188 | 211 | ||
189 | acpi_target_sleep_state = ACPI_STATE_S0; | 212 | acpi_target_sleep_state = ACPI_STATE_S0; |
213 | acpi_sleep_finish_wake_up = false; | ||
190 | 214 | ||
191 | #ifdef CONFIG_X86 | 215 | #ifdef CONFIG_X86 |
192 | if (init_8259A_after_S1) { | 216 | if (init_8259A_after_S1) { |
@@ -203,10 +227,11 @@ static void acpi_pm_finish(void) | |||
203 | static void acpi_pm_end(void) | 227 | static void acpi_pm_end(void) |
204 | { | 228 | { |
205 | /* | 229 | /* |
206 | * This is necessary in case acpi_pm_finish() is not called during a | 230 | * This is necessary in case acpi_pm_finish() is not called directly |
207 | * failing transition to a sleep state. | 231 | * during a failing transition to a sleep state. |
208 | */ | 232 | */ |
209 | acpi_target_sleep_state = ACPI_STATE_S0; | 233 | if (acpi_sleep_finish_wake_up) |
234 | acpi_pm_finish(); | ||
210 | } | 235 | } |
211 | 236 | ||
212 | static int acpi_pm_state_valid(suspend_state_t pm_state) | 237 | static int acpi_pm_state_valid(suspend_state_t pm_state) |