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>
This commit is contained in:
parent
221e9b5838
commit
0140d8bd47
1 changed files with 39 additions and 4 deletions
|
@ -33,6 +33,20 @@
|
||||||
__ret; \
|
__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 LIST_HEAD(gpd_list);
|
||||||
static DEFINE_MUTEX(gpd_list_lock);
|
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)
|
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)
|
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)
|
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)
|
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)
|
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) {
|
if (genpd->power_on) {
|
||||||
|
ktime_t time_start = ktime_get();
|
||||||
|
s64 elapsed_ns;
|
||||||
|
|
||||||
ret = genpd->power_on(genpd);
|
ret = genpd->power_on(genpd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
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);
|
genpd_set_active(genpd);
|
||||||
|
@ -377,11 +403,16 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (genpd->power_off) {
|
if (genpd->power_off) {
|
||||||
|
ktime_t time_start;
|
||||||
|
s64 elapsed_ns;
|
||||||
|
|
||||||
if (atomic_read(&genpd->sd_count) > 0) {
|
if (atomic_read(&genpd->sd_count) > 0) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_start = ktime_get();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If sd_count > 0 at this point, one of the subdomains hasn't
|
* If sd_count > 0 at this point, one of the subdomains hasn't
|
||||||
* managed to call pm_genpd_poweron() for the master yet after
|
* 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);
|
genpd_set_active(genpd);
|
||||||
goto out;
|
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;
|
genpd->status = GPD_STATE_POWER_OFF;
|
||||||
|
|
Loading…
Add table
Reference in a new issue