aboutsummaryrefslogtreecommitdiff
path: root/drivers/cpufreq/cpufreq.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-03 23:13:20 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-03 23:13:20 +0200
commit057beb1de54d33ecfd3397ed219b1f4518e3b470 (patch)
tree7c67e9d8c88093a3d551111e56401826a964ffba /drivers/cpufreq/cpufreq.c
parent42a09284fab8abc15c8554f2e2aa2368161c77c6 (diff)
parent5ece2399181a5abaf42a4cb607463770686778e6 (diff)
Merge branch 'pm-cpufreq'
* pm-cpufreq: (28 commits) cpufreq: handle calls to ->target_index() in separate routine cpufreq: s5pv210: drop check for CONFIG_PM_VERBOSE cpufreq: intel_pstate: Remove unused member name of cpudata cpufreq: Break out early when frequency equals target_freq cpufreq: Tegra: drop wrapper around tegra_update_cpu_speed() cpufreq: imx6q: Remove unused include cpufreq: imx6q: Drop devm_clk/regulator_get usage cpufreq: powernow-k8: Suppress checkpatch warnings cpufreq: powernv: make local function static cpufreq: Enable big.LITTLE cpufreq driver on arm64 cpufreq: nforce2: remove DEFINE_PCI_DEVICE_TABLE macro intel_pstate: Add CPU IDs for Broadwell processors cpufreq: Fix build error on some platforms that use cpufreq_for_each_* PM / OPP: Move cpufreq specific OPP functions out of generic OPP library PM / OPP: Remove cpufreq wrapper dependency on internal data organization cpufreq: Catch double invocations of cpufreq_freq_transition_begin/end intel_pstate: Remove sample parameter in intel_pstate_calc_busy cpufreq: Kconfig: Fix spelling errors cpufreq: Make linux-pm@vger.kernel.org official mailing list cpufreq: exynos: Use dev_err/info function instead of pr_err/info ...
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r--drivers/cpufreq/cpufreq.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index abda6609d3e..ae11dd51f81 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -354,6 +354,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs)
{
+
+ /*
+ * Catch double invocations of _begin() which lead to self-deadlock.
+ * ASYNC_NOTIFICATION drivers are left out because the cpufreq core
+ * doesn't invoke _begin() on their behalf, and hence the chances of
+ * double invocations are very low. Moreover, there are scenarios
+ * where these checks can emit false-positive warnings in these
+ * drivers; so we avoid that by skipping them altogether.
+ */
+ WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION)
+ && current == policy->transition_task);
+
wait:
wait_event(policy->transition_wait, !policy->transition_ongoing);
@@ -365,6 +377,7 @@ wait:
}
policy->transition_ongoing = true;
+ policy->transition_task = current;
spin_unlock(&policy->transition_lock);
@@ -381,6 +394,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
cpufreq_notify_post_transition(policy, freqs, transition_failed);
policy->transition_ongoing = false;
+ policy->transition_task = NULL;
wake_up(&policy->transition_wait);
}
@@ -1802,12 +1816,43 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS *
*********************************************************************/
+static int __target_index(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *freq_table, int index)
+{
+ struct cpufreq_freqs freqs;
+ int retval = -EINVAL;
+ bool notify;
+
+ notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
+
+ if (notify) {
+ freqs.old = policy->cur;
+ freqs.new = freq_table[index].frequency;
+ freqs.flags = 0;
+
+ pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
+ __func__, policy->cpu, freqs.old, freqs.new);
+
+ cpufreq_freq_transition_begin(policy, &freqs);
+ }
+
+ retval = cpufreq_driver->target_index(policy, index);
+ if (retval)
+ pr_err("%s: Failed to change cpu frequency: %d\n", __func__,
+ retval);
+
+ if (notify)
+ cpufreq_freq_transition_end(policy, &freqs, retval);
+
+ return retval;
+}
+
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int retval = -EINVAL;
unsigned int old_target_freq = target_freq;
+ int retval = -EINVAL;
if (cpufreq_disabled())
return -ENODEV;
@@ -1834,8 +1879,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
retval = cpufreq_driver->target(policy, target_freq, relation);
else if (cpufreq_driver->target_index) {
struct cpufreq_frequency_table *freq_table;
- struct cpufreq_freqs freqs;
- bool notify;
int index;
freq_table = cpufreq_frequency_get_table(policy->cpu);
@@ -1856,26 +1899,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
goto out;
}
- notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
-
- if (notify) {
- freqs.old = policy->cur;
- freqs.new = freq_table[index].frequency;
- freqs.flags = 0;
-
- pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
- __func__, policy->cpu, freqs.old, freqs.new);
-
- cpufreq_freq_transition_begin(policy, &freqs);
- }
-
- retval = cpufreq_driver->target_index(policy, index);
- if (retval)
- pr_err("%s: Failed to change cpu frequency: %d\n",
- __func__, retval);
-
- if (notify)
- cpufreq_freq_transition_end(policy, &freqs, retval);
+ retval = __target_index(policy, freq_table, index);
}
out: