From: Rafael J. Wysocki Date: Fri, 29 Jan 2016 20:45:17 +0000 (+0100) Subject: Merge branches 'pm-cpuidle', 'pm-cpufreq', 'pm-domains' and 'pm-sleep' X-Git-Tag: v4.5-rc2~19^2 X-Git-Url: https://repo.jachan.dev/linux.git/commitdiff_plain/ad1ac94767aa9d74c6533e33e768a14d2715162f?hp=-c Merge branches 'pm-cpuidle', 'pm-cpufreq', 'pm-domains' and 'pm-sleep' * pm-cpuidle: cpuidle: coupled: remove unused define cpuidle_coupled_lock cpuidle: fix fallback mechanism for suspend to idle in absence of enter_freeze * pm-cpufreq: cpufreq: cpufreq-dt: avoid uninitialized variable warnings: cpufreq: pxa2xx: fix pxa_cpufreq_change_voltage prototype cpufreq: Use list_is_last() to check last entry of the policy list cpufreq: Fix NULL reference crash while accessing policy->governor_data * pm-domains: PM / Domains: Fix typo in comment PM / Domains: Fix potential deadlock while adding/removing subdomains PM / domains: fix lockdep issue for all subdomains * pm-sleep: PM: APM_EMULATION does not depend on PM --- ad1ac94767aa9d74c6533e33e768a14d2715162f diff --combined drivers/base/power/domain.c index 6ac9a7f33b64,e03b1ad25a90,65f50eccd49b,014024a2fee9,e03b1ad25a90..784dbe897a5e --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@@@@@ -20,8 -20,6 -20,6 -20,6 -20,6 +20,8 @@@@@@ #include #include ++++#include "power.h" ++++ #define GENPD_RETRY_MAX_MS 250 /* Approximate */ #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ @@@@@@ -162,7 -160,7 -160,7 -160,7 -160,7 +162,7 @@@@@@ static int genpd_power_off(struct gener /** * genpd_queue_power_off_work - Queue up the execution of genpd_poweroff(). --- - * @genpd: PM domait to power off. +++ + * @genpd: PM domain to power off. * * Queue up the execution of genpd_poweroff() unless it's already been done * before. @@@@@@ -172,16 -170,16 -170,16 -170,15 -170,16 +172,15 @@@@@@ static void genpd_queue_power_off_work( queue_work(pm_wq, &genpd->power_off_work); } --- -static int genpd_poweron(struct generic_pm_domain *genpd); --- - /** * __genpd_poweron - Restore power to a given PM domain and its masters. * @genpd: PM domain to power up. +++ + * @depth: nesting count for lockdep. * * Restore power to @genpd and all of its masters so that it is possible to * resume a device belonging to it. */ --- -static int __genpd_poweron(struct generic_pm_domain *genpd) +++ +static int __genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) { struct gpd_link *link; int ret = 0; @@@@@@ -196,11 -194,11 -194,11 -193,16 -194,11 +195,16 @@@@@@ * with it. */ list_for_each_entry(link, &genpd->slave_links, slave_node) { --- - genpd_sd_counter_inc(link->master); +++ + struct generic_pm_domain *master = link->master; +++ + +++ + genpd_sd_counter_inc(master); +++ + +++ + mutex_lock_nested(&master->lock, depth + 1); +++ + ret = __genpd_poweron(master, depth + 1); +++ + mutex_unlock(&master->lock); --- - ret = genpd_poweron(link->master); if (ret) { --- - genpd_sd_counter_dec(link->master); +++ + genpd_sd_counter_dec(master); goto err; } } @@@@@@ -232,11 -230,11 -230,11 -234,12 -230,11 +236,12 @@@@@@ static int genpd_poweron(struct generic int ret; mutex_lock(&genpd->lock); --- - ret = __genpd_poweron(genpd); +++ + ret = __genpd_poweron(genpd, 0); mutex_unlock(&genpd->lock); return ret; } +++ + static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) { return GENPD_DEV_CALLBACK(genpd, int, save_state, dev); @@@@@@ -392,7 -390,6 -390,7 -395,7 -390,6 +397,7 @@@@@@ static int pm_genpd_runtime_suspend(str 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; @@@@@@ -403,19 -400,12 -401,19 -406,19 -400,12 +408,19 @@@@@@ 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; /* Measure suspend latency. */ - - time_start = ktime_get(); + + if (runtime_pm) + + time_start = ktime_get(); ret = genpd_save_dev(genpd, dev); if (ret) @@@@@@ -428,15 -418,13 -426,15 -431,15 -418,13 +433,15 @@@@@@ } /* Update suspend latency value if the measured time exceeds it. */ - - 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 (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; + + } } /* @@@@@@ -465,7 -453,6 -463,7 -468,7 -453,6 +470,7 @@@@@@ static int pm_genpd_runtime_resume(stru { 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; @@@@@@ -484,7 -471,7 -482,7 -487,7 -471,7 +489,7 @@@@@@ } mutex_lock(&genpd->lock); --- - ret = __genpd_poweron(genpd); +++ + ret = __genpd_poweron(genpd, 0); mutex_unlock(&genpd->lock); if (ret) @@@@@@ -492,14 -479,14 -490,14 -495,14 -479,14 +497,14 @@@@@@ out: /* 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; @@@@@@ -1190,11 -1177,10 -1188,10 -1193,10 -1177,10 +1195,11 @@@@@@ static struct generic_pm_domain_data *g } dev->power.subsys_data->domain_data = &gpd_data->base; ---- dev->pm_domain = &genpd->domain; spin_unlock_irq(&dev->power.lock); ++++ dev_pm_domain_set(dev, &genpd->domain); ++++ return gpd_data; err_free: @@@@@@ -1208,10 -1194,9 -1205,9 -1210,9 -1194,9 +1213,10 @@@@@@ static void genpd_free_dev_data(struct device *dev, struct generic_pm_domain_data *gpd_data) { ++++ dev_pm_domain_set(dev, NULL); ++++ spin_lock_irq(&dev->power.lock); ---- dev->pm_domain = NULL; dev->power.subsys_data->domain_data = NULL; spin_unlock_irq(&dev->power.lock); @@@@@@ -1267,7 -1252,6 -1263,6 -1268,7 -1252,6 +1272,7 @@@@@@ int __pm_genpd_add_device(struct generi return ret; } ++ +EXPORT_SYMBOL_GPL(__pm_genpd_add_device); /** * pm_genpd_remove_device - Remove a device from an I/O PM domain. @@@@@@ -1318,7 -1302,6 -1313,6 -1319,7 -1302,6 +1323,7 @@@@@@ int pm_genpd_remove_device(struct gener return ret; } ++ +EXPORT_SYMBOL_GPL(pm_genpd_remove_device); /** * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. @@@@@@ -1339,8 -1322,8 -1333,8 -1340,8 -1322,8 +1344,8 @@@@@@ int pm_genpd_add_subdomain(struct gener if (!link) return -ENOMEM; --- - mutex_lock(&genpd->lock); --- - mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); +++ + mutex_lock(&subdomain->lock); +++ + mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); if (genpd->status == GPD_STATE_POWER_OFF && subdomain->status != GPD_STATE_POWER_OFF) { @@@@@@ -1363,8 -1346,8 -1357,8 -1364,8 -1346,8 +1368,8 @@@@@@ genpd_sd_counter_inc(genpd); out: --- - mutex_unlock(&subdomain->lock); mutex_unlock(&genpd->lock); +++ + mutex_unlock(&subdomain->lock); if (ret) kfree(link); return ret; @@@@@@ -1385,7 -1368,7 -1379,7 -1386,8 -1368,7 +1390,8 @@@@@@ int pm_genpd_remove_subdomain(struct ge if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) return -EINVAL; --- - mutex_lock(&genpd->lock); +++ + mutex_lock(&subdomain->lock); +++ + mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING); if (!list_empty(&subdomain->slave_links) || subdomain->device_count) { pr_warn("%s: unable to remove subdomain %s\n", genpd->name, @@@@@@ -1398,22 -1381,22 -1392,22 -1400,19 -1381,22 +1404,19 @@@@@@ if (link->slave != subdomain) continue; --- - mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); --- - list_del(&link->master_node); list_del(&link->slave_node); kfree(link); if (subdomain->status != GPD_STATE_POWER_OFF) genpd_sd_counter_dec(genpd); --- - mutex_unlock(&subdomain->lock); --- - ret = 0; break; } out: mutex_unlock(&genpd->lock); +++ + mutex_unlock(&subdomain->lock); return ret; } @@@@@@ -1792,10 -1775,10 -1786,10 -1791,10 -1775,10 +1795,10 @@@@@@ int genpd_dev_pm_attach(struct device * } pd = of_genpd_get_from_provider(&pd_args); + + of_node_put(pd_args.np); if (IS_ERR(pd)) { dev_dbg(dev, "%s() failed to find PM domain: %ld\n", __func__, PTR_ERR(pd)); - - of_node_put(dev->of_node); return -EPROBE_DEFER; } @@@@@@ -1813,6 -1796,7 -1807,6 -1812,6 -1796,7 +1816,6 @@@@@@ if (ret < 0) { dev_err(dev, "failed to add to PM domain %s: %d", pd->name, ret); - - of_node_put(dev->of_node); goto out; } diff --combined kernel/sched/idle.c index de0e786b2667,30f7b6ad3920,4a2ef5a02fd3,4a2ef5a02fd3,4a2ef5a02fd3..544a7133cbd1 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@@@@@ -97,6 -97,6 -97,12 -97,12 -97,12 +97,6 @@@@@@ void default_idle_call(void static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev, int next_state) { --- /* Fall back to the default arch idle method on errors. */ --- if (next_state < 0) { --- default_idle_call(); --- return next_state; --- } --- /* * The idle task must be scheduled, it is pointless to go to idle, just * update no idle residency and return. @@@@@@ -162,7 -162,7 -168,7 -168,7 -168,7 +162,7 @@@@@@ static void cpuidle_idle_call(void */ if (idle_should_freeze()) { entered_state = cpuidle_enter_freeze(drv, dev); - --- if (entered_state >= 0) { + +++ if (entered_state > 0) { local_irq_enable(); goto exit_idle; } @@@@@@ -213,7 -213,6 -219,6 -219,6 -219,6 +213,7 @@@@@@ static void cpu_idle_loop(void */ __current_set_polling(); ++++ quiet_vmstat(); tick_nohz_idle_enter(); while (!need_resched()) {