{
struct generic_pm_domain *genpd;
bool (*stop_ok)(struct device *__dev);
+ struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+++ bool runtime_pm = pm_runtime_enabled(dev);
+ ktime_t time_start;
+ s64 elapsed_ns;
int ret;
dev_dbg(dev, "%s()\n", __func__);
if (IS_ERR(genpd))
return -EINVAL;
+++ /*
+++ * A runtime PM centric subsystem/driver may re-use the runtime PM
+++ * callbacks for other purposes than runtime PM. In those scenarios
+++ * runtime PM is disabled. Under these circumstances, we shall skip
+++ * validating/measuring the PM QoS latency.
+++ */
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
--- if (stop_ok && !stop_ok(dev))
+++ if (runtime_pm && stop_ok && !stop_ok(dev))
return -EBUSY;
- - time_start = ktime_get();
+ /* Measure suspend latency. */
+++ if (runtime_pm)
+++ time_start = ktime_get();
+
ret = genpd_save_dev(genpd, dev);
if (ret)
return ret;
return ret;
}
- - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- - if (elapsed_ns > td->suspend_latency_ns) {
- - td->suspend_latency_ns = elapsed_ns;
- - dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
- - elapsed_ns);
- - genpd->max_off_time_changed = true;
- - td->constraint_changed = true;
+ /* Update suspend latency value if the measured time exceeds it. */
+++ if (runtime_pm) {
+++ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+++ if (elapsed_ns > td->suspend_latency_ns) {
+++ td->suspend_latency_ns = elapsed_ns;
+++ dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
+++ elapsed_ns);
+++ genpd->max_off_time_changed = true;
+++ td->constraint_changed = true;
+++ }
+ }
+
/*
* If power.irq_safe is set, this routine will be run with interrupts
* off, so it can't use mutexes.
static int pm_genpd_runtime_resume(struct device *dev)
{
struct generic_pm_domain *genpd;
+ struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+++ bool runtime_pm = pm_runtime_enabled(dev);
+ ktime_t time_start;
+ s64 elapsed_ns;
int ret;
bool timed = true;
return ret;
out:
- genpd_start_dev(genpd, dev, timed);
- genpd_restore_dev(genpd, dev, timed);
+ /* Measure resume latency. */
- - if (timed)
+++ if (timed && runtime_pm)
+ time_start = ktime_get();
+
+ genpd_start_dev(genpd, dev);
+ genpd_restore_dev(genpd, dev);
+
+ /* Update resume latency value if the measured time exceeds it. */
- - if (timed) {
+++ if (timed && runtime_pm) {
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns > td->resume_latency_ns) {
+ td->resume_latency_ns = elapsed_ns;
+ dev_dbg(dev, "resume latency exceeded, %lld ns\n",
+ elapsed_ns);
+ genpd->max_off_time_changed = true;
+ td->constraint_changed = true;
+ }
+ }
return 0;
}
out:
mutex_unlock(&subdomain->lock);
mutex_unlock(&genpd->lock);
-
+ if (ret)
+ kfree(link);
return ret;
}
-
- /**
- * pm_genpd_add_subdomain_names - Add a subdomain to an I/O PM domain.
- * @master_name: Name of the master PM domain to add the subdomain to.
- * @subdomain_name: Name of the subdomain to be added.
- */
- int pm_genpd_add_subdomain_names(const char *master_name,
- const char *subdomain_name)
- {
- struct generic_pm_domain *master = NULL, *subdomain = NULL, *gpd;
-
- if (IS_ERR_OR_NULL(master_name) || IS_ERR_OR_NULL(subdomain_name))
- return -EINVAL;
-
- mutex_lock(&gpd_list_lock);
- list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
- if (!master && !strcmp(gpd->name, master_name))
- master = gpd;
-
- if (!subdomain && !strcmp(gpd->name, subdomain_name))
- subdomain = gpd;
-
- if (master && subdomain)
- break;
- }
- mutex_unlock(&gpd_list_lock);
-
- return pm_genpd_add_subdomain(master, subdomain);
- }
+ +EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);
/**
* pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
return ret;
}
-
- /**
- * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle.
- * @genpd: PM domain to be connected with cpuidle.
- * @state: cpuidle state this domain can disable/enable.
- *
- * Make a PM domain behave as though it contained a CPU core, that is, instead
- * of calling its power down routine it will enable the given cpuidle state so
- * that the cpuidle subsystem can power it down (if possible and desirable).
- */
- int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
- {
- struct cpuidle_driver *cpuidle_drv;
- struct gpd_cpuidle_data *cpuidle_data;
- struct cpuidle_state *idle_state;
- int ret = 0;
-
- if (IS_ERR_OR_NULL(genpd) || state < 0)
- return -EINVAL;
-
- mutex_lock(&genpd->lock);
-
- if (genpd->cpuidle_data) {
- ret = -EEXIST;
- goto out;
- }
- cpuidle_data = kzalloc(sizeof(*cpuidle_data), GFP_KERNEL);
- if (!cpuidle_data) {
- ret = -ENOMEM;
- goto out;
- }
- cpuidle_drv = cpuidle_driver_ref();
- if (!cpuidle_drv) {
- ret = -ENODEV;
- goto err_drv;
- }
- if (cpuidle_drv->state_count <= state) {
- ret = -EINVAL;
- goto err;
- }
- idle_state = &cpuidle_drv->states[state];
- if (!idle_state->disabled) {
- ret = -EAGAIN;
- goto err;
- }
- cpuidle_data->idle_state = idle_state;
- cpuidle_data->saved_exit_latency = idle_state->exit_latency;
- genpd->cpuidle_data = cpuidle_data;
- genpd_recalc_cpu_exit_latency(genpd);
-
- out:
- mutex_unlock(&genpd->lock);
- return ret;
-
- err:
- cpuidle_driver_unref();
-
- err_drv:
- kfree(cpuidle_data);
- goto out;
- }
-
- /**
- * pm_genpd_name_attach_cpuidle - Find PM domain and connect cpuidle to it.
- * @name: Name of the domain to connect to cpuidle.
- * @state: cpuidle state this domain can manipulate.
- */
- int pm_genpd_name_attach_cpuidle(const char *name, int state)
- {
- return pm_genpd_attach_cpuidle(pm_genpd_lookup_name(name), state);
- }
-
- /**
- * pm_genpd_detach_cpuidle - Remove the cpuidle connection from a PM domain.
- * @genpd: PM domain to remove the cpuidle connection from.
- *
- * Remove the cpuidle connection set up by pm_genpd_attach_cpuidle() from the
- * given PM domain.
- */
- int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
- {
- struct gpd_cpuidle_data *cpuidle_data;
- struct cpuidle_state *idle_state;
- int ret = 0;
-
- if (IS_ERR_OR_NULL(genpd))
- return -EINVAL;
-
- mutex_lock(&genpd->lock);
-
- cpuidle_data = genpd->cpuidle_data;
- if (!cpuidle_data) {
- ret = -ENODEV;
- goto out;
- }
- idle_state = cpuidle_data->idle_state;
- if (!idle_state->disabled) {
- ret = -EAGAIN;
- goto out;
- }
- idle_state->exit_latency = cpuidle_data->saved_exit_latency;
- cpuidle_driver_unref();
- genpd->cpuidle_data = NULL;
- kfree(cpuidle_data);
-
- out:
- mutex_unlock(&genpd->lock);
- return ret;
- }
-
- /**
- * pm_genpd_name_detach_cpuidle - Find PM domain and disconnect cpuidle from it.
- * @name: Name of the domain to disconnect cpuidle from.
- */
- int pm_genpd_name_detach_cpuidle(const char *name)
- {
- return pm_genpd_detach_cpuidle(pm_genpd_lookup_name(name));
- }
+ +EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain);
/* Default device callbacks for generic PM domains. */