diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-10 11:14:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-10 11:14:53 -0500 |
commit | c8940eca75e6d1ea57f6c491a30bd1023c64c9ad (patch) | |
tree | d68944ab9fa8ba3c77b18edc2bd836c7e355b23e /drivers/base/power/main.c | |
parent | 78c92a9fd4b6abbbc1fe1ec335c697cb4e63f252 (diff) | |
parent | 3ae22e8c8ac39daf88ae32f047fb23825be7c646 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
spi / PM: Support dev_pm_ops
PM: Prototype the pm_generic_ operations
PM / Runtime: Generic resume shouldn't set RPM_ACTIVE unconditionally
PM: Use dev_name() in core device suspend and resume routines
PM: Permit registration of parentless devices during system suspend
PM: Replace the device power.status field with a bit field
PM: Remove redundant checks from core device resume routines
PM: Use a different list of devices for each stage of device suspend
PM: Avoid compiler warning in pm_noirq_op()
PM: Use pm_wakeup_pending() in __device_suspend()
PM / Wakeup: Replace pm_check_wakeup_events() with pm_wakeup_pending()
PM: Prevent dpm_prepare() from returning errors unnecessarily
PM: Fix references to basic-pm-debugging.txt in drivers-testing.txt
PM / Runtime: Add synchronous runtime interface for interrupt handlers (v3)
PM / Hibernate: When failed, in_suspend should be reset
PM / Hibernate: hibernation_ops->leave should be checked too
Freezer: Fix a race during freezing of TASK_STOPPED tasks
PM: Use proper ccflag flag in kernel/power/Makefile
PM / Runtime: Fix comments to match runtime callback code
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r-- | drivers/base/power/main.c | 174 |
1 files changed, 62 insertions, 112 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ead3e79d6fcf..2a52270aeb30 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/async.h> | 28 | #include <linux/async.h> |
29 | #include <linux/suspend.h> | ||
29 | 30 | ||
30 | #include "../base.h" | 31 | #include "../base.h" |
31 | #include "power.h" | 32 | #include "power.h" |
@@ -41,16 +42,13 @@ | |||
41 | */ | 42 | */ |
42 | 43 | ||
43 | LIST_HEAD(dpm_list); | 44 | LIST_HEAD(dpm_list); |
45 | LIST_HEAD(dpm_prepared_list); | ||
46 | LIST_HEAD(dpm_suspended_list); | ||
47 | LIST_HEAD(dpm_noirq_list); | ||
44 | 48 | ||
45 | static DEFINE_MUTEX(dpm_list_mtx); | 49 | static DEFINE_MUTEX(dpm_list_mtx); |
46 | static pm_message_t pm_transition; | 50 | static pm_message_t pm_transition; |
47 | 51 | ||
48 | /* | ||
49 | * Set once the preparation of devices for a PM transition has started, reset | ||
50 | * before starting to resume devices. Protected by dpm_list_mtx. | ||
51 | */ | ||
52 | static bool transition_started; | ||
53 | |||
54 | static int async_error; | 52 | static int async_error; |
55 | 53 | ||
56 | /** | 54 | /** |
@@ -59,7 +57,7 @@ static int async_error; | |||
59 | */ | 57 | */ |
60 | void device_pm_init(struct device *dev) | 58 | void device_pm_init(struct device *dev) |
61 | { | 59 | { |
62 | dev->power.status = DPM_ON; | 60 | dev->power.in_suspend = false; |
63 | init_completion(&dev->power.completion); | 61 | init_completion(&dev->power.completion); |
64 | complete_all(&dev->power.completion); | 62 | complete_all(&dev->power.completion); |
65 | dev->power.wakeup = NULL; | 63 | dev->power.wakeup = NULL; |
@@ -90,22 +88,11 @@ void device_pm_unlock(void) | |||
90 | void device_pm_add(struct device *dev) | 88 | void device_pm_add(struct device *dev) |
91 | { | 89 | { |
92 | pr_debug("PM: Adding info for %s:%s\n", | 90 | pr_debug("PM: Adding info for %s:%s\n", |
93 | dev->bus ? dev->bus->name : "No Bus", | 91 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
94 | kobject_name(&dev->kobj)); | ||
95 | mutex_lock(&dpm_list_mtx); | 92 | mutex_lock(&dpm_list_mtx); |
96 | if (dev->parent) { | 93 | if (dev->parent && dev->parent->power.in_suspend) |
97 | if (dev->parent->power.status >= DPM_SUSPENDING) | 94 | dev_warn(dev, "parent %s should not be sleeping\n", |
98 | dev_warn(dev, "parent %s should not be sleeping\n", | 95 | dev_name(dev->parent)); |
99 | dev_name(dev->parent)); | ||
100 | } else if (transition_started) { | ||
101 | /* | ||
102 | * We refuse to register parentless devices while a PM | ||
103 | * transition is in progress in order to avoid leaving them | ||
104 | * unhandled down the road | ||
105 | */ | ||
106 | dev_WARN(dev, "Parentless device registered during a PM transaction\n"); | ||
107 | } | ||
108 | |||
109 | list_add_tail(&dev->power.entry, &dpm_list); | 96 | list_add_tail(&dev->power.entry, &dpm_list); |
110 | mutex_unlock(&dpm_list_mtx); | 97 | mutex_unlock(&dpm_list_mtx); |
111 | } | 98 | } |
@@ -117,8 +104,7 @@ void device_pm_add(struct device *dev) | |||
117 | void device_pm_remove(struct device *dev) | 104 | void device_pm_remove(struct device *dev) |
118 | { | 105 | { |
119 | pr_debug("PM: Removing info for %s:%s\n", | 106 | pr_debug("PM: Removing info for %s:%s\n", |
120 | dev->bus ? dev->bus->name : "No Bus", | 107 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
121 | kobject_name(&dev->kobj)); | ||
122 | complete_all(&dev->power.completion); | 108 | complete_all(&dev->power.completion); |
123 | mutex_lock(&dpm_list_mtx); | 109 | mutex_lock(&dpm_list_mtx); |
124 | list_del_init(&dev->power.entry); | 110 | list_del_init(&dev->power.entry); |
@@ -135,10 +121,8 @@ void device_pm_remove(struct device *dev) | |||
135 | void device_pm_move_before(struct device *deva, struct device *devb) | 121 | void device_pm_move_before(struct device *deva, struct device *devb) |
136 | { | 122 | { |
137 | pr_debug("PM: Moving %s:%s before %s:%s\n", | 123 | pr_debug("PM: Moving %s:%s before %s:%s\n", |
138 | deva->bus ? deva->bus->name : "No Bus", | 124 | deva->bus ? deva->bus->name : "No Bus", dev_name(deva), |
139 | kobject_name(&deva->kobj), | 125 | devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); |
140 | devb->bus ? devb->bus->name : "No Bus", | ||
141 | kobject_name(&devb->kobj)); | ||
142 | /* Delete deva from dpm_list and reinsert before devb. */ | 126 | /* Delete deva from dpm_list and reinsert before devb. */ |
143 | list_move_tail(&deva->power.entry, &devb->power.entry); | 127 | list_move_tail(&deva->power.entry, &devb->power.entry); |
144 | } | 128 | } |
@@ -151,10 +135,8 @@ void device_pm_move_before(struct device *deva, struct device *devb) | |||
151 | void device_pm_move_after(struct device *deva, struct device *devb) | 135 | void device_pm_move_after(struct device *deva, struct device *devb) |
152 | { | 136 | { |
153 | pr_debug("PM: Moving %s:%s after %s:%s\n", | 137 | pr_debug("PM: Moving %s:%s after %s:%s\n", |
154 | deva->bus ? deva->bus->name : "No Bus", | 138 | deva->bus ? deva->bus->name : "No Bus", dev_name(deva), |
155 | kobject_name(&deva->kobj), | 139 | devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); |
156 | devb->bus ? devb->bus->name : "No Bus", | ||
157 | kobject_name(&devb->kobj)); | ||
158 | /* Delete deva from dpm_list and reinsert after devb. */ | 140 | /* Delete deva from dpm_list and reinsert after devb. */ |
159 | list_move(&deva->power.entry, &devb->power.entry); | 141 | list_move(&deva->power.entry, &devb->power.entry); |
160 | } | 142 | } |
@@ -166,8 +148,7 @@ void device_pm_move_after(struct device *deva, struct device *devb) | |||
166 | void device_pm_move_last(struct device *dev) | 148 | void device_pm_move_last(struct device *dev) |
167 | { | 149 | { |
168 | pr_debug("PM: Moving %s:%s to end of list\n", | 150 | pr_debug("PM: Moving %s:%s to end of list\n", |
169 | dev->bus ? dev->bus->name : "No Bus", | 151 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
170 | kobject_name(&dev->kobj)); | ||
171 | list_move_tail(&dev->power.entry, &dpm_list); | 152 | list_move_tail(&dev->power.entry, &dpm_list); |
172 | } | 153 | } |
173 | 154 | ||
@@ -303,7 +284,7 @@ static int pm_noirq_op(struct device *dev, | |||
303 | pm_message_t state) | 284 | pm_message_t state) |
304 | { | 285 | { |
305 | int error = 0; | 286 | int error = 0; |
306 | ktime_t calltime, delta, rettime; | 287 | ktime_t calltime = ktime_set(0, 0), delta, rettime; |
307 | 288 | ||
308 | if (initcall_debug) { | 289 | if (initcall_debug) { |
309 | pr_info("calling %s+ @ %i, parent: %s\n", | 290 | pr_info("calling %s+ @ %i, parent: %s\n", |
@@ -405,7 +386,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info, | |||
405 | int error) | 386 | int error) |
406 | { | 387 | { |
407 | printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n", | 388 | printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n", |
408 | kobject_name(&dev->kobj), pm_verb(state.event), info, error); | 389 | dev_name(dev), pm_verb(state.event), info, error); |
409 | } | 390 | } |
410 | 391 | ||
411 | static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) | 392 | static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info) |
@@ -475,33 +456,24 @@ End: | |||
475 | */ | 456 | */ |
476 | void dpm_resume_noirq(pm_message_t state) | 457 | void dpm_resume_noirq(pm_message_t state) |
477 | { | 458 | { |
478 | struct list_head list; | ||
479 | ktime_t starttime = ktime_get(); | 459 | ktime_t starttime = ktime_get(); |
480 | 460 | ||
481 | INIT_LIST_HEAD(&list); | ||
482 | mutex_lock(&dpm_list_mtx); | 461 | mutex_lock(&dpm_list_mtx); |
483 | transition_started = false; | 462 | while (!list_empty(&dpm_noirq_list)) { |
484 | while (!list_empty(&dpm_list)) { | 463 | struct device *dev = to_device(dpm_noirq_list.next); |
485 | struct device *dev = to_device(dpm_list.next); | 464 | int error; |
486 | 465 | ||
487 | get_device(dev); | 466 | get_device(dev); |
488 | if (dev->power.status > DPM_OFF) { | 467 | list_move_tail(&dev->power.entry, &dpm_suspended_list); |
489 | int error; | 468 | mutex_unlock(&dpm_list_mtx); |
490 | |||
491 | dev->power.status = DPM_OFF; | ||
492 | mutex_unlock(&dpm_list_mtx); | ||
493 | 469 | ||
494 | error = device_resume_noirq(dev, state); | 470 | error = device_resume_noirq(dev, state); |
471 | if (error) | ||
472 | pm_dev_err(dev, state, " early", error); | ||
495 | 473 | ||
496 | mutex_lock(&dpm_list_mtx); | 474 | mutex_lock(&dpm_list_mtx); |
497 | if (error) | ||
498 | pm_dev_err(dev, state, " early", error); | ||
499 | } | ||
500 | if (!list_empty(&dev->power.entry)) | ||
501 | list_move_tail(&dev->power.entry, &list); | ||
502 | put_device(dev); | 475 | put_device(dev); |
503 | } | 476 | } |
504 | list_splice(&list, &dpm_list); | ||
505 | mutex_unlock(&dpm_list_mtx); | 477 | mutex_unlock(&dpm_list_mtx); |
506 | dpm_show_time(starttime, state, "early"); | 478 | dpm_show_time(starttime, state, "early"); |
507 | resume_device_irqs(); | 479 | resume_device_irqs(); |
@@ -544,7 +516,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
544 | dpm_wait(dev->parent, async); | 516 | dpm_wait(dev->parent, async); |
545 | device_lock(dev); | 517 | device_lock(dev); |
546 | 518 | ||
547 | dev->power.status = DPM_RESUMING; | 519 | dev->power.in_suspend = false; |
548 | 520 | ||
549 | if (dev->bus) { | 521 | if (dev->bus) { |
550 | if (dev->bus->pm) { | 522 | if (dev->bus->pm) { |
@@ -610,19 +582,14 @@ static bool is_async(struct device *dev) | |||
610 | */ | 582 | */ |
611 | static void dpm_resume(pm_message_t state) | 583 | static void dpm_resume(pm_message_t state) |
612 | { | 584 | { |
613 | struct list_head list; | ||
614 | struct device *dev; | 585 | struct device *dev; |
615 | ktime_t starttime = ktime_get(); | 586 | ktime_t starttime = ktime_get(); |
616 | 587 | ||
617 | INIT_LIST_HEAD(&list); | ||
618 | mutex_lock(&dpm_list_mtx); | 588 | mutex_lock(&dpm_list_mtx); |
619 | pm_transition = state; | 589 | pm_transition = state; |
620 | async_error = 0; | 590 | async_error = 0; |
621 | 591 | ||
622 | list_for_each_entry(dev, &dpm_list, power.entry) { | 592 | list_for_each_entry(dev, &dpm_suspended_list, power.entry) { |
623 | if (dev->power.status < DPM_OFF) | ||
624 | continue; | ||
625 | |||
626 | INIT_COMPLETION(dev->power.completion); | 593 | INIT_COMPLETION(dev->power.completion); |
627 | if (is_async(dev)) { | 594 | if (is_async(dev)) { |
628 | get_device(dev); | 595 | get_device(dev); |
@@ -630,28 +597,24 @@ static void dpm_resume(pm_message_t state) | |||
630 | } | 597 | } |
631 | } | 598 | } |
632 | 599 | ||
633 | while (!list_empty(&dpm_list)) { | 600 | while (!list_empty(&dpm_suspended_list)) { |
634 | dev = to_device(dpm_list.next); | 601 | dev = to_device(dpm_suspended_list.next); |
635 | get_device(dev); | 602 | get_device(dev); |
636 | if (dev->power.status >= DPM_OFF && !is_async(dev)) { | 603 | if (!is_async(dev)) { |
637 | int error; | 604 | int error; |
638 | 605 | ||
639 | mutex_unlock(&dpm_list_mtx); | 606 | mutex_unlock(&dpm_list_mtx); |
640 | 607 | ||
641 | error = device_resume(dev, state, false); | 608 | error = device_resume(dev, state, false); |
642 | |||
643 | mutex_lock(&dpm_list_mtx); | ||
644 | if (error) | 609 | if (error) |
645 | pm_dev_err(dev, state, "", error); | 610 | pm_dev_err(dev, state, "", error); |
646 | } else if (dev->power.status == DPM_SUSPENDING) { | 611 | |
647 | /* Allow new children of the device to be registered */ | 612 | mutex_lock(&dpm_list_mtx); |
648 | dev->power.status = DPM_RESUMING; | ||
649 | } | 613 | } |
650 | if (!list_empty(&dev->power.entry)) | 614 | if (!list_empty(&dev->power.entry)) |
651 | list_move_tail(&dev->power.entry, &list); | 615 | list_move_tail(&dev->power.entry, &dpm_prepared_list); |
652 | put_device(dev); | 616 | put_device(dev); |
653 | } | 617 | } |
654 | list_splice(&list, &dpm_list); | ||
655 | mutex_unlock(&dpm_list_mtx); | 618 | mutex_unlock(&dpm_list_mtx); |
656 | async_synchronize_full(); | 619 | async_synchronize_full(); |
657 | dpm_show_time(starttime, state, NULL); | 620 | dpm_show_time(starttime, state, NULL); |
@@ -697,22 +660,18 @@ static void dpm_complete(pm_message_t state) | |||
697 | 660 | ||
698 | INIT_LIST_HEAD(&list); | 661 | INIT_LIST_HEAD(&list); |
699 | mutex_lock(&dpm_list_mtx); | 662 | mutex_lock(&dpm_list_mtx); |
700 | transition_started = false; | 663 | while (!list_empty(&dpm_prepared_list)) { |
701 | while (!list_empty(&dpm_list)) { | 664 | struct device *dev = to_device(dpm_prepared_list.prev); |
702 | struct device *dev = to_device(dpm_list.prev); | ||
703 | 665 | ||
704 | get_device(dev); | 666 | get_device(dev); |
705 | if (dev->power.status > DPM_ON) { | 667 | dev->power.in_suspend = false; |
706 | dev->power.status = DPM_ON; | 668 | list_move(&dev->power.entry, &list); |
707 | mutex_unlock(&dpm_list_mtx); | 669 | mutex_unlock(&dpm_list_mtx); |
708 | 670 | ||
709 | device_complete(dev, state); | 671 | device_complete(dev, state); |
710 | pm_runtime_put_sync(dev); | 672 | pm_runtime_put_sync(dev); |
711 | 673 | ||
712 | mutex_lock(&dpm_list_mtx); | 674 | mutex_lock(&dpm_list_mtx); |
713 | } | ||
714 | if (!list_empty(&dev->power.entry)) | ||
715 | list_move(&dev->power.entry, &list); | ||
716 | put_device(dev); | 675 | put_device(dev); |
717 | } | 676 | } |
718 | list_splice(&list, &dpm_list); | 677 | list_splice(&list, &dpm_list); |
@@ -802,15 +761,13 @@ End: | |||
802 | */ | 761 | */ |
803 | int dpm_suspend_noirq(pm_message_t state) | 762 | int dpm_suspend_noirq(pm_message_t state) |
804 | { | 763 | { |
805 | struct list_head list; | ||
806 | ktime_t starttime = ktime_get(); | 764 | ktime_t starttime = ktime_get(); |
807 | int error = 0; | 765 | int error = 0; |
808 | 766 | ||
809 | INIT_LIST_HEAD(&list); | ||
810 | suspend_device_irqs(); | 767 | suspend_device_irqs(); |
811 | mutex_lock(&dpm_list_mtx); | 768 | mutex_lock(&dpm_list_mtx); |
812 | while (!list_empty(&dpm_list)) { | 769 | while (!list_empty(&dpm_suspended_list)) { |
813 | struct device *dev = to_device(dpm_list.prev); | 770 | struct device *dev = to_device(dpm_suspended_list.prev); |
814 | 771 | ||
815 | get_device(dev); | 772 | get_device(dev); |
816 | mutex_unlock(&dpm_list_mtx); | 773 | mutex_unlock(&dpm_list_mtx); |
@@ -823,12 +780,10 @@ int dpm_suspend_noirq(pm_message_t state) | |||
823 | put_device(dev); | 780 | put_device(dev); |
824 | break; | 781 | break; |
825 | } | 782 | } |
826 | dev->power.status = DPM_OFF_IRQ; | ||
827 | if (!list_empty(&dev->power.entry)) | 783 | if (!list_empty(&dev->power.entry)) |
828 | list_move(&dev->power.entry, &list); | 784 | list_move(&dev->power.entry, &dpm_noirq_list); |
829 | put_device(dev); | 785 | put_device(dev); |
830 | } | 786 | } |
831 | list_splice_tail(&list, &dpm_list); | ||
832 | mutex_unlock(&dpm_list_mtx); | 787 | mutex_unlock(&dpm_list_mtx); |
833 | if (error) | 788 | if (error) |
834 | dpm_resume_noirq(resume_event(state)); | 789 | dpm_resume_noirq(resume_event(state)); |
@@ -876,6 +831,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
876 | if (async_error) | 831 | if (async_error) |
877 | goto End; | 832 | goto End; |
878 | 833 | ||
834 | if (pm_wakeup_pending()) { | ||
835 | async_error = -EBUSY; | ||
836 | goto End; | ||
837 | } | ||
838 | |||
879 | if (dev->class) { | 839 | if (dev->class) { |
880 | if (dev->class->pm) { | 840 | if (dev->class->pm) { |
881 | pm_dev_dbg(dev, state, "class "); | 841 | pm_dev_dbg(dev, state, "class "); |
@@ -907,9 +867,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
907 | } | 867 | } |
908 | } | 868 | } |
909 | 869 | ||
910 | if (!error) | ||
911 | dev->power.status = DPM_OFF; | ||
912 | |||
913 | End: | 870 | End: |
914 | device_unlock(dev); | 871 | device_unlock(dev); |
915 | complete_all(&dev->power.completion); | 872 | complete_all(&dev->power.completion); |
@@ -951,16 +908,14 @@ static int device_suspend(struct device *dev) | |||
951 | */ | 908 | */ |
952 | static int dpm_suspend(pm_message_t state) | 909 | static int dpm_suspend(pm_message_t state) |
953 | { | 910 | { |
954 | struct list_head list; | ||
955 | ktime_t starttime = ktime_get(); | 911 | ktime_t starttime = ktime_get(); |
956 | int error = 0; | 912 | int error = 0; |
957 | 913 | ||
958 | INIT_LIST_HEAD(&list); | ||
959 | mutex_lock(&dpm_list_mtx); | 914 | mutex_lock(&dpm_list_mtx); |
960 | pm_transition = state; | 915 | pm_transition = state; |
961 | async_error = 0; | 916 | async_error = 0; |
962 | while (!list_empty(&dpm_list)) { | 917 | while (!list_empty(&dpm_prepared_list)) { |
963 | struct device *dev = to_device(dpm_list.prev); | 918 | struct device *dev = to_device(dpm_prepared_list.prev); |
964 | 919 | ||
965 | get_device(dev); | 920 | get_device(dev); |
966 | mutex_unlock(&dpm_list_mtx); | 921 | mutex_unlock(&dpm_list_mtx); |
@@ -974,12 +929,11 @@ static int dpm_suspend(pm_message_t state) | |||
974 | break; | 929 | break; |
975 | } | 930 | } |
976 | if (!list_empty(&dev->power.entry)) | 931 | if (!list_empty(&dev->power.entry)) |
977 | list_move(&dev->power.entry, &list); | 932 | list_move(&dev->power.entry, &dpm_suspended_list); |
978 | put_device(dev); | 933 | put_device(dev); |
979 | if (async_error) | 934 | if (async_error) |
980 | break; | 935 | break; |
981 | } | 936 | } |
982 | list_splice(&list, dpm_list.prev); | ||
983 | mutex_unlock(&dpm_list_mtx); | 937 | mutex_unlock(&dpm_list_mtx); |
984 | async_synchronize_full(); | 938 | async_synchronize_full(); |
985 | if (!error) | 939 | if (!error) |
@@ -1038,22 +992,20 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
1038 | */ | 992 | */ |
1039 | static int dpm_prepare(pm_message_t state) | 993 | static int dpm_prepare(pm_message_t state) |
1040 | { | 994 | { |
1041 | struct list_head list; | ||
1042 | int error = 0; | 995 | int error = 0; |
1043 | 996 | ||
1044 | INIT_LIST_HEAD(&list); | ||
1045 | mutex_lock(&dpm_list_mtx); | 997 | mutex_lock(&dpm_list_mtx); |
1046 | transition_started = true; | ||
1047 | while (!list_empty(&dpm_list)) { | 998 | while (!list_empty(&dpm_list)) { |
1048 | struct device *dev = to_device(dpm_list.next); | 999 | struct device *dev = to_device(dpm_list.next); |
1049 | 1000 | ||
1050 | get_device(dev); | 1001 | get_device(dev); |
1051 | dev->power.status = DPM_PREPARING; | ||
1052 | mutex_unlock(&dpm_list_mtx); | 1002 | mutex_unlock(&dpm_list_mtx); |
1053 | 1003 | ||
1054 | pm_runtime_get_noresume(dev); | 1004 | pm_runtime_get_noresume(dev); |
1055 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) { | 1005 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) |
1056 | /* Wake-up requested during system sleep transition. */ | 1006 | pm_wakeup_event(dev, 0); |
1007 | |||
1008 | if (pm_wakeup_pending()) { | ||
1057 | pm_runtime_put_sync(dev); | 1009 | pm_runtime_put_sync(dev); |
1058 | error = -EBUSY; | 1010 | error = -EBUSY; |
1059 | } else { | 1011 | } else { |
@@ -1062,24 +1014,22 @@ static int dpm_prepare(pm_message_t state) | |||
1062 | 1014 | ||
1063 | mutex_lock(&dpm_list_mtx); | 1015 | mutex_lock(&dpm_list_mtx); |
1064 | if (error) { | 1016 | if (error) { |
1065 | dev->power.status = DPM_ON; | ||
1066 | if (error == -EAGAIN) { | 1017 | if (error == -EAGAIN) { |
1067 | put_device(dev); | 1018 | put_device(dev); |
1068 | error = 0; | 1019 | error = 0; |
1069 | continue; | 1020 | continue; |
1070 | } | 1021 | } |
1071 | printk(KERN_ERR "PM: Failed to prepare device %s " | 1022 | printk(KERN_INFO "PM: Device %s not prepared " |
1072 | "for power transition: error %d\n", | 1023 | "for power transition: code %d\n", |
1073 | kobject_name(&dev->kobj), error); | 1024 | dev_name(dev), error); |
1074 | put_device(dev); | 1025 | put_device(dev); |
1075 | break; | 1026 | break; |
1076 | } | 1027 | } |
1077 | dev->power.status = DPM_SUSPENDING; | 1028 | dev->power.in_suspend = true; |
1078 | if (!list_empty(&dev->power.entry)) | 1029 | if (!list_empty(&dev->power.entry)) |
1079 | list_move_tail(&dev->power.entry, &list); | 1030 | list_move_tail(&dev->power.entry, &dpm_prepared_list); |
1080 | put_device(dev); | 1031 | put_device(dev); |
1081 | } | 1032 | } |
1082 | list_splice(&list, &dpm_list); | ||
1083 | mutex_unlock(&dpm_list_mtx); | 1033 | mutex_unlock(&dpm_list_mtx); |
1084 | return error; | 1034 | return error; |
1085 | } | 1035 | } |