diff options
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 | 35 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 84 | ||||
| -rw-r--r-- | kernel/power/user.c | 12 |
9 files changed, 122 insertions, 133 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 6a768e537001..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)) { |
| @@ -1000,20 +1001,20 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) | |||
| 1000 | s_page = pfn_to_page(src_pfn); | 1001 | s_page = pfn_to_page(src_pfn); |
| 1001 | d_page = pfn_to_page(dst_pfn); | 1002 | d_page = pfn_to_page(dst_pfn); |
| 1002 | if (PageHighMem(s_page)) { | 1003 | if (PageHighMem(s_page)) { |
| 1003 | src = kmap_atomic(s_page, KM_USER0); | 1004 | src = kmap_atomic(s_page); |
| 1004 | dst = kmap_atomic(d_page, KM_USER1); | 1005 | dst = kmap_atomic(d_page); |
| 1005 | do_copy_page(dst, src); | 1006 | do_copy_page(dst, src); |
| 1006 | kunmap_atomic(dst, KM_USER1); | 1007 | kunmap_atomic(dst); |
| 1007 | kunmap_atomic(src, KM_USER0); | 1008 | kunmap_atomic(src); |
| 1008 | } else { | 1009 | } else { |
| 1009 | if (PageHighMem(d_page)) { | 1010 | if (PageHighMem(d_page)) { |
| 1010 | /* Page pointed to by src may contain some kernel | 1011 | /* Page pointed to by src may contain some kernel |
| 1011 | * data modified by kmap_atomic() | 1012 | * data modified by kmap_atomic() |
| 1012 | */ | 1013 | */ |
| 1013 | safe_copy_page(buffer, s_page); | 1014 | safe_copy_page(buffer, s_page); |
| 1014 | dst = kmap_atomic(d_page, KM_USER0); | 1015 | dst = kmap_atomic(d_page); |
| 1015 | copy_page(dst, buffer); | 1016 | copy_page(dst, buffer); |
| 1016 | kunmap_atomic(dst, KM_USER0); | 1017 | kunmap_atomic(dst); |
| 1017 | } else { | 1018 | } else { |
| 1018 | safe_copy_page(page_address(d_page), s_page); | 1019 | safe_copy_page(page_address(d_page), s_page); |
| 1019 | } | 1020 | } |
| @@ -1728,9 +1729,9 @@ int snapshot_read_next(struct snapshot_handle *handle) | |||
| 1728 | */ | 1729 | */ |
| 1729 | void *kaddr; | 1730 | void *kaddr; |
| 1730 | 1731 | ||
| 1731 | kaddr = kmap_atomic(page, KM_USER0); | 1732 | kaddr = kmap_atomic(page); |
| 1732 | copy_page(buffer, kaddr); | 1733 | copy_page(buffer, kaddr); |
| 1733 | kunmap_atomic(kaddr, KM_USER0); | 1734 | kunmap_atomic(kaddr); |
| 1734 | handle->buffer = buffer; | 1735 | handle->buffer = buffer; |
| 1735 | } else { | 1736 | } else { |
| 1736 | handle->buffer = page_address(page); | 1737 | handle->buffer = page_address(page); |
| @@ -2014,9 +2015,9 @@ static void copy_last_highmem_page(void) | |||
| 2014 | if (last_highmem_page) { | 2015 | if (last_highmem_page) { |
| 2015 | void *dst; | 2016 | void *dst; |
| 2016 | 2017 | ||
| 2017 | dst = kmap_atomic(last_highmem_page, KM_USER0); | 2018 | dst = kmap_atomic(last_highmem_page); |
| 2018 | copy_page(dst, buffer); | 2019 | copy_page(dst, buffer); |
| 2019 | kunmap_atomic(dst, KM_USER0); | 2020 | kunmap_atomic(dst); |
| 2020 | last_highmem_page = NULL; | 2021 | last_highmem_page = NULL; |
| 2021 | } | 2022 | } |
| 2022 | } | 2023 | } |
| @@ -2309,13 +2310,13 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf) | |||
| 2309 | { | 2310 | { |
| 2310 | void *kaddr1, *kaddr2; | 2311 | void *kaddr1, *kaddr2; |
| 2311 | 2312 | ||
| 2312 | kaddr1 = kmap_atomic(p1, KM_USER0); | 2313 | kaddr1 = kmap_atomic(p1); |
| 2313 | kaddr2 = kmap_atomic(p2, KM_USER1); | 2314 | kaddr2 = kmap_atomic(p2); |
| 2314 | copy_page(buf, kaddr1); | 2315 | copy_page(buf, kaddr1); |
| 2315 | copy_page(kaddr1, kaddr2); | 2316 | copy_page(kaddr1, kaddr2); |
| 2316 | copy_page(kaddr2, buf); | 2317 | copy_page(kaddr2, buf); |
| 2317 | kunmap_atomic(kaddr2, KM_USER1); | 2318 | kunmap_atomic(kaddr2); |
| 2318 | kunmap_atomic(kaddr1, KM_USER0); | 2319 | kunmap_atomic(kaddr1); |
| 2319 | } | 2320 | } |
| 2320 | 2321 | ||
| 2321 | /** | 2322 | /** |
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 | ||
