diff options
Diffstat (limited to 'drivers/acpi/sleep')
-rw-r--r-- | drivers/acpi/sleep/main.c | 144 | ||||
-rw-r--r-- | drivers/acpi/sleep/proc.c | 46 | ||||
-rw-r--r-- | drivers/acpi/sleep/sleep.h | 2 |
3 files changed, 135 insertions, 57 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 2c0b6630f8ba..7f97e32fc33f 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -26,9 +26,24 @@ 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 | static int acpi_sleep_prepare(u32 acpi_state) |
32 | { | 47 | { |
33 | #ifdef CONFIG_ACPI_SLEEP | 48 | #ifdef CONFIG_ACPI_SLEEP |
34 | /* do we have a wakeup address for S2 and S3? */ | 49 | /* do we have a wakeup address for S2 and S3? */ |
@@ -44,6 +59,8 @@ int acpi_sleep_prepare(u32 acpi_state) | |||
44 | ACPI_FLUSH_CPU_CACHE(); | 59 | ACPI_FLUSH_CPU_CACHE(); |
45 | acpi_enable_wakeup_device_prep(acpi_state); | 60 | acpi_enable_wakeup_device_prep(acpi_state); |
46 | #endif | 61 | #endif |
62 | printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", | ||
63 | acpi_state); | ||
47 | acpi_enter_sleep_state_prep(acpi_state); | 64 | acpi_enter_sleep_state_prep(acpi_state); |
48 | return 0; | 65 | return 0; |
49 | } | 66 | } |
@@ -63,17 +80,25 @@ static u32 acpi_suspend_states[] = { | |||
63 | static int init_8259A_after_S1; | 80 | static int init_8259A_after_S1; |
64 | 81 | ||
65 | /** | 82 | /** |
66 | * acpi_pm_set_target - Set the target system sleep state to the state | 83 | * acpi_pm_begin - Set the target system sleep state to the state |
67 | * associated with given @pm_state, if supported. | 84 | * associated with given @pm_state, if supported. |
68 | */ | 85 | */ |
69 | 86 | ||
70 | static int acpi_pm_set_target(suspend_state_t pm_state) | 87 | static int acpi_pm_begin(suspend_state_t pm_state) |
71 | { | 88 | { |
72 | u32 acpi_state = acpi_suspend_states[pm_state]; | 89 | u32 acpi_state = acpi_suspend_states[pm_state]; |
73 | int error = 0; | 90 | int error = 0; |
74 | 91 | ||
75 | if (sleep_states[acpi_state]) { | 92 | if (sleep_states[acpi_state]) { |
76 | acpi_target_sleep_state = acpi_state; | 93 | acpi_target_sleep_state = acpi_state; |
94 | if (new_pts_ordering) | ||
95 | return 0; | ||
96 | |||
97 | error = acpi_sleep_prepare(acpi_state); | ||
98 | if (error) | ||
99 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
100 | else | ||
101 | acpi_sleep_finish_wake_up = true; | ||
77 | } else { | 102 | } else { |
78 | printk(KERN_ERR "ACPI does not support this state: %d\n", | 103 | printk(KERN_ERR "ACPI does not support this state: %d\n", |
79 | pm_state); | 104 | pm_state); |
@@ -91,12 +116,17 @@ static int acpi_pm_set_target(suspend_state_t pm_state) | |||
91 | 116 | ||
92 | static int acpi_pm_prepare(void) | 117 | static int acpi_pm_prepare(void) |
93 | { | 118 | { |
94 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | 119 | if (new_pts_ordering) { |
120 | int error = acpi_sleep_prepare(acpi_target_sleep_state); | ||
95 | 121 | ||
96 | if (error) | 122 | if (error) { |
97 | acpi_target_sleep_state = ACPI_STATE_S0; | 123 | acpi_target_sleep_state = ACPI_STATE_S0; |
124 | return error; | ||
125 | } | ||
126 | acpi_sleep_finish_wake_up = true; | ||
127 | } | ||
98 | 128 | ||
99 | return error; | 129 | return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; |
100 | } | 130 | } |
101 | 131 | ||
102 | /** | 132 | /** |
@@ -120,10 +150,8 @@ static int acpi_pm_enter(suspend_state_t pm_state) | |||
120 | if (acpi_state == ACPI_STATE_S3) { | 150 | if (acpi_state == ACPI_STATE_S3) { |
121 | int error = acpi_save_state_mem(); | 151 | int error = acpi_save_state_mem(); |
122 | 152 | ||
123 | if (error) { | 153 | if (error) |
124 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
125 | return error; | 154 | return error; |
126 | } | ||
127 | } | 155 | } |
128 | 156 | ||
129 | local_irq_save(flags); | 157 | local_irq_save(flags); |
@@ -139,6 +167,9 @@ static int acpi_pm_enter(suspend_state_t pm_state) | |||
139 | break; | 167 | break; |
140 | } | 168 | } |
141 | 169 | ||
170 | /* Reprogram control registers and execute _BFS */ | ||
171 | acpi_leave_sleep_state_prep(acpi_state); | ||
172 | |||
142 | /* ACPI 3.0 specs (P62) says that it's the responsabilty | 173 | /* ACPI 3.0 specs (P62) says that it's the responsabilty |
143 | * of the OSPM to clear the status bit [ implying that the | 174 | * of the OSPM to clear the status bit [ implying that the |
144 | * POWER_BUTTON event should not reach userspace ] | 175 | * POWER_BUTTON event should not reach userspace ] |
@@ -146,6 +177,13 @@ static int acpi_pm_enter(suspend_state_t pm_state) | |||
146 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) | 177 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) |
147 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | 178 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); |
148 | 179 | ||
180 | /* | ||
181 | * Disable and clear GPE status before interrupt is enabled. Some GPEs | ||
182 | * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. | ||
183 | * acpi_leave_sleep_state will reenable specific GPEs later | ||
184 | */ | ||
185 | acpi_hw_disable_all_gpes(); | ||
186 | |||
149 | local_irq_restore(flags); | 187 | local_irq_restore(flags); |
150 | printk(KERN_DEBUG "Back to C!\n"); | 188 | printk(KERN_DEBUG "Back to C!\n"); |
151 | 189 | ||
@@ -157,7 +195,7 @@ static int acpi_pm_enter(suspend_state_t pm_state) | |||
157 | } | 195 | } |
158 | 196 | ||
159 | /** | 197 | /** |
160 | * acpi_pm_finish - Finish up suspend sequence. | 198 | * acpi_pm_finish - Instruct the platform to leave a sleep state. |
161 | * | 199 | * |
162 | * This is called after we wake back up (or if entering the sleep state | 200 | * This is called after we wake back up (or if entering the sleep state |
163 | * failed). | 201 | * failed). |
@@ -174,6 +212,7 @@ static void acpi_pm_finish(void) | |||
174 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 212 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
175 | 213 | ||
176 | acpi_target_sleep_state = ACPI_STATE_S0; | 214 | acpi_target_sleep_state = ACPI_STATE_S0; |
215 | acpi_sleep_finish_wake_up = false; | ||
177 | 216 | ||
178 | #ifdef CONFIG_X86 | 217 | #ifdef CONFIG_X86 |
179 | if (init_8259A_after_S1) { | 218 | if (init_8259A_after_S1) { |
@@ -183,6 +222,20 @@ static void acpi_pm_finish(void) | |||
183 | #endif | 222 | #endif |
184 | } | 223 | } |
185 | 224 | ||
225 | /** | ||
226 | * acpi_pm_end - Finish up suspend sequence. | ||
227 | */ | ||
228 | |||
229 | static void acpi_pm_end(void) | ||
230 | { | ||
231 | /* | ||
232 | * This is necessary in case acpi_pm_finish() is not called directly | ||
233 | * during a failing transition to a sleep state. | ||
234 | */ | ||
235 | if (acpi_sleep_finish_wake_up) | ||
236 | acpi_pm_finish(); | ||
237 | } | ||
238 | |||
186 | static int acpi_pm_state_valid(suspend_state_t pm_state) | 239 | static int acpi_pm_state_valid(suspend_state_t pm_state) |
187 | { | 240 | { |
188 | u32 acpi_state; | 241 | u32 acpi_state; |
@@ -201,10 +254,11 @@ static int acpi_pm_state_valid(suspend_state_t pm_state) | |||
201 | 254 | ||
202 | static struct platform_suspend_ops acpi_pm_ops = { | 255 | static struct platform_suspend_ops acpi_pm_ops = { |
203 | .valid = acpi_pm_state_valid, | 256 | .valid = acpi_pm_state_valid, |
204 | .set_target = acpi_pm_set_target, | 257 | .begin = acpi_pm_begin, |
205 | .prepare = acpi_pm_prepare, | 258 | .prepare = acpi_pm_prepare, |
206 | .enter = acpi_pm_enter, | 259 | .enter = acpi_pm_enter, |
207 | .finish = acpi_pm_finish, | 260 | .finish = acpi_pm_finish, |
261 | .end = acpi_pm_end, | ||
208 | }; | 262 | }; |
209 | 263 | ||
210 | /* | 264 | /* |
@@ -229,15 +283,36 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { | |||
229 | #endif /* CONFIG_SUSPEND */ | 283 | #endif /* CONFIG_SUSPEND */ |
230 | 284 | ||
231 | #ifdef CONFIG_HIBERNATION | 285 | #ifdef CONFIG_HIBERNATION |
232 | static int acpi_hibernation_start(void) | 286 | static int acpi_hibernation_begin(void) |
233 | { | 287 | { |
288 | int error; | ||
289 | |||
234 | acpi_target_sleep_state = ACPI_STATE_S4; | 290 | acpi_target_sleep_state = ACPI_STATE_S4; |
235 | return 0; | 291 | if (new_pts_ordering) |
292 | return 0; | ||
293 | |||
294 | error = acpi_sleep_prepare(ACPI_STATE_S4); | ||
295 | if (error) | ||
296 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
297 | else | ||
298 | acpi_sleep_finish_wake_up = true; | ||
299 | |||
300 | return error; | ||
236 | } | 301 | } |
237 | 302 | ||
238 | static int acpi_hibernation_prepare(void) | 303 | static int acpi_hibernation_prepare(void) |
239 | { | 304 | { |
240 | return acpi_sleep_prepare(ACPI_STATE_S4); | 305 | if (new_pts_ordering) { |
306 | int error = acpi_sleep_prepare(ACPI_STATE_S4); | ||
307 | |||
308 | if (error) { | ||
309 | acpi_target_sleep_state = ACPI_STATE_S0; | ||
310 | return error; | ||
311 | } | ||
312 | acpi_sleep_finish_wake_up = true; | ||
313 | } | ||
314 | |||
315 | return ACPI_SUCCESS(acpi_hw_disable_all_gpes()) ? 0 : -EFAULT; | ||
241 | } | 316 | } |
242 | 317 | ||
243 | static int acpi_hibernation_enter(void) | 318 | static int acpi_hibernation_enter(void) |
@@ -251,6 +326,8 @@ static int acpi_hibernation_enter(void) | |||
251 | acpi_enable_wakeup_device(ACPI_STATE_S4); | 326 | acpi_enable_wakeup_device(ACPI_STATE_S4); |
252 | /* This shouldn't return. If it returns, we have a problem */ | 327 | /* This shouldn't return. If it returns, we have a problem */ |
253 | status = acpi_enter_sleep_state(ACPI_STATE_S4); | 328 | status = acpi_enter_sleep_state(ACPI_STATE_S4); |
329 | /* Reprogram control registers and execute _BFS */ | ||
330 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | ||
254 | local_irq_restore(flags); | 331 | local_irq_restore(flags); |
255 | 332 | ||
256 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; | 333 | return ACPI_SUCCESS(status) ? 0 : -EFAULT; |
@@ -263,15 +340,12 @@ static void acpi_hibernation_leave(void) | |||
263 | * enable it here. | 340 | * enable it here. |
264 | */ | 341 | */ |
265 | acpi_enable(); | 342 | acpi_enable(); |
343 | /* Reprogram control registers and execute _BFS */ | ||
344 | acpi_leave_sleep_state_prep(ACPI_STATE_S4); | ||
266 | } | 345 | } |
267 | 346 | ||
268 | static void acpi_hibernation_finish(void) | 347 | static void acpi_hibernation_finish(void) |
269 | { | 348 | { |
270 | /* | ||
271 | * If ACPI is not enabled by the BIOS and the boot kernel, we need to | ||
272 | * enable it here. | ||
273 | */ | ||
274 | acpi_enable(); | ||
275 | acpi_disable_wakeup_device(ACPI_STATE_S4); | 349 | acpi_disable_wakeup_device(ACPI_STATE_S4); |
276 | acpi_leave_sleep_state(ACPI_STATE_S4); | 350 | acpi_leave_sleep_state(ACPI_STATE_S4); |
277 | 351 | ||
@@ -279,6 +353,17 @@ static void acpi_hibernation_finish(void) | |||
279 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 353 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
280 | 354 | ||
281 | acpi_target_sleep_state = ACPI_STATE_S0; | 355 | acpi_target_sleep_state = ACPI_STATE_S0; |
356 | acpi_sleep_finish_wake_up = false; | ||
357 | } | ||
358 | |||
359 | static void acpi_hibernation_end(void) | ||
360 | { | ||
361 | /* | ||
362 | * This is necessary in case acpi_hibernation_finish() is not called | ||
363 | * directly during a failing transition to the sleep state. | ||
364 | */ | ||
365 | if (acpi_sleep_finish_wake_up) | ||
366 | acpi_hibernation_finish(); | ||
282 | } | 367 | } |
283 | 368 | ||
284 | static int acpi_hibernation_pre_restore(void) | 369 | static int acpi_hibernation_pre_restore(void) |
@@ -296,7 +381,8 @@ static void acpi_hibernation_restore_cleanup(void) | |||
296 | } | 381 | } |
297 | 382 | ||
298 | static struct platform_hibernation_ops acpi_hibernation_ops = { | 383 | static struct platform_hibernation_ops acpi_hibernation_ops = { |
299 | .start = acpi_hibernation_start, | 384 | .begin = acpi_hibernation_begin, |
385 | .end = acpi_hibernation_end, | ||
300 | .pre_snapshot = acpi_hibernation_prepare, | 386 | .pre_snapshot = acpi_hibernation_prepare, |
301 | .finish = acpi_hibernation_finish, | 387 | .finish = acpi_hibernation_finish, |
302 | .prepare = acpi_hibernation_prepare, | 388 | .prepare = acpi_hibernation_prepare, |
@@ -386,11 +472,20 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p) | |||
386 | if (acpi_target_sleep_state == ACPI_STATE_S0 || | 472 | if (acpi_target_sleep_state == ACPI_STATE_S0 || |
387 | (wake && adev->wakeup.state.enabled && | 473 | (wake && adev->wakeup.state.enabled && |
388 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { | 474 | adev->wakeup.sleep_state <= acpi_target_sleep_state)) { |
475 | acpi_status status; | ||
476 | |||
389 | acpi_method[3] = 'W'; | 477 | acpi_method[3] = 'W'; |
390 | acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); | 478 | status = acpi_evaluate_integer(handle, acpi_method, NULL, |
391 | /* Sanity check */ | 479 | &d_max); |
392 | if (d_max < d_min) | 480 | if (ACPI_FAILURE(status)) { |
481 | d_max = d_min; | ||
482 | } else if (d_max < d_min) { | ||
483 | /* Warn the user of the broken DSDT */ | ||
484 | printk(KERN_WARNING "ACPI: Wrong value from %s\n", | ||
485 | acpi_method); | ||
486 | /* Sanitize it */ | ||
393 | d_min = d_max; | 487 | d_min = d_max; |
488 | } | ||
394 | } | 489 | } |
395 | 490 | ||
396 | if (d_min_p) | 491 | if (d_min_p) |
@@ -403,6 +498,7 @@ static void acpi_power_off_prepare(void) | |||
403 | { | 498 | { |
404 | /* Prepare to power off the system */ | 499 | /* Prepare to power off the system */ |
405 | acpi_sleep_prepare(ACPI_STATE_S5); | 500 | acpi_sleep_prepare(ACPI_STATE_S5); |
501 | acpi_hw_disable_all_gpes(); | ||
406 | } | 502 | } |
407 | 503 | ||
408 | static void acpi_power_off(void) | 504 | static void acpi_power_off(void) |
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 1538355c266b..f8df5217d477 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c | |||
@@ -178,6 +178,9 @@ static int get_date_field(char **p, u32 * value) | |||
178 | * Try to find delimeter, only to insert null. The end of the | 178 | * Try to find delimeter, only to insert null. The end of the |
179 | * string won't have one, but is still valid. | 179 | * string won't have one, but is still valid. |
180 | */ | 180 | */ |
181 | if (*p == NULL) | ||
182 | return result; | ||
183 | |||
181 | next = strpbrk(*p, "- :"); | 184 | next = strpbrk(*p, "- :"); |
182 | if (next) | 185 | if (next) |
183 | *next++ = '\0'; | 186 | *next++ = '\0'; |
@@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value) | |||
190 | 193 | ||
191 | if (next) | 194 | if (next) |
192 | *p = next; | 195 | *p = next; |
196 | else | ||
197 | *p = NULL; | ||
193 | 198 | ||
194 | return result; | 199 | return result; |
195 | } | 200 | } |
@@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file, | |||
251 | if ((result = get_date_field(&p, &sec))) | 256 | if ((result = get_date_field(&p, &sec))) |
252 | goto end; | 257 | goto end; |
253 | 258 | ||
254 | if (sec > 59) { | ||
255 | min += 1; | ||
256 | sec -= 60; | ||
257 | } | ||
258 | if (min > 59) { | ||
259 | hr += 1; | ||
260 | min -= 60; | ||
261 | } | ||
262 | if (hr > 23) { | ||
263 | day += 1; | ||
264 | hr -= 24; | ||
265 | } | ||
266 | if (day > 31) { | ||
267 | mo += 1; | ||
268 | day -= 31; | ||
269 | } | ||
270 | if (mo > 12) { | ||
271 | yr += 1; | ||
272 | mo -= 12; | ||
273 | } | ||
274 | |||
275 | spin_lock_irq(&rtc_lock); | 259 | spin_lock_irq(&rtc_lock); |
276 | 260 | ||
277 | rtc_control = CMOS_READ(RTC_CONTROL); | 261 | rtc_control = CMOS_READ(RTC_CONTROL); |
@@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file, | |||
288 | spin_unlock_irq(&rtc_lock); | 272 | spin_unlock_irq(&rtc_lock); |
289 | 273 | ||
290 | if (sec > 59) { | 274 | if (sec > 59) { |
291 | min++; | 275 | min += sec/60; |
292 | sec -= 60; | 276 | sec = sec%60; |
293 | } | 277 | } |
294 | if (min > 59) { | 278 | if (min > 59) { |
295 | hr++; | 279 | hr += min/60; |
296 | min -= 60; | 280 | min = min%60; |
297 | } | 281 | } |
298 | if (hr > 23) { | 282 | if (hr > 23) { |
299 | day++; | 283 | day += hr/24; |
300 | hr -= 24; | 284 | hr = hr%24; |
301 | } | 285 | } |
302 | if (day > 31) { | 286 | if (day > 31) { |
303 | mo++; | 287 | mo += day/32; |
304 | day -= 31; | 288 | day = day%32; |
305 | } | 289 | } |
306 | if (mo > 12) { | 290 | if (mo > 12) { |
307 | yr++; | 291 | yr += mo/13; |
308 | mo -= 12; | 292 | mo = mo%13; |
309 | } | 293 | } |
310 | 294 | ||
311 | spin_lock_irq(&rtc_lock); | 295 | spin_lock_irq(&rtc_lock); |
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h index a2ea125ae2d0..cfaf8f5b0a14 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep/sleep.h | |||
@@ -5,5 +5,3 @@ extern int acpi_suspend (u32 state); | |||
5 | extern void acpi_enable_wakeup_device_prep(u8 sleep_state); | 5 | extern void acpi_enable_wakeup_device_prep(u8 sleep_state); |
6 | extern void acpi_enable_wakeup_device(u8 sleep_state); | 6 | extern void acpi_enable_wakeup_device(u8 sleep_state); |
7 | extern void acpi_disable_wakeup_device(u8 sleep_state); | 7 | extern void acpi_disable_wakeup_device(u8 sleep_state); |
8 | |||
9 | extern int acpi_sleep_prepare(u32 acpi_state); | ||