aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/domain.c70
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/power/trace.c6
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
71struct 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 */
77struct 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 */
100static 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 */
2094static void genpd_dev_pm_detach(struct device *dev, bool power_off) 2121static 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
2149static 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
1058Complete: 1061Complete:
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
1200Complete: 1207Complete:
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 */
157void generate_resume_trace(const void *tracedata, unsigned int user) 157void 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}
167EXPORT_SYMBOL(generate_resume_trace); 167EXPORT_SYMBOL(generate_pm_trace);
168 168
169extern char __tracedata_start, __tracedata_end; 169extern char __tracedata_start, __tracedata_end;
170static int show_file_hash(unsigned int value) 170static int show_file_hash(unsigned int value)