From: Rafael J. Wysocki <rafael.j.wyso...@intel.com>

It sometimes is necessary to find a cpufreq policy for a given CPU
and acquire its rwsem (for writing) immediately after that, so
introduce cpufreq_cpu_acquire() as a helper for that and the
complementary cpufreq_cpu_release().

Make cpufreq_update_policy() use the new functions.

Signed-off-by: Rafael J. Wysocki <rafael.j.wyso...@intel.com>
Acked-by: Viresh Kumar <viresh.ku...@linaro.org>
---

v2 -> v3:
  * Added Acked-by from Viresh.

---
 drivers/cpufreq/cpufreq.c |   56 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 47 insertions(+), 9 deletions(-)

Index: linux-pm/drivers/cpufreq/cpufreq.c
===================================================================
--- linux-pm.orig/drivers/cpufreq/cpufreq.c
+++ linux-pm/drivers/cpufreq/cpufreq.c
@@ -250,6 +250,51 @@ void cpufreq_cpu_put(struct cpufreq_poli
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
+/**
+ * cpufreq_cpu_release - Unlock a policy and decrement its usage counter.
+ * @policy: cpufreq policy returned by cpufreq_cpu_acquire().
+ */
+static void cpufreq_cpu_release(struct cpufreq_policy *policy)
+{
+       if (WARN_ON(!policy))
+               return;
+
+       lockdep_assert_held(&policy->rwsem);
+
+       up_write(&policy->rwsem);
+
+       cpufreq_cpu_put(policy);
+}
+
+/**
+ * cpufreq_cpu_acquire - Find policy for a CPU, mark it as busy and lock it.
+ * @cpu: CPU to find the policy for.
+ *
+ * Call cpufreq_cpu_get() to get a reference on the cpufreq policy for @cpu and
+ * if the policy returned by it is not NULL, acquire its rwsem for writing.
+ * Return the policy if it is active or release it and return NULL otherwise.
+ *
+ * The policy returned by this function has to be released with the help of
+ * cpufreq_cpu_release() in order to release its rwsem and balance its usage
+ * counter properly.
+ */
+static struct cpufreq_policy *cpufreq_cpu_acquire(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+
+       if (!policy)
+               return NULL;
+
+       down_write(&policy->rwsem);
+
+       if (policy_is_inactive(policy)) {
+               cpufreq_cpu_release(policy);
+               return NULL;
+       }
+
+       return policy;
+}
+
 /*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
  *********************************************************************/
@@ -2337,17 +2382,12 @@ static int cpufreq_set_policy(struct cpu
  */
 void cpufreq_update_policy(unsigned int cpu)
 {
-       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
        struct cpufreq_policy new_policy;
 
        if (!policy)
                return;
 
-       down_write(&policy->rwsem);
-
-       if (policy_is_inactive(policy))
-               goto unlock;
-
        /*
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
@@ -2364,9 +2404,7 @@ void cpufreq_update_policy(unsigned int
        cpufreq_set_policy(policy, &new_policy);
 
 unlock:
-       up_write(&policy->rwsem);
-
-       cpufreq_cpu_put(policy);
+       cpufreq_cpu_release(policy);
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 

Reply via email to