| From 17a958115eaf26f242853d26d79463f9978397d3 Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| Date: Thu, 1 Dec 2011 00:02:17 +0100 |
| Subject: 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> |
| (cherry picked from commit 0140d8bd47f798d55c3720f7fcade9e50929a5e5) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| drivers/base/power/domain.c | 43 +++++++++++++++++++++++++++++++++++++++---- |
| 1 file changed, 39 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c |
| index 9189619..5a8d67d 100644 |
| --- a/drivers/base/power/domain.c |
| +++ b/drivers/base/power/domain.c |
| @@ -33,6 +33,20 @@ |
| __ret; \ |
| }) |
| |
| +#define GENPD_DEV_TIMED_CALLBACK(genpd, type, callback, dev, field, name) \ |
| +({ \ |
| + ktime_t __start = ktime_get(); \ |
| + type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \ |
| + s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \ |
| + struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \ |
| + if (__elapsed > __gpd_data->td.field) { \ |
| + __gpd_data->td.field = __elapsed; \ |
| + dev_warn(dev, name " latency exceeded, new value %lld ns\n", \ |
| + __elapsed); \ |
| + } \ |
| + __retval; \ |
| +}) |
| + |
| static LIST_HEAD(gpd_list); |
| static DEFINE_MUTEX(gpd_list_lock); |
| |
| @@ -48,22 +62,27 @@ struct generic_pm_domain *dev_to_genpd(struct device *dev) |
| |
| static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) |
| { |
| - return GENPD_DEV_CALLBACK(genpd, int, stop, dev); |
| + return GENPD_DEV_TIMED_CALLBACK(genpd, int, stop, dev, |
| + stop_latency_ns, "stop"); |
| } |
| |
| static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) |
| { |
| - return GENPD_DEV_CALLBACK(genpd, int, start, dev); |
| + return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev, |
| + start_latency_ns, "start"); |
| } |
| |
| static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) |
| { |
| - return GENPD_DEV_CALLBACK(genpd, int, save_state, dev); |
| + return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, |
| + save_state_latency_ns, "state save"); |
| } |
| |
| static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev) |
| { |
| - return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); |
| + return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev, |
| + restore_state_latency_ns, |
| + "state restore"); |
| } |
| |
| static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) |
| @@ -182,9 +201,16 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd) |
| } |
| |
| if (genpd->power_on) { |
| + ktime_t time_start = ktime_get(); |
| + s64 elapsed_ns; |
| + |
| ret = genpd->power_on(genpd); |
| if (ret) |
| goto err; |
| + |
| + elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); |
| + if (elapsed_ns > genpd->power_on_latency_ns) |
| + genpd->power_on_latency_ns = elapsed_ns; |
| } |
| |
| genpd_set_active(genpd); |
| @@ -377,11 +403,16 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) |
| } |
| |
| if (genpd->power_off) { |
| + ktime_t time_start; |
| + s64 elapsed_ns; |
| + |
| if (atomic_read(&genpd->sd_count) > 0) { |
| ret = -EBUSY; |
| goto out; |
| } |
| |
| + time_start = ktime_get(); |
| + |
| /* |
| * If sd_count > 0 at this point, one of the subdomains hasn't |
| * 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) |
| genpd_set_active(genpd); |
| goto out; |
| } |
| + |
| + elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); |
| + if (elapsed_ns > genpd->power_off_latency_ns) |
| + genpd->power_off_latency_ns = elapsed_ns; |
| } |
| |
| genpd->status = GPD_STATE_POWER_OFF; |
| -- |
| 1.7.10.1.362.g242cab3 |
| |