diff options
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r-- | drivers/base/power/main.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a85459126bc..59f8ab23548 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -46,6 +46,7 @@ LIST_HEAD(dpm_prepared_list); | |||
46 | LIST_HEAD(dpm_suspended_list); | 46 | LIST_HEAD(dpm_suspended_list); |
47 | LIST_HEAD(dpm_noirq_list); | 47 | LIST_HEAD(dpm_noirq_list); |
48 | 48 | ||
49 | struct suspend_stats suspend_stats; | ||
49 | static DEFINE_MUTEX(dpm_list_mtx); | 50 | static DEFINE_MUTEX(dpm_list_mtx); |
50 | static pm_message_t pm_transition; | 51 | static pm_message_t pm_transition; |
51 | 52 | ||
@@ -65,6 +66,7 @@ void device_pm_init(struct device *dev) | |||
65 | spin_lock_init(&dev->power.lock); | 66 | spin_lock_init(&dev->power.lock); |
66 | pm_runtime_init(dev); | 67 | pm_runtime_init(dev); |
67 | INIT_LIST_HEAD(&dev->power.entry); | 68 | INIT_LIST_HEAD(&dev->power.entry); |
69 | dev->power.power_state = PMSG_INVALID; | ||
68 | } | 70 | } |
69 | 71 | ||
70 | /** | 72 | /** |
@@ -96,6 +98,7 @@ void device_pm_add(struct device *dev) | |||
96 | dev_warn(dev, "parent %s should not be sleeping\n", | 98 | dev_warn(dev, "parent %s should not be sleeping\n", |
97 | dev_name(dev->parent)); | 99 | dev_name(dev->parent)); |
98 | list_add_tail(&dev->power.entry, &dpm_list); | 100 | list_add_tail(&dev->power.entry, &dpm_list); |
101 | dev_pm_qos_constraints_init(dev); | ||
99 | mutex_unlock(&dpm_list_mtx); | 102 | mutex_unlock(&dpm_list_mtx); |
100 | } | 103 | } |
101 | 104 | ||
@@ -109,6 +112,7 @@ void device_pm_remove(struct device *dev) | |||
109 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); | 112 | dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); |
110 | complete_all(&dev->power.completion); | 113 | complete_all(&dev->power.completion); |
111 | mutex_lock(&dpm_list_mtx); | 114 | mutex_lock(&dpm_list_mtx); |
115 | dev_pm_qos_constraints_destroy(dev); | ||
112 | list_del_init(&dev->power.entry); | 116 | list_del_init(&dev->power.entry); |
113 | mutex_unlock(&dpm_list_mtx); | 117 | mutex_unlock(&dpm_list_mtx); |
114 | device_wakeup_disable(dev); | 118 | device_wakeup_disable(dev); |
@@ -464,8 +468,12 @@ void dpm_resume_noirq(pm_message_t state) | |||
464 | mutex_unlock(&dpm_list_mtx); | 468 | mutex_unlock(&dpm_list_mtx); |
465 | 469 | ||
466 | error = device_resume_noirq(dev, state); | 470 | error = device_resume_noirq(dev, state); |
467 | if (error) | 471 | if (error) { |
472 | suspend_stats.failed_resume_noirq++; | ||
473 | dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); | ||
474 | dpm_save_failed_dev(dev_name(dev)); | ||
468 | pm_dev_err(dev, state, " early", error); | 475 | pm_dev_err(dev, state, " early", error); |
476 | } | ||
469 | 477 | ||
470 | mutex_lock(&dpm_list_mtx); | 478 | mutex_lock(&dpm_list_mtx); |
471 | put_device(dev); | 479 | put_device(dev); |
@@ -626,8 +634,12 @@ void dpm_resume(pm_message_t state) | |||
626 | mutex_unlock(&dpm_list_mtx); | 634 | mutex_unlock(&dpm_list_mtx); |
627 | 635 | ||
628 | error = device_resume(dev, state, false); | 636 | error = device_resume(dev, state, false); |
629 | if (error) | 637 | if (error) { |
638 | suspend_stats.failed_resume++; | ||
639 | dpm_save_failed_step(SUSPEND_RESUME); | ||
640 | dpm_save_failed_dev(dev_name(dev)); | ||
630 | pm_dev_err(dev, state, "", error); | 641 | pm_dev_err(dev, state, "", error); |
642 | } | ||
631 | 643 | ||
632 | mutex_lock(&dpm_list_mtx); | 644 | mutex_lock(&dpm_list_mtx); |
633 | } | 645 | } |
@@ -802,6 +814,9 @@ int dpm_suspend_noirq(pm_message_t state) | |||
802 | mutex_lock(&dpm_list_mtx); | 814 | mutex_lock(&dpm_list_mtx); |
803 | if (error) { | 815 | if (error) { |
804 | pm_dev_err(dev, state, " late", error); | 816 | pm_dev_err(dev, state, " late", error); |
817 | suspend_stats.failed_suspend_noirq++; | ||
818 | dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); | ||
819 | dpm_save_failed_dev(dev_name(dev)); | ||
805 | put_device(dev); | 820 | put_device(dev); |
806 | break; | 821 | break; |
807 | } | 822 | } |
@@ -902,7 +917,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
902 | } | 917 | } |
903 | 918 | ||
904 | End: | 919 | End: |
905 | dev->power.is_suspended = !error; | 920 | if (!error) { |
921 | dev->power.is_suspended = true; | ||
922 | if (dev->power.wakeup_path && dev->parent) | ||
923 | dev->parent->power.wakeup_path = true; | ||
924 | } | ||
906 | 925 | ||
907 | device_unlock(dev); | 926 | device_unlock(dev); |
908 | complete_all(&dev->power.completion); | 927 | complete_all(&dev->power.completion); |
@@ -923,8 +942,10 @@ static void async_suspend(void *data, async_cookie_t cookie) | |||
923 | int error; | 942 | int error; |
924 | 943 | ||
925 | error = __device_suspend(dev, pm_transition, true); | 944 | error = __device_suspend(dev, pm_transition, true); |
926 | if (error) | 945 | if (error) { |
946 | dpm_save_failed_dev(dev_name(dev)); | ||
927 | pm_dev_err(dev, pm_transition, " async", error); | 947 | pm_dev_err(dev, pm_transition, " async", error); |
948 | } | ||
928 | 949 | ||
929 | put_device(dev); | 950 | put_device(dev); |
930 | } | 951 | } |
@@ -967,6 +988,7 @@ int dpm_suspend(pm_message_t state) | |||
967 | mutex_lock(&dpm_list_mtx); | 988 | mutex_lock(&dpm_list_mtx); |
968 | if (error) { | 989 | if (error) { |
969 | pm_dev_err(dev, state, "", error); | 990 | pm_dev_err(dev, state, "", error); |
991 | dpm_save_failed_dev(dev_name(dev)); | ||
970 | put_device(dev); | 992 | put_device(dev); |
971 | break; | 993 | break; |
972 | } | 994 | } |
@@ -980,7 +1002,10 @@ int dpm_suspend(pm_message_t state) | |||
980 | async_synchronize_full(); | 1002 | async_synchronize_full(); |
981 | if (!error) | 1003 | if (!error) |
982 | error = async_error; | 1004 | error = async_error; |
983 | if (!error) | 1005 | if (error) { |
1006 | suspend_stats.failed_suspend++; | ||
1007 | dpm_save_failed_step(SUSPEND_SUSPEND); | ||
1008 | } else | ||
984 | dpm_show_time(starttime, state, NULL); | 1009 | dpm_show_time(starttime, state, NULL); |
985 | return error; | 1010 | return error; |
986 | } | 1011 | } |
@@ -999,6 +1024,8 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
999 | 1024 | ||
1000 | device_lock(dev); | 1025 | device_lock(dev); |
1001 | 1026 | ||
1027 | dev->power.wakeup_path = device_may_wakeup(dev); | ||
1028 | |||
1002 | if (dev->pm_domain) { | 1029 | if (dev->pm_domain) { |
1003 | pm_dev_dbg(dev, state, "preparing power domain "); | 1030 | pm_dev_dbg(dev, state, "preparing power domain "); |
1004 | if (dev->pm_domain->ops.prepare) | 1031 | if (dev->pm_domain->ops.prepare) |
@@ -1088,7 +1115,10 @@ int dpm_suspend_start(pm_message_t state) | |||
1088 | int error; | 1115 | int error; |
1089 | 1116 | ||
1090 | error = dpm_prepare(state); | 1117 | error = dpm_prepare(state); |
1091 | if (!error) | 1118 | if (error) { |
1119 | suspend_stats.failed_prepare++; | ||
1120 | dpm_save_failed_step(SUSPEND_PREPARE); | ||
1121 | } else | ||
1092 | error = dpm_suspend(state); | 1122 | error = dpm_suspend(state); |
1093 | return error; | 1123 | return error; |
1094 | } | 1124 | } |