diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:15:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:15:51 -0400 |
commit | c7c66c0cb0c77b1a8edf09bca57d922312d58030 (patch) | |
tree | 77277103c5f16aa4dee64978a060933d92e14776 /kernel/power | |
parent | 9f3938346a5c1fa504647670edb5fea5756cfb00 (diff) | |
parent | 98e8bdafeb4728a6af7bbcbcc3984967d1cf2bc1 (diff) |
Merge tag 'pm-for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates for 3.4 from Rafael Wysocki:
"Assorted extensions and fixes including:
* Introduction of early/late suspend/hibernation device callbacks.
* Generic PM domains extensions and fixes.
* devfreq updates from Axel Lin and MyungJoo Ham.
* Device PM QoS updates.
* Fixes of concurrency problems with wakeup sources.
* System suspend and hibernation fixes."
* tag 'pm-for-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (43 commits)
PM / Domains: Check domain status during hibernation restore of devices
PM / devfreq: add relation of recommended frequency.
PM / shmobile: Make MTU2 driver use pm_genpd_dev_always_on()
PM / shmobile: Make CMT driver use pm_genpd_dev_always_on()
PM / shmobile: Make TMU driver use pm_genpd_dev_always_on()
PM / Domains: Introduce "always on" device flag
PM / Domains: Fix hibernation restore of devices, v2
PM / Domains: Fix handling of wakeup devices during system resume
sh_mmcif / PM: Use PM QoS latency constraint
tmio_mmc / PM: Use PM QoS latency constraint
PM / QoS: Make it possible to expose PM QoS latency constraints
PM / Sleep: JBD and JBD2 missing set_freezable()
PM / Domains: Fix include for PM_GENERIC_DOMAINS=n case
PM / Freezer: Remove references to TIF_FREEZE in comments
PM / Sleep: Add more wakeup source initialization routines
PM / Hibernate: Enable usermodehelpers in hibernate() error path
PM / Sleep: Make __pm_stay_awake() delete wakeup source timers
PM / Sleep: Fix race conditions related to wakeup source timer function
PM / Sleep: Fix possible infinite loop during wakeup source destruction
PM / Hibernate: print physical addresses consistently with other parts of kernel
...
Diffstat (limited to 'kernel/power')
-rw-r--r-- | kernel/power/Makefile | 3 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 47 | ||||
-rw-r--r-- | kernel/power/main.c | 20 | ||||
-rw-r--r-- | kernel/power/power.h | 7 | ||||
-rw-r--r-- | kernel/power/process.c | 24 | ||||
-rw-r--r-- | kernel/power/qos.c | 23 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 7 | ||||
-rw-r--r-- | kernel/power/suspend.c | 84 | ||||
-rw-r--r-- | kernel/power/user.c | 12 |
9 files changed, 108 insertions, 119 deletions
diff --git a/kernel/power/Makefile b/kernel/power/Makefile index 07e0e28ffba7..66d808ec5252 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile | |||
@@ -1,7 +1,8 @@ | |||
1 | 1 | ||
2 | ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG | 2 | ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG |
3 | 3 | ||
4 | obj-$(CONFIG_PM) += main.o qos.o | 4 | obj-y += qos.o |
5 | obj-$(CONFIG_PM) += main.o | ||
5 | obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o | 6 | obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o |
6 | obj-$(CONFIG_FREEZER) += process.o | 7 | obj-$(CONFIG_FREEZER) += process.o |
7 | obj-$(CONFIG_SUSPEND) += suspend.o | 8 | obj-$(CONFIG_SUSPEND) += suspend.o |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 6d6d28870335..0a186cfde788 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -245,8 +245,8 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop, | |||
245 | * create_image - Create a hibernation image. | 245 | * create_image - Create a hibernation image. |
246 | * @platform_mode: Whether or not to use the platform driver. | 246 | * @platform_mode: Whether or not to use the platform driver. |
247 | * | 247 | * |
248 | * Execute device drivers' .freeze_noirq() callbacks, create a hibernation image | 248 | * Execute device drivers' "late" and "noirq" freeze callbacks, create a |
249 | * and execute the drivers' .thaw_noirq() callbacks. | 249 | * hibernation image and run the drivers' "noirq" and "early" thaw callbacks. |
250 | * | 250 | * |
251 | * Control reappears in this routine after the subsequent restore. | 251 | * Control reappears in this routine after the subsequent restore. |
252 | */ | 252 | */ |
@@ -254,7 +254,7 @@ static int create_image(int platform_mode) | |||
254 | { | 254 | { |
255 | int error; | 255 | int error; |
256 | 256 | ||
257 | error = dpm_suspend_noirq(PMSG_FREEZE); | 257 | error = dpm_suspend_end(PMSG_FREEZE); |
258 | if (error) { | 258 | if (error) { |
259 | printk(KERN_ERR "PM: Some devices failed to power down, " | 259 | printk(KERN_ERR "PM: Some devices failed to power down, " |
260 | "aborting hibernation\n"); | 260 | "aborting hibernation\n"); |
@@ -306,7 +306,7 @@ static int create_image(int platform_mode) | |||
306 | Platform_finish: | 306 | Platform_finish: |
307 | platform_finish(platform_mode); | 307 | platform_finish(platform_mode); |
308 | 308 | ||
309 | dpm_resume_noirq(in_suspend ? | 309 | dpm_resume_start(in_suspend ? |
310 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 310 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
311 | 311 | ||
312 | return error; | 312 | return error; |
@@ -343,13 +343,13 @@ int hibernation_snapshot(int platform_mode) | |||
343 | * successful freezer test. | 343 | * successful freezer test. |
344 | */ | 344 | */ |
345 | freezer_test_done = true; | 345 | freezer_test_done = true; |
346 | goto Cleanup; | 346 | goto Thaw; |
347 | } | 347 | } |
348 | 348 | ||
349 | error = dpm_prepare(PMSG_FREEZE); | 349 | error = dpm_prepare(PMSG_FREEZE); |
350 | if (error) { | 350 | if (error) { |
351 | dpm_complete(PMSG_RECOVER); | 351 | dpm_complete(PMSG_RECOVER); |
352 | goto Cleanup; | 352 | goto Thaw; |
353 | } | 353 | } |
354 | 354 | ||
355 | suspend_console(); | 355 | suspend_console(); |
@@ -385,6 +385,8 @@ int hibernation_snapshot(int platform_mode) | |||
385 | platform_end(platform_mode); | 385 | platform_end(platform_mode); |
386 | return error; | 386 | return error; |
387 | 387 | ||
388 | Thaw: | ||
389 | thaw_kernel_threads(); | ||
388 | Cleanup: | 390 | Cleanup: |
389 | swsusp_free(); | 391 | swsusp_free(); |
390 | goto Close; | 392 | goto Close; |
@@ -394,16 +396,16 @@ int hibernation_snapshot(int platform_mode) | |||
394 | * resume_target_kernel - Restore system state from a hibernation image. | 396 | * resume_target_kernel - Restore system state from a hibernation image. |
395 | * @platform_mode: Whether or not to use the platform driver. | 397 | * @platform_mode: Whether or not to use the platform driver. |
396 | * | 398 | * |
397 | * Execute device drivers' .freeze_noirq() callbacks, restore the contents of | 399 | * Execute device drivers' "noirq" and "late" freeze callbacks, restore the |
398 | * highmem that have not been restored yet from the image and run the low-level | 400 | * contents of highmem that have not been restored yet from the image and run |
399 | * code that will restore the remaining contents of memory and switch to the | 401 | * the low-level code that will restore the remaining contents of memory and |
400 | * just restored target kernel. | 402 | * switch to the just restored target kernel. |
401 | */ | 403 | */ |
402 | static int resume_target_kernel(bool platform_mode) | 404 | static int resume_target_kernel(bool platform_mode) |
403 | { | 405 | { |
404 | int error; | 406 | int error; |
405 | 407 | ||
406 | error = dpm_suspend_noirq(PMSG_QUIESCE); | 408 | error = dpm_suspend_end(PMSG_QUIESCE); |
407 | if (error) { | 409 | if (error) { |
408 | printk(KERN_ERR "PM: Some devices failed to power down, " | 410 | printk(KERN_ERR "PM: Some devices failed to power down, " |
409 | "aborting resume\n"); | 411 | "aborting resume\n"); |
@@ -460,7 +462,7 @@ static int resume_target_kernel(bool platform_mode) | |||
460 | Cleanup: | 462 | Cleanup: |
461 | platform_restore_cleanup(platform_mode); | 463 | platform_restore_cleanup(platform_mode); |
462 | 464 | ||
463 | dpm_resume_noirq(PMSG_RECOVER); | 465 | dpm_resume_start(PMSG_RECOVER); |
464 | 466 | ||
465 | return error; | 467 | return error; |
466 | } | 468 | } |
@@ -518,7 +520,7 @@ int hibernation_platform_enter(void) | |||
518 | goto Resume_devices; | 520 | goto Resume_devices; |
519 | } | 521 | } |
520 | 522 | ||
521 | error = dpm_suspend_noirq(PMSG_HIBERNATE); | 523 | error = dpm_suspend_end(PMSG_HIBERNATE); |
522 | if (error) | 524 | if (error) |
523 | goto Resume_devices; | 525 | goto Resume_devices; |
524 | 526 | ||
@@ -549,7 +551,7 @@ int hibernation_platform_enter(void) | |||
549 | Platform_finish: | 551 | Platform_finish: |
550 | hibernation_ops->finish(); | 552 | hibernation_ops->finish(); |
551 | 553 | ||
552 | dpm_resume_noirq(PMSG_RESTORE); | 554 | dpm_resume_start(PMSG_RESTORE); |
553 | 555 | ||
554 | Resume_devices: | 556 | Resume_devices: |
555 | entering_platform_hibernation = false; | 557 | entering_platform_hibernation = false; |
@@ -616,7 +618,7 @@ int hibernate(void) | |||
616 | /* Allocate memory management structures */ | 618 | /* Allocate memory management structures */ |
617 | error = create_basic_memory_bitmaps(); | 619 | error = create_basic_memory_bitmaps(); |
618 | if (error) | 620 | if (error) |
619 | goto Exit; | 621 | goto Enable_umh; |
620 | 622 | ||
621 | printk(KERN_INFO "PM: Syncing filesystems ... "); | 623 | printk(KERN_INFO "PM: Syncing filesystems ... "); |
622 | sys_sync(); | 624 | sys_sync(); |
@@ -624,15 +626,11 @@ int hibernate(void) | |||
624 | 626 | ||
625 | error = freeze_processes(); | 627 | error = freeze_processes(); |
626 | if (error) | 628 | if (error) |
627 | goto Finish; | 629 | goto Free_bitmaps; |
628 | 630 | ||
629 | error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); | 631 | error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM); |
630 | if (error) | 632 | if (error || freezer_test_done) |
631 | goto Thaw; | ||
632 | if (freezer_test_done) { | ||
633 | freezer_test_done = false; | ||
634 | goto Thaw; | 633 | goto Thaw; |
635 | } | ||
636 | 634 | ||
637 | if (in_suspend) { | 635 | if (in_suspend) { |
638 | unsigned int flags = 0; | 636 | unsigned int flags = 0; |
@@ -657,8 +655,13 @@ int hibernate(void) | |||
657 | 655 | ||
658 | Thaw: | 656 | Thaw: |
659 | thaw_processes(); | 657 | thaw_processes(); |
660 | Finish: | 658 | |
659 | /* Don't bother checking whether freezer_test_done is true */ | ||
660 | freezer_test_done = false; | ||
661 | |||
662 | Free_bitmaps: | ||
661 | free_basic_memory_bitmaps(); | 663 | free_basic_memory_bitmaps(); |
664 | Enable_umh: | ||
662 | usermodehelper_enable(); | 665 | usermodehelper_enable(); |
663 | Exit: | 666 | Exit: |
664 | pm_notifier_call_chain(PM_POST_HIBERNATION); | 667 | pm_notifier_call_chain(PM_POST_HIBERNATION); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 9824b41e5a18..1c12581f1c62 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -165,16 +165,20 @@ static int suspend_stats_show(struct seq_file *s, void *unused) | |||
165 | last_errno %= REC_FAILED_NUM; | 165 | last_errno %= REC_FAILED_NUM; |
166 | last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; | 166 | last_step = suspend_stats.last_failed_step + REC_FAILED_NUM - 1; |
167 | last_step %= REC_FAILED_NUM; | 167 | last_step %= REC_FAILED_NUM; |
168 | seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n" | 168 | seq_printf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n" |
169 | "%s: %d\n%s: %d\n%s: %d\n%s: %d\n", | 169 | "%s: %d\n%s: %d\n%s: %d\n%s: %d\n%s: %d\n", |
170 | "success", suspend_stats.success, | 170 | "success", suspend_stats.success, |
171 | "fail", suspend_stats.fail, | 171 | "fail", suspend_stats.fail, |
172 | "failed_freeze", suspend_stats.failed_freeze, | 172 | "failed_freeze", suspend_stats.failed_freeze, |
173 | "failed_prepare", suspend_stats.failed_prepare, | 173 | "failed_prepare", suspend_stats.failed_prepare, |
174 | "failed_suspend", suspend_stats.failed_suspend, | 174 | "failed_suspend", suspend_stats.failed_suspend, |
175 | "failed_suspend_late", | ||
176 | suspend_stats.failed_suspend_late, | ||
175 | "failed_suspend_noirq", | 177 | "failed_suspend_noirq", |
176 | suspend_stats.failed_suspend_noirq, | 178 | suspend_stats.failed_suspend_noirq, |
177 | "failed_resume", suspend_stats.failed_resume, | 179 | "failed_resume", suspend_stats.failed_resume, |
180 | "failed_resume_early", | ||
181 | suspend_stats.failed_resume_early, | ||
178 | "failed_resume_noirq", | 182 | "failed_resume_noirq", |
179 | suspend_stats.failed_resume_noirq); | 183 | suspend_stats.failed_resume_noirq); |
180 | seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", | 184 | seq_printf(s, "failures:\n last_failed_dev:\t%-s\n", |
@@ -287,16 +291,10 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, | |||
287 | 291 | ||
288 | #ifdef CONFIG_SUSPEND | 292 | #ifdef CONFIG_SUSPEND |
289 | for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { | 293 | for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) { |
290 | if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) | 294 | if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) { |
295 | error = pm_suspend(state); | ||
291 | break; | 296 | break; |
292 | } | 297 | } |
293 | if (state < PM_SUSPEND_MAX && *s) { | ||
294 | error = enter_state(state); | ||
295 | if (error) { | ||
296 | suspend_stats.fail++; | ||
297 | dpm_save_failed_errno(error); | ||
298 | } else | ||
299 | suspend_stats.success++; | ||
300 | } | 298 | } |
301 | #endif | 299 | #endif |
302 | 300 | ||
diff --git a/kernel/power/power.h b/kernel/power/power.h index 21724eee5206..98f3622d7407 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
@@ -177,13 +177,11 @@ extern const char *const pm_states[]; | |||
177 | 177 | ||
178 | extern bool valid_state(suspend_state_t state); | 178 | extern bool valid_state(suspend_state_t state); |
179 | extern int suspend_devices_and_enter(suspend_state_t state); | 179 | extern int suspend_devices_and_enter(suspend_state_t state); |
180 | extern int enter_state(suspend_state_t state); | ||
181 | #else /* !CONFIG_SUSPEND */ | 180 | #else /* !CONFIG_SUSPEND */ |
182 | static inline int suspend_devices_and_enter(suspend_state_t state) | 181 | static inline int suspend_devices_and_enter(suspend_state_t state) |
183 | { | 182 | { |
184 | return -ENOSYS; | 183 | return -ENOSYS; |
185 | } | 184 | } |
186 | static inline int enter_state(suspend_state_t state) { return -ENOSYS; } | ||
187 | static inline bool valid_state(suspend_state_t state) { return false; } | 185 | static inline bool valid_state(suspend_state_t state) { return false; } |
188 | #endif /* !CONFIG_SUSPEND */ | 186 | #endif /* !CONFIG_SUSPEND */ |
189 | 187 | ||
@@ -234,16 +232,14 @@ static inline int suspend_freeze_processes(void) | |||
234 | int error; | 232 | int error; |
235 | 233 | ||
236 | error = freeze_processes(); | 234 | error = freeze_processes(); |
237 | |||
238 | /* | 235 | /* |
239 | * freeze_processes() automatically thaws every task if freezing | 236 | * freeze_processes() automatically thaws every task if freezing |
240 | * fails. So we need not do anything extra upon error. | 237 | * fails. So we need not do anything extra upon error. |
241 | */ | 238 | */ |
242 | if (error) | 239 | if (error) |
243 | goto Finish; | 240 | return error; |
244 | 241 | ||
245 | error = freeze_kernel_threads(); | 242 | error = freeze_kernel_threads(); |
246 | |||
247 | /* | 243 | /* |
248 | * freeze_kernel_threads() thaws only kernel threads upon freezing | 244 | * freeze_kernel_threads() thaws only kernel threads upon freezing |
249 | * failure. So we have to thaw the userspace tasks ourselves. | 245 | * failure. So we have to thaw the userspace tasks ourselves. |
@@ -251,7 +247,6 @@ static inline int suspend_freeze_processes(void) | |||
251 | if (error) | 247 | if (error) |
252 | thaw_processes(); | 248 | thaw_processes(); |
253 | 249 | ||
254 | Finish: | ||
255 | return error; | 250 | return error; |
256 | } | 251 | } |
257 | 252 | ||
diff --git a/kernel/power/process.c b/kernel/power/process.c index 7e426459e60a..0d2aeb226108 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -53,11 +53,9 @@ static int try_to_freeze_tasks(bool user_only) | |||
53 | * It is "frozen enough". If the task does wake | 53 | * It is "frozen enough". If the task does wake |
54 | * up, it will immediately call try_to_freeze. | 54 | * up, it will immediately call try_to_freeze. |
55 | * | 55 | * |
56 | * Because freeze_task() goes through p's | 56 | * Because freeze_task() goes through p's scheduler lock, it's |
57 | * scheduler lock after setting TIF_FREEZE, it's | 57 | * guaranteed that TASK_STOPPED/TRACED -> TASK_RUNNING |
58 | * guaranteed that either we see TASK_RUNNING or | 58 | * transition can't race with task state testing here. |
59 | * try_to_stop() after schedule() in ptrace/signal | ||
60 | * stop sees TIF_FREEZE. | ||
61 | */ | 59 | */ |
62 | if (!task_is_stopped_or_traced(p) && | 60 | if (!task_is_stopped_or_traced(p) && |
63 | !freezer_should_skip(p)) | 61 | !freezer_should_skip(p)) |
@@ -98,13 +96,15 @@ static int try_to_freeze_tasks(bool user_only) | |||
98 | elapsed_csecs / 100, elapsed_csecs % 100, | 96 | elapsed_csecs / 100, elapsed_csecs % 100, |
99 | todo - wq_busy, wq_busy); | 97 | todo - wq_busy, wq_busy); |
100 | 98 | ||
101 | read_lock(&tasklist_lock); | 99 | if (!wakeup) { |
102 | do_each_thread(g, p) { | 100 | read_lock(&tasklist_lock); |
103 | if (!wakeup && !freezer_should_skip(p) && | 101 | do_each_thread(g, p) { |
104 | p != current && freezing(p) && !frozen(p)) | 102 | if (p != current && !freezer_should_skip(p) |
105 | sched_show_task(p); | 103 | && freezing(p) && !frozen(p)) |
106 | } while_each_thread(g, p); | 104 | sched_show_task(p); |
107 | read_unlock(&tasklist_lock); | 105 | } while_each_thread(g, p); |
106 | read_unlock(&tasklist_lock); | ||
107 | } | ||
108 | } else { | 108 | } else { |
109 | printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, | 109 | printk("(elapsed %d.%02d seconds) ", elapsed_csecs / 100, |
110 | elapsed_csecs % 100); | 110 | elapsed_csecs % 100); |
diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 995e3bd3417b..d6d6dbd1ecc0 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c | |||
@@ -469,21 +469,18 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, | |||
469 | static int __init pm_qos_power_init(void) | 469 | static int __init pm_qos_power_init(void) |
470 | { | 470 | { |
471 | int ret = 0; | 471 | int ret = 0; |
472 | int i; | ||
472 | 473 | ||
473 | ret = register_pm_qos_misc(&cpu_dma_pm_qos); | 474 | BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); |
474 | if (ret < 0) { | 475 | |
475 | printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n"); | 476 | for (i = 1; i < PM_QOS_NUM_CLASSES; i++) { |
476 | return ret; | 477 | ret = register_pm_qos_misc(pm_qos_array[i]); |
477 | } | 478 | if (ret < 0) { |
478 | ret = register_pm_qos_misc(&network_lat_pm_qos); | 479 | printk(KERN_ERR "pm_qos_param: %s setup failed\n", |
479 | if (ret < 0) { | 480 | pm_qos_array[i]->name); |
480 | printk(KERN_ERR "pm_qos_param: network_latency setup failed\n"); | 481 | return ret; |
481 | return ret; | 482 | } |
482 | } | 483 | } |
483 | ret = register_pm_qos_misc(&network_throughput_pm_qos); | ||
484 | if (ret < 0) | ||
485 | printk(KERN_ERR | ||
486 | "pm_qos_param: network_throughput setup failed\n"); | ||
487 | 484 | ||
488 | return ret; | 485 | return ret; |
489 | } | 486 | } |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 3a564ac85f36..0de28576807d 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -711,9 +711,10 @@ static void mark_nosave_pages(struct memory_bitmap *bm) | |||
711 | list_for_each_entry(region, &nosave_regions, list) { | 711 | list_for_each_entry(region, &nosave_regions, list) { |
712 | unsigned long pfn; | 712 | unsigned long pfn; |
713 | 713 | ||
714 | pr_debug("PM: Marking nosave pages: %016lx - %016lx\n", | 714 | pr_debug("PM: Marking nosave pages: [mem %#010llx-%#010llx]\n", |
715 | region->start_pfn << PAGE_SHIFT, | 715 | (unsigned long long) region->start_pfn << PAGE_SHIFT, |
716 | region->end_pfn << PAGE_SHIFT); | 716 | ((unsigned long long) region->end_pfn << PAGE_SHIFT) |
717 | - 1); | ||
717 | 718 | ||
718 | for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++) | 719 | for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++) |
719 | if (pfn_valid(pfn)) { | 720 | if (pfn_valid(pfn)) { |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 4fd51beed879..88e5c967370d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -37,8 +37,8 @@ const char *const pm_states[PM_SUSPEND_MAX] = { | |||
37 | static const struct platform_suspend_ops *suspend_ops; | 37 | static const struct platform_suspend_ops *suspend_ops; |
38 | 38 | ||
39 | /** | 39 | /** |
40 | * suspend_set_ops - Set the global suspend method table. | 40 | * suspend_set_ops - Set the global suspend method table. |
41 | * @ops: Pointer to ops structure. | 41 | * @ops: Suspend operations to use. |
42 | */ | 42 | */ |
43 | void suspend_set_ops(const struct platform_suspend_ops *ops) | 43 | void suspend_set_ops(const struct platform_suspend_ops *ops) |
44 | { | 44 | { |
@@ -58,11 +58,11 @@ bool valid_state(suspend_state_t state) | |||
58 | } | 58 | } |
59 | 59 | ||
60 | /** | 60 | /** |
61 | * suspend_valid_only_mem - generic memory-only valid callback | 61 | * suspend_valid_only_mem - Generic memory-only valid callback. |
62 | * | 62 | * |
63 | * Platform drivers that implement mem suspend only and only need | 63 | * Platform drivers that implement mem suspend only and only need to check for |
64 | * to check for that in their .valid callback can use this instead | 64 | * that in their .valid() callback can use this instead of rolling their own |
65 | * of rolling their own .valid callback. | 65 | * .valid() callback. |
66 | */ | 66 | */ |
67 | int suspend_valid_only_mem(suspend_state_t state) | 67 | int suspend_valid_only_mem(suspend_state_t state) |
68 | { | 68 | { |
@@ -83,10 +83,11 @@ static int suspend_test(int level) | |||
83 | } | 83 | } |
84 | 84 | ||
85 | /** | 85 | /** |
86 | * suspend_prepare - Do prep work before entering low-power state. | 86 | * suspend_prepare - Prepare for entering system sleep state. |
87 | * | 87 | * |
88 | * This is common code that is called for each state that we're entering. | 88 | * Common code run for every system sleep state that can be entered (except for |
89 | * Run suspend notifiers, allocate a console and stop all processes. | 89 | * hibernation). Run suspend notifiers, allocate the "suspend" console and |
90 | * freeze processes. | ||
90 | */ | 91 | */ |
91 | static int suspend_prepare(void) | 92 | static int suspend_prepare(void) |
92 | { | 93 | { |
@@ -131,9 +132,9 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | |||
131 | } | 132 | } |
132 | 133 | ||
133 | /** | 134 | /** |
134 | * suspend_enter - enter the desired system sleep state. | 135 | * suspend_enter - Make the system enter the given sleep state. |
135 | * @state: State to enter | 136 | * @state: System sleep state to enter. |
136 | * @wakeup: Returns information that suspend should not be entered again. | 137 | * @wakeup: Returns information that the sleep state should not be re-entered. |
137 | * | 138 | * |
138 | * This function should be called after devices have been suspended. | 139 | * This function should be called after devices have been suspended. |
139 | */ | 140 | */ |
@@ -147,7 +148,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
147 | goto Platform_finish; | 148 | goto Platform_finish; |
148 | } | 149 | } |
149 | 150 | ||
150 | error = dpm_suspend_noirq(PMSG_SUSPEND); | 151 | error = dpm_suspend_end(PMSG_SUSPEND); |
151 | if (error) { | 152 | if (error) { |
152 | printk(KERN_ERR "PM: Some devices failed to power down\n"); | 153 | printk(KERN_ERR "PM: Some devices failed to power down\n"); |
153 | goto Platform_finish; | 154 | goto Platform_finish; |
@@ -189,7 +190,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
189 | if (suspend_ops->wake) | 190 | if (suspend_ops->wake) |
190 | suspend_ops->wake(); | 191 | suspend_ops->wake(); |
191 | 192 | ||
192 | dpm_resume_noirq(PMSG_RESUME); | 193 | dpm_resume_start(PMSG_RESUME); |
193 | 194 | ||
194 | Platform_finish: | 195 | Platform_finish: |
195 | if (suspend_ops->finish) | 196 | if (suspend_ops->finish) |
@@ -199,9 +200,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) | |||
199 | } | 200 | } |
200 | 201 | ||
201 | /** | 202 | /** |
202 | * suspend_devices_and_enter - suspend devices and enter the desired system | 203 | * suspend_devices_and_enter - Suspend devices and enter system sleep state. |
203 | * sleep state. | 204 | * @state: System sleep state to enter. |
204 | * @state: state to enter | ||
205 | */ | 205 | */ |
206 | int suspend_devices_and_enter(suspend_state_t state) | 206 | int suspend_devices_and_enter(suspend_state_t state) |
207 | { | 207 | { |
@@ -251,10 +251,10 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
251 | } | 251 | } |
252 | 252 | ||
253 | /** | 253 | /** |
254 | * suspend_finish - Do final work before exiting suspend sequence. | 254 | * suspend_finish - Clean up before finishing the suspend sequence. |
255 | * | 255 | * |
256 | * Call platform code to clean up, restart processes, and free the | 256 | * Call platform code to clean up, restart processes, and free the console that |
257 | * console that we've allocated. This is not called for suspend-to-disk. | 257 | * we've allocated. This routine is not called for hibernation. |
258 | */ | 258 | */ |
259 | static void suspend_finish(void) | 259 | static void suspend_finish(void) |
260 | { | 260 | { |
@@ -265,16 +265,14 @@ static void suspend_finish(void) | |||
265 | } | 265 | } |
266 | 266 | ||
267 | /** | 267 | /** |
268 | * enter_state - Do common work of entering low-power state. | 268 | * enter_state - Do common work needed to enter system sleep state. |
269 | * @state: pm_state structure for state we're entering. | 269 | * @state: System sleep state to enter. |
270 | * | 270 | * |
271 | * Make sure we're the only ones trying to enter a sleep state. Fail | 271 | * Make sure that no one else is trying to put the system into a sleep state. |
272 | * if someone has beat us to it, since we don't want anything weird to | 272 | * Fail if that's not the case. Otherwise, prepare for system suspend, make the |
273 | * happen when we wake up. | 273 | * system enter the given sleep state and clean up after wakeup. |
274 | * Then, do the setup for suspend, enter the state, and cleaup (after | ||
275 | * we've woken up). | ||
276 | */ | 274 | */ |
277 | int enter_state(suspend_state_t state) | 275 | static int enter_state(suspend_state_t state) |
278 | { | 276 | { |
279 | int error; | 277 | int error; |
280 | 278 | ||
@@ -310,24 +308,26 @@ int enter_state(suspend_state_t state) | |||
310 | } | 308 | } |
311 | 309 | ||
312 | /** | 310 | /** |
313 | * pm_suspend - Externally visible function for suspending system. | 311 | * pm_suspend - Externally visible function for suspending the system. |
314 | * @state: Enumerated value of state to enter. | 312 | * @state: System sleep state to enter. |
315 | * | 313 | * |
316 | * Determine whether or not value is within range, get state | 314 | * Check if the value of @state represents one of the supported states, |
317 | * structure, and enter (above). | 315 | * execute enter_state() and update system suspend statistics. |
318 | */ | 316 | */ |
319 | int pm_suspend(suspend_state_t state) | 317 | int pm_suspend(suspend_state_t state) |
320 | { | 318 | { |
321 | int ret; | 319 | int error; |
322 | if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) { | 320 | |
323 | ret = enter_state(state); | 321 | if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) |
324 | if (ret) { | 322 | return -EINVAL; |
325 | suspend_stats.fail++; | 323 | |
326 | dpm_save_failed_errno(ret); | 324 | error = enter_state(state); |
327 | } else | 325 | if (error) { |
328 | suspend_stats.success++; | 326 | suspend_stats.fail++; |
329 | return ret; | 327 | dpm_save_failed_errno(error); |
328 | } else { | ||
329 | suspend_stats.success++; | ||
330 | } | 330 | } |
331 | return -EINVAL; | 331 | return error; |
332 | } | 332 | } |
333 | EXPORT_SYMBOL(pm_suspend); | 333 | EXPORT_SYMBOL(pm_suspend); |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 3e100075b13c..33c4329205af 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -249,16 +249,10 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, | |||
249 | } | 249 | } |
250 | pm_restore_gfp_mask(); | 250 | pm_restore_gfp_mask(); |
251 | error = hibernation_snapshot(data->platform_support); | 251 | error = hibernation_snapshot(data->platform_support); |
252 | if (error) { | 252 | if (!error) { |
253 | thaw_kernel_threads(); | ||
254 | } else { | ||
255 | error = put_user(in_suspend, (int __user *)arg); | 253 | error = put_user(in_suspend, (int __user *)arg); |
256 | if (!error && !freezer_test_done) | 254 | data->ready = !freezer_test_done && !error; |
257 | data->ready = 1; | 255 | freezer_test_done = false; |
258 | if (freezer_test_done) { | ||
259 | freezer_test_done = false; | ||
260 | thaw_kernel_threads(); | ||
261 | } | ||
262 | } | 256 | } |
263 | break; | 257 | break; |
264 | 258 | ||