diff options
Diffstat (limited to 'drivers/base/power')
-rw-r--r-- | drivers/base/power/domain.c | 70 | ||||
-rw-r--r-- | drivers/base/power/main.c | 20 | ||||
-rw-r--r-- | drivers/base/power/trace.c | 6 |
3 files changed, 68 insertions, 28 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 45937f88e77c..2327613d4539 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -68,7 +68,36 @@ static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name) | |||
68 | return genpd; | 68 | return genpd; |
69 | } | 69 | } |
70 | 70 | ||
71 | struct generic_pm_domain *dev_to_genpd(struct device *dev) | 71 | /* |
72 | * Get the generic PM domain for a particular struct device. | ||
73 | * This validates the struct device pointer, the PM domain pointer, | ||
74 | * and checks that the PM domain pointer is a real generic PM domain. | ||
75 | * Any failure results in NULL being returned. | ||
76 | */ | ||
77 | struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev) | ||
78 | { | ||
79 | struct generic_pm_domain *genpd = NULL, *gpd; | ||
80 | |||
81 | if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain)) | ||
82 | return NULL; | ||
83 | |||
84 | mutex_lock(&gpd_list_lock); | ||
85 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
86 | if (&gpd->domain == dev->pm_domain) { | ||
87 | genpd = gpd; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | mutex_unlock(&gpd_list_lock); | ||
92 | |||
93 | return genpd; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * This should only be used where we are certain that the pm_domain | ||
98 | * attached to the device is a genpd domain. | ||
99 | */ | ||
100 | static struct generic_pm_domain *dev_to_genpd(struct device *dev) | ||
72 | { | 101 | { |
73 | if (IS_ERR_OR_NULL(dev->pm_domain)) | 102 | if (IS_ERR_OR_NULL(dev->pm_domain)) |
74 | return ERR_PTR(-EINVAL); | 103 | return ERR_PTR(-EINVAL); |
@@ -173,8 +202,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd) | |||
173 | genpd->power_on_latency_ns = elapsed_ns; | 202 | genpd->power_on_latency_ns = elapsed_ns; |
174 | genpd->max_off_time_changed = true; | 203 | genpd->max_off_time_changed = true; |
175 | genpd_recalc_cpu_exit_latency(genpd); | 204 | genpd_recalc_cpu_exit_latency(genpd); |
176 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | 205 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
177 | genpd->name, "on", elapsed_ns); | 206 | genpd->name, "on", elapsed_ns); |
178 | 207 | ||
179 | return ret; | 208 | return ret; |
180 | } | 209 | } |
@@ -199,8 +228,8 @@ static int genpd_power_off(struct generic_pm_domain *genpd) | |||
199 | 228 | ||
200 | genpd->power_off_latency_ns = elapsed_ns; | 229 | genpd->power_off_latency_ns = elapsed_ns; |
201 | genpd->max_off_time_changed = true; | 230 | genpd->max_off_time_changed = true; |
202 | pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n", | 231 | pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", |
203 | genpd->name, "off", elapsed_ns); | 232 | genpd->name, "off", elapsed_ns); |
204 | 233 | ||
205 | return ret; | 234 | return ret; |
206 | } | 235 | } |
@@ -1513,9 +1542,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, | |||
1513 | 1542 | ||
1514 | dev_dbg(dev, "%s()\n", __func__); | 1543 | dev_dbg(dev, "%s()\n", __func__); |
1515 | 1544 | ||
1516 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev) | 1545 | if (!genpd || genpd != pm_genpd_lookup_dev(dev)) |
1517 | || IS_ERR_OR_NULL(dev->pm_domain) | ||
1518 | || pd_to_genpd(dev->pm_domain) != genpd) | ||
1519 | return -EINVAL; | 1546 | return -EINVAL; |
1520 | 1547 | ||
1521 | /* The above validation also means we have existing domain_data. */ | 1548 | /* The above validation also means we have existing domain_data. */ |
@@ -2093,21 +2120,10 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); | |||
2093 | */ | 2120 | */ |
2094 | static void genpd_dev_pm_detach(struct device *dev, bool power_off) | 2121 | static void genpd_dev_pm_detach(struct device *dev, bool power_off) |
2095 | { | 2122 | { |
2096 | struct generic_pm_domain *pd = NULL, *gpd; | 2123 | struct generic_pm_domain *pd; |
2097 | int ret = 0; | 2124 | int ret = 0; |
2098 | 2125 | ||
2099 | if (!dev->pm_domain) | 2126 | pd = pm_genpd_lookup_dev(dev); |
2100 | return; | ||
2101 | |||
2102 | mutex_lock(&gpd_list_lock); | ||
2103 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { | ||
2104 | if (&gpd->domain == dev->pm_domain) { | ||
2105 | pd = gpd; | ||
2106 | break; | ||
2107 | } | ||
2108 | } | ||
2109 | mutex_unlock(&gpd_list_lock); | ||
2110 | |||
2111 | if (!pd) | 2127 | if (!pd) |
2112 | return; | 2128 | return; |
2113 | 2129 | ||
@@ -2130,6 +2146,17 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off) | |||
2130 | genpd_queue_power_off_work(pd); | 2146 | genpd_queue_power_off_work(pd); |
2131 | } | 2147 | } |
2132 | 2148 | ||
2149 | static void genpd_dev_pm_sync(struct device *dev) | ||
2150 | { | ||
2151 | struct generic_pm_domain *pd; | ||
2152 | |||
2153 | pd = dev_to_genpd(dev); | ||
2154 | if (IS_ERR(pd)) | ||
2155 | return; | ||
2156 | |||
2157 | genpd_queue_power_off_work(pd); | ||
2158 | } | ||
2159 | |||
2133 | /** | 2160 | /** |
2134 | * genpd_dev_pm_attach - Attach a device to its PM domain using DT. | 2161 | * genpd_dev_pm_attach - Attach a device to its PM domain using DT. |
2135 | * @dev: Device to attach. | 2162 | * @dev: Device to attach. |
@@ -2196,6 +2223,7 @@ int genpd_dev_pm_attach(struct device *dev) | |||
2196 | } | 2223 | } |
2197 | 2224 | ||
2198 | dev->pm_domain->detach = genpd_dev_pm_detach; | 2225 | dev->pm_domain->detach = genpd_dev_pm_detach; |
2226 | dev->pm_domain->sync = genpd_dev_pm_sync; | ||
2199 | pm_genpd_poweron(pd); | 2227 | pm_genpd_poweron(pd); |
2200 | 2228 | ||
2201 | return 0; | 2229 | return 0; |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9717d5f20139..3d874eca7104 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include <linux/resume-trace.h> | 26 | #include <linux/pm-trace.h> |
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
29 | #include <linux/async.h> | 29 | #include <linux/async.h> |
@@ -1017,6 +1017,9 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a | |||
1017 | char *info = NULL; | 1017 | char *info = NULL; |
1018 | int error = 0; | 1018 | int error = 0; |
1019 | 1019 | ||
1020 | TRACE_DEVICE(dev); | ||
1021 | TRACE_SUSPEND(0); | ||
1022 | |||
1020 | if (async_error) | 1023 | if (async_error) |
1021 | goto Complete; | 1024 | goto Complete; |
1022 | 1025 | ||
@@ -1057,6 +1060,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a | |||
1057 | 1060 | ||
1058 | Complete: | 1061 | Complete: |
1059 | complete_all(&dev->power.completion); | 1062 | complete_all(&dev->power.completion); |
1063 | TRACE_SUSPEND(error); | ||
1060 | return error; | 1064 | return error; |
1061 | } | 1065 | } |
1062 | 1066 | ||
@@ -1078,7 +1082,7 @@ static int device_suspend_noirq(struct device *dev) | |||
1078 | { | 1082 | { |
1079 | reinit_completion(&dev->power.completion); | 1083 | reinit_completion(&dev->power.completion); |
1080 | 1084 | ||
1081 | if (pm_async_enabled && dev->power.async_suspend) { | 1085 | if (is_async(dev)) { |
1082 | get_device(dev); | 1086 | get_device(dev); |
1083 | async_schedule(async_suspend_noirq, dev); | 1087 | async_schedule(async_suspend_noirq, dev); |
1084 | return 0; | 1088 | return 0; |
@@ -1157,6 +1161,9 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as | |||
1157 | char *info = NULL; | 1161 | char *info = NULL; |
1158 | int error = 0; | 1162 | int error = 0; |
1159 | 1163 | ||
1164 | TRACE_DEVICE(dev); | ||
1165 | TRACE_SUSPEND(0); | ||
1166 | |||
1160 | __pm_runtime_disable(dev, false); | 1167 | __pm_runtime_disable(dev, false); |
1161 | 1168 | ||
1162 | if (async_error) | 1169 | if (async_error) |
@@ -1198,6 +1205,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as | |||
1198 | async_error = error; | 1205 | async_error = error; |
1199 | 1206 | ||
1200 | Complete: | 1207 | Complete: |
1208 | TRACE_SUSPEND(error); | ||
1201 | complete_all(&dev->power.completion); | 1209 | complete_all(&dev->power.completion); |
1202 | return error; | 1210 | return error; |
1203 | } | 1211 | } |
@@ -1219,7 +1227,7 @@ static int device_suspend_late(struct device *dev) | |||
1219 | { | 1227 | { |
1220 | reinit_completion(&dev->power.completion); | 1228 | reinit_completion(&dev->power.completion); |
1221 | 1229 | ||
1222 | if (pm_async_enabled && dev->power.async_suspend) { | 1230 | if (is_async(dev)) { |
1223 | get_device(dev); | 1231 | get_device(dev); |
1224 | async_schedule(async_suspend_late, dev); | 1232 | async_schedule(async_suspend_late, dev); |
1225 | return 0; | 1233 | return 0; |
@@ -1338,6 +1346,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1338 | int error = 0; | 1346 | int error = 0; |
1339 | DECLARE_DPM_WATCHDOG_ON_STACK(wd); | 1347 | DECLARE_DPM_WATCHDOG_ON_STACK(wd); |
1340 | 1348 | ||
1349 | TRACE_DEVICE(dev); | ||
1350 | TRACE_SUSPEND(0); | ||
1351 | |||
1341 | dpm_wait_for_children(dev, async); | 1352 | dpm_wait_for_children(dev, async); |
1342 | 1353 | ||
1343 | if (async_error) | 1354 | if (async_error) |
@@ -1444,6 +1455,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
1444 | if (error) | 1455 | if (error) |
1445 | async_error = error; | 1456 | async_error = error; |
1446 | 1457 | ||
1458 | TRACE_SUSPEND(error); | ||
1447 | return error; | 1459 | return error; |
1448 | } | 1460 | } |
1449 | 1461 | ||
@@ -1465,7 +1477,7 @@ static int device_suspend(struct device *dev) | |||
1465 | { | 1477 | { |
1466 | reinit_completion(&dev->power.completion); | 1478 | reinit_completion(&dev->power.completion); |
1467 | 1479 | ||
1468 | if (pm_async_enabled && dev->power.async_suspend) { | 1480 | if (is_async(dev)) { |
1469 | get_device(dev); | 1481 | get_device(dev); |
1470 | async_schedule(async_suspend, dev); | 1482 | async_schedule(async_suspend, dev); |
1471 | return 0; | 1483 | return 0; |
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index d94a1f5121cf..a311cfa4c5bd 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * devices may be working. | 7 | * devices may be working. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/resume-trace.h> | 10 | #include <linux/pm-trace.h> |
11 | #include <linux/export.h> | 11 | #include <linux/export.h> |
12 | #include <linux/rtc.h> | 12 | #include <linux/rtc.h> |
13 | 13 | ||
@@ -154,7 +154,7 @@ EXPORT_SYMBOL(set_trace_device); | |||
154 | * it's not any guarantee, but it's a high _likelihood_ that | 154 | * it's not any guarantee, but it's a high _likelihood_ that |
155 | * the match is valid). | 155 | * the match is valid). |
156 | */ | 156 | */ |
157 | void generate_resume_trace(const void *tracedata, unsigned int user) | 157 | void generate_pm_trace(const void *tracedata, unsigned int user) |
158 | { | 158 | { |
159 | unsigned short lineno = *(unsigned short *)tracedata; | 159 | unsigned short lineno = *(unsigned short *)tracedata; |
160 | const char *file = *(const char **)(tracedata + 2); | 160 | const char *file = *(const char **)(tracedata + 2); |
@@ -164,7 +164,7 @@ void generate_resume_trace(const void *tracedata, unsigned int user) | |||
164 | file_hash_value = hash_string(lineno, file, FILEHASH); | 164 | file_hash_value = hash_string(lineno, file, FILEHASH); |
165 | set_magic_time(user_hash_value, file_hash_value, dev_hash_value); | 165 | set_magic_time(user_hash_value, file_hash_value, dev_hash_value); |
166 | } | 166 | } |
167 | EXPORT_SYMBOL(generate_resume_trace); | 167 | EXPORT_SYMBOL(generate_pm_trace); |
168 | 168 | ||
169 | extern char __tracedata_start, __tracedata_end; | 169 | extern char __tracedata_start, __tracedata_end; |
170 | static int show_file_hash(unsigned int value) | 170 | static int show_file_hash(unsigned int value) |