aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-11-30 18:02:17 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-01 15:48:07 -0500
commit0140d8bd47f798d55c3720f7fcade9e50929a5e5 (patch)
tree8be169e9eab129f60fc0af2977e0335cfe764dee
parent221e9b58380abdd6c05e11b4538597e2586ee141 (diff)
PM / Domains: Automatically update overoptimistic latency information
Measure the time of execution of the .stop(), .start(), .save_state() and .restore_state() PM domain device callbacks and if the result is greater than the corresponding latency value stored in the device's struct generic_pm_domain_data object, replace the inaccurate value with the measured time. Do analogously for the PM domains' .power_off() and .power_off() callbacks. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--drivers/base/power/domain.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 91896194e76b..5a8d67d51f0e 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -33,6 +33,20 @@
33 __ret; \ 33 __ret; \
34}) 34})
35 35
36#define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name) \
37({ \
38 ktime_t __start = ktime_get(); \
39 type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \
40 s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \
41 struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \
42 if (__elapsed > __gpd_data->td.field) { \
43 __gpd_data->td.field = __elapsed; \
44 dev_warn(dev, name " latency exceeded, new value %lld ns\n", \
45 __elapsed); \
46 } \
47 __retval; \
48})
49
36static LIST_HEAD(gpd_list); 50static LIST_HEAD(gpd_list);
37static DEFINE_MUTEX(gpd_list_lock); 51static DEFINE_MUTEX(gpd_list_lock);
38 52
@@ -48,22 +62,27 @@ struct generic_pm_domain *dev_to_genpd(struct device *dev)
48 62
49static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) 63static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
50{ 64{
51 return GENPD_DEV_CALLBACK(genpd, int, stop, dev); 65 return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev,
66 stop_latency_ns, "stop");
52} 67}
53 68
54static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) 69static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
55{ 70{
56 return GENPD_DEV_CALLBACK(genpd, int, start, dev); 71 return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev,
72 start_latency_ns, "start");
57} 73}
58 74
59static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) 75static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
60{ 76{
61 return GENPD_DEV_CALLBACK(genpd, int, save_state, dev); 77 return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
78 save_state_latency_ns, "state save");
62} 79}
63 80
64static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev) 81static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
65{ 82{
66 return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); 83 return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
84 restore_state_latency_ns,
85 "state restore");
67} 86}
68 87
69static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) 88static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
@@ -182,9 +201,16 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
182 } 201 }
183 202
184 if (genpd->power_on) { 203 if (genpd->power_on) {
204 ktime_t time_start = ktime_get();
205 s64 elapsed_ns;
206
185 ret = genpd->power_on(genpd); 207 ret = genpd->power_on(genpd);
186 if (ret) 208 if (ret)
187 goto err; 209 goto err;
210
211 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
212 if (elapsed_ns > genpd->power_on_latency_ns)
213 genpd->power_on_latency_ns = elapsed_ns;
188 } 214 }
189 215
190 genpd_set_active(genpd); 216 genpd_set_active(genpd);
@@ -377,11 +403,16 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
377 } 403 }
378 404
379 if (genpd->power_off) { 405 if (genpd->power_off) {
406 ktime_t time_start;
407 s64 elapsed_ns;
408
380 if (atomic_read(&genpd->sd_count) > 0) { 409 if (atomic_read(&genpd->sd_count) > 0) {
381 ret = -EBUSY; 410 ret = -EBUSY;
382 goto out; 411 goto out;
383 } 412 }
384 413
414 time_start = ktime_get();
415
385 /* 416 /*
386 * If sd_count > 0 at this point, one of the subdomains hasn't 417 * If sd_count > 0 at this point, one of the subdomains hasn't
387 * managed to call pm_genpd_poweron() for the master yet after 418 * managed to call pm_genpd_poweron() for the master yet after
@@ -395,6 +426,10 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
395 genpd_set_active(genpd); 426 genpd_set_active(genpd);
396 goto out; 427 goto out;
397 } 428 }
429
430 elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
431 if (elapsed_ns > genpd->power_off_latency_ns)
432 genpd->power_off_latency_ns = elapsed_ns;
398 } 433 }
399 434
400 genpd->status = GPD_STATE_POWER_OFF; 435 genpd->status = GPD_STATE_POWER_OFF;