aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-12-15 18:50:30 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2010-12-24 09:02:43 -0500
commit8a43a9ab7b329aa8590f8a064df9bf8c80987507 (patch)
tree7e60bb0dd5f4dcf6531aa3aad196930f02553166 /drivers/base/power
parent2cbb3ce1ad19e66858a4284dd6c4bb958162c483 (diff)
PM: Use a different list of devices for each stage of device suspend
Instead of keeping all devices in the same list during system suspend and resume, regardless of what suspend-resume callbacks have been executed for them already, use separate lists of devices that have had their ->prepare(), ->suspend() and ->suspend_noirq() callbacks executed. This will allow us to simplify the core device suspend and resume routines. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/main.c53
1 files changed, 19 insertions, 34 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index e6d628012654..b711867fa58e 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -42,6 +42,9 @@
42 */ 42 */
43 43
44LIST_HEAD(dpm_list); 44LIST_HEAD(dpm_list);
45LIST_HEAD(dpm_prepared_list);
46LIST_HEAD(dpm_suspended_list);
47LIST_HEAD(dpm_noirq_list);
45 48
46static DEFINE_MUTEX(dpm_list_mtx); 49static DEFINE_MUTEX(dpm_list_mtx);
47static pm_message_t pm_transition; 50static pm_message_t pm_transition;
@@ -476,14 +479,12 @@ End:
476 */ 479 */
477void dpm_resume_noirq(pm_message_t state) 480void dpm_resume_noirq(pm_message_t state)
478{ 481{
479 struct list_head list;
480 ktime_t starttime = ktime_get(); 482 ktime_t starttime = ktime_get();
481 483
482 INIT_LIST_HEAD(&list);
483 mutex_lock(&dpm_list_mtx); 484 mutex_lock(&dpm_list_mtx);
484 transition_started = false; 485 transition_started = false;
485 while (!list_empty(&dpm_list)) { 486 while (!list_empty(&dpm_noirq_list)) {
486 struct device *dev = to_device(dpm_list.next); 487 struct device *dev = to_device(dpm_noirq_list.next);
487 488
488 get_device(dev); 489 get_device(dev);
489 if (dev->power.status > DPM_OFF) { 490 if (dev->power.status > DPM_OFF) {
@@ -499,10 +500,9 @@ void dpm_resume_noirq(pm_message_t state)
499 pm_dev_err(dev, state, " early", error); 500 pm_dev_err(dev, state, " early", error);
500 } 501 }
501 if (!list_empty(&dev->power.entry)) 502 if (!list_empty(&dev->power.entry))
502 list_move_tail(&dev->power.entry, &list); 503 list_move_tail(&dev->power.entry, &dpm_suspended_list);
503 put_device(dev); 504 put_device(dev);
504 } 505 }
505 list_splice(&list, &dpm_list);
506 mutex_unlock(&dpm_list_mtx); 506 mutex_unlock(&dpm_list_mtx);
507 dpm_show_time(starttime, state, "early"); 507 dpm_show_time(starttime, state, "early");
508 resume_device_irqs(); 508 resume_device_irqs();
@@ -611,16 +611,14 @@ static bool is_async(struct device *dev)
611 */ 611 */
612static void dpm_resume(pm_message_t state) 612static void dpm_resume(pm_message_t state)
613{ 613{
614 struct list_head list;
615 struct device *dev; 614 struct device *dev;
616 ktime_t starttime = ktime_get(); 615 ktime_t starttime = ktime_get();
617 616
618 INIT_LIST_HEAD(&list);
619 mutex_lock(&dpm_list_mtx); 617 mutex_lock(&dpm_list_mtx);
620 pm_transition = state; 618 pm_transition = state;
621 async_error = 0; 619 async_error = 0;
622 620
623 list_for_each_entry(dev, &dpm_list, power.entry) { 621 list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
624 if (dev->power.status < DPM_OFF) 622 if (dev->power.status < DPM_OFF)
625 continue; 623 continue;
626 624
@@ -631,8 +629,8 @@ static void dpm_resume(pm_message_t state)
631 } 629 }
632 } 630 }
633 631
634 while (!list_empty(&dpm_list)) { 632 while (!list_empty(&dpm_suspended_list)) {
635 dev = to_device(dpm_list.next); 633 dev = to_device(dpm_suspended_list.next);
636 get_device(dev); 634 get_device(dev);
637 if (dev->power.status >= DPM_OFF && !is_async(dev)) { 635 if (dev->power.status >= DPM_OFF && !is_async(dev)) {
638 int error; 636 int error;
@@ -644,15 +642,11 @@ static void dpm_resume(pm_message_t state)
644 mutex_lock(&dpm_list_mtx); 642 mutex_lock(&dpm_list_mtx);
645 if (error) 643 if (error)
646 pm_dev_err(dev, state, "", error); 644 pm_dev_err(dev, state, "", error);
647 } else if (dev->power.status == DPM_SUSPENDING) {
648 /* Allow new children of the device to be registered */
649 dev->power.status = DPM_RESUMING;
650 } 645 }
651 if (!list_empty(&dev->power.entry)) 646 if (!list_empty(&dev->power.entry))
652 list_move_tail(&dev->power.entry, &list); 647 list_move_tail(&dev->power.entry, &dpm_prepared_list);
653 put_device(dev); 648 put_device(dev);
654 } 649 }
655 list_splice(&list, &dpm_list);
656 mutex_unlock(&dpm_list_mtx); 650 mutex_unlock(&dpm_list_mtx);
657 async_synchronize_full(); 651 async_synchronize_full();
658 dpm_show_time(starttime, state, NULL); 652 dpm_show_time(starttime, state, NULL);
@@ -699,8 +693,8 @@ static void dpm_complete(pm_message_t state)
699 INIT_LIST_HEAD(&list); 693 INIT_LIST_HEAD(&list);
700 mutex_lock(&dpm_list_mtx); 694 mutex_lock(&dpm_list_mtx);
701 transition_started = false; 695 transition_started = false;
702 while (!list_empty(&dpm_list)) { 696 while (!list_empty(&dpm_prepared_list)) {
703 struct device *dev = to_device(dpm_list.prev); 697 struct device *dev = to_device(dpm_prepared_list.prev);
704 698
705 get_device(dev); 699 get_device(dev);
706 if (dev->power.status > DPM_ON) { 700 if (dev->power.status > DPM_ON) {
@@ -803,15 +797,13 @@ End:
803 */ 797 */
804int dpm_suspend_noirq(pm_message_t state) 798int dpm_suspend_noirq(pm_message_t state)
805{ 799{
806 struct list_head list;
807 ktime_t starttime = ktime_get(); 800 ktime_t starttime = ktime_get();
808 int error = 0; 801 int error = 0;
809 802
810 INIT_LIST_HEAD(&list);
811 suspend_device_irqs(); 803 suspend_device_irqs();
812 mutex_lock(&dpm_list_mtx); 804 mutex_lock(&dpm_list_mtx);
813 while (!list_empty(&dpm_list)) { 805 while (!list_empty(&dpm_suspended_list)) {
814 struct device *dev = to_device(dpm_list.prev); 806 struct device *dev = to_device(dpm_suspended_list.prev);
815 807
816 get_device(dev); 808 get_device(dev);
817 mutex_unlock(&dpm_list_mtx); 809 mutex_unlock(&dpm_list_mtx);
@@ -826,10 +818,9 @@ int dpm_suspend_noirq(pm_message_t state)
826 } 818 }
827 dev->power.status = DPM_OFF_IRQ; 819 dev->power.status = DPM_OFF_IRQ;
828 if (!list_empty(&dev->power.entry)) 820 if (!list_empty(&dev->power.entry))
829 list_move(&dev->power.entry, &list); 821 list_move(&dev->power.entry, &dpm_noirq_list);
830 put_device(dev); 822 put_device(dev);
831 } 823 }
832 list_splice_tail(&list, &dpm_list);
833 mutex_unlock(&dpm_list_mtx); 824 mutex_unlock(&dpm_list_mtx);
834 if (error) 825 if (error)
835 dpm_resume_noirq(resume_event(state)); 826 dpm_resume_noirq(resume_event(state));
@@ -957,16 +948,14 @@ static int device_suspend(struct device *dev)
957 */ 948 */
958static int dpm_suspend(pm_message_t state) 949static int dpm_suspend(pm_message_t state)
959{ 950{
960 struct list_head list;
961 ktime_t starttime = ktime_get(); 951 ktime_t starttime = ktime_get();
962 int error = 0; 952 int error = 0;
963 953
964 INIT_LIST_HEAD(&list);
965 mutex_lock(&dpm_list_mtx); 954 mutex_lock(&dpm_list_mtx);
966 pm_transition = state; 955 pm_transition = state;
967 async_error = 0; 956 async_error = 0;
968 while (!list_empty(&dpm_list)) { 957 while (!list_empty(&dpm_prepared_list)) {
969 struct device *dev = to_device(dpm_list.prev); 958 struct device *dev = to_device(dpm_prepared_list.prev);
970 959
971 get_device(dev); 960 get_device(dev);
972 mutex_unlock(&dpm_list_mtx); 961 mutex_unlock(&dpm_list_mtx);
@@ -980,12 +969,11 @@ static int dpm_suspend(pm_message_t state)
980 break; 969 break;
981 } 970 }
982 if (!list_empty(&dev->power.entry)) 971 if (!list_empty(&dev->power.entry))
983 list_move(&dev->power.entry, &list); 972 list_move(&dev->power.entry, &dpm_suspended_list);
984 put_device(dev); 973 put_device(dev);
985 if (async_error) 974 if (async_error)
986 break; 975 break;
987 } 976 }
988 list_splice(&list, dpm_list.prev);
989 mutex_unlock(&dpm_list_mtx); 977 mutex_unlock(&dpm_list_mtx);
990 async_synchronize_full(); 978 async_synchronize_full();
991 if (!error) 979 if (!error)
@@ -1044,10 +1032,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
1044 */ 1032 */
1045static int dpm_prepare(pm_message_t state) 1033static int dpm_prepare(pm_message_t state)
1046{ 1034{
1047 struct list_head list;
1048 int error = 0; 1035 int error = 0;
1049 1036
1050 INIT_LIST_HEAD(&list);
1051 mutex_lock(&dpm_list_mtx); 1037 mutex_lock(&dpm_list_mtx);
1052 transition_started = true; 1038 transition_started = true;
1053 while (!list_empty(&dpm_list)) { 1039 while (!list_empty(&dpm_list)) {
@@ -1084,10 +1070,9 @@ static int dpm_prepare(pm_message_t state)
1084 } 1070 }
1085 dev->power.status = DPM_SUSPENDING; 1071 dev->power.status = DPM_SUSPENDING;
1086 if (!list_empty(&dev->power.entry)) 1072 if (!list_empty(&dev->power.entry))
1087 list_move_tail(&dev->power.entry, &list); 1073 list_move_tail(&dev->power.entry, &dpm_prepared_list);
1088 put_device(dev); 1074 put_device(dev);
1089 } 1075 }
1090 list_splice(&list, &dpm_list);
1091 mutex_unlock(&dpm_list_mtx); 1076 mutex_unlock(&dpm_list_mtx);
1092 return error; 1077 return error;
1093} 1078}