Merge branch 'pm-cpufreq-governor' into pm-cpufreq
[linux-2.6-block.git] / drivers / cpufreq / cpufreq.c
index abca44c2e4e3ed899a42b8a5717c6f1fc590af5d..4c7825856eabebde799913257e936f12b29ec387 100644 (file)
@@ -64,7 +64,6 @@ static LIST_HEAD(cpufreq_governor_list);
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
 static DEFINE_RWLOCK(cpufreq_driver_lock);
-DEFINE_MUTEX(cpufreq_governor_lock);
 
 /* Flag to suspend/resume CPUFreq governors */
 static bool cpufreq_suspended;
@@ -75,10 +74,8 @@ static inline bool has_target(void)
 }
 
 /* internal prototypes */
-static int __cpufreq_governor(struct cpufreq_policy *policy,
-               unsigned int event);
+static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
-static void handle_update(struct work_struct *work);
 
 /**
  * Two notifier lists: the "policy" list is involved in the
@@ -955,30 +952,38 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
        if (cpumask_test_cpu(cpu, policy->cpus))
                return 0;
 
+       down_write(&policy->rwsem);
        if (has_target()) {
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
                if (ret) {
                        pr_err("%s: Failed to stop governor\n", __func__);
-                       return ret;
+                       goto unlock;
                }
        }
 
-       down_write(&policy->rwsem);
        cpumask_set_cpu(cpu, policy->cpus);
-       up_write(&policy->rwsem);
 
        if (has_target()) {
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
                if (!ret)
-                       ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                       ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 
-               if (ret) {
+               if (ret)
                        pr_err("%s: Failed to start governor\n", __func__);
-                       return ret;
-               }
        }
 
-       return 0;
+unlock:
+       up_write(&policy->rwsem);
+       return ret;
+}
+
+static void handle_update(struct work_struct *work)
+{
+       struct cpufreq_policy *policy =
+               container_of(work, struct cpufreq_policy, update);
+       unsigned int cpu = policy->cpu;
+       pr_debug("handle_update for cpu %u called\n", cpu);
+       cpufreq_update_policy(cpu);
 }
 
 static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
@@ -1267,9 +1272,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        return ret;
 }
 
-static void cpufreq_offline_prepare(unsigned int cpu)
+static void cpufreq_offline(unsigned int cpu)
 {
        struct cpufreq_policy *policy;
+       int ret;
 
        pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
 
@@ -1279,13 +1285,13 @@ static void cpufreq_offline_prepare(unsigned int cpu)
                return;
        }
 
+       down_write(&policy->rwsem);
        if (has_target()) {
-               int ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
                if (ret)
                        pr_err("%s: Failed to stop governor\n", __func__);
        }
 
-       down_write(&policy->rwsem);
        cpumask_clear_cpu(cpu, policy->cpus);
 
        if (policy_is_inactive(policy)) {
@@ -1298,39 +1304,27 @@ static void cpufreq_offline_prepare(unsigned int cpu)
                /* Nominate new CPU */
                policy->cpu = cpumask_any(policy->cpus);
        }
-       up_write(&policy->rwsem);
 
        /* Start governor again for active policy */
        if (!policy_is_inactive(policy)) {
                if (has_target()) {
-                       int ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+                       ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
                        if (!ret)
-                               ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                               ret = cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 
                        if (ret)
                                pr_err("%s: Failed to start governor\n", __func__);
                }
-       } else if (cpufreq_driver->stop_cpu) {
-               cpufreq_driver->stop_cpu(policy);
-       }
-}
 
-static void cpufreq_offline_finish(unsigned int cpu)
-{
-       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
-
-       if (!policy) {
-               pr_debug("%s: No cpu_data found\n", __func__);
-               return;
+               goto unlock;
        }
 
-       /* Only proceed for inactive policies */
-       if (!policy_is_inactive(policy))
-               return;
+       if (cpufreq_driver->stop_cpu)
+               cpufreq_driver->stop_cpu(policy);
 
        /* If cpu is last user of policy, free policy */
        if (has_target()) {
-               int ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
                if (ret)
                        pr_err("%s: Failed to exit governor\n", __func__);
        }
@@ -1344,6 +1338,9 @@ static void cpufreq_offline_finish(unsigned int cpu)
                cpufreq_driver->exit(policy);
                policy->freq_table = NULL;
        }
+
+unlock:
+       up_write(&policy->rwsem);
 }
 
 /**
@@ -1359,10 +1356,8 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        if (!policy)
                return;
 
-       if (cpu_online(cpu)) {
-               cpufreq_offline_prepare(cpu);
-               cpufreq_offline_finish(cpu);
-       }
+       if (cpu_online(cpu))
+               cpufreq_offline(cpu);
 
        cpumask_clear_cpu(cpu, policy->real_cpus);
        remove_cpu_dev_symlink(policy, cpu);
@@ -1371,15 +1366,6 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
                cpufreq_policy_free(policy, true);
 }
 
-static void handle_update(struct work_struct *work)
-{
-       struct cpufreq_policy *policy =
-               container_of(work, struct cpufreq_policy, update);
-       unsigned int cpu = policy->cpu;
-       pr_debug("handle_update for cpu %u called\n", cpu);
-       cpufreq_update_policy(cpu);
-}
-
 /**
  *     cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
  *     in deep trouble.
@@ -1542,6 +1528,7 @@ EXPORT_SYMBOL(cpufreq_generic_suspend);
 void cpufreq_suspend(void)
 {
        struct cpufreq_policy *policy;
+       int ret;
 
        if (!cpufreq_driver)
                return;
@@ -1552,7 +1539,11 @@ void cpufreq_suspend(void)
        pr_debug("%s: Suspending Governors\n", __func__);
 
        for_each_active_policy(policy) {
-               if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
+               down_write(&policy->rwsem);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+               up_write(&policy->rwsem);
+
+               if (ret)
                        pr_err("%s: Failed to stop governor for policy: %p\n",
                                __func__, policy);
                else if (cpufreq_driver->suspend
@@ -1574,6 +1565,7 @@ suspend:
 void cpufreq_resume(void)
 {
        struct cpufreq_policy *policy;
+       int ret;
 
        if (!cpufreq_driver)
                return;
@@ -1586,13 +1578,20 @@ void cpufreq_resume(void)
        pr_debug("%s: Resuming Governors\n", __func__);
 
        for_each_active_policy(policy) {
-               if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
+               if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) {
                        pr_err("%s: Failed to resume driver: %p\n", __func__,
                                policy);
-               else if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
-                   || __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
-                       pr_err("%s: Failed to start governor for policy: %p\n",
-                               __func__, policy);
+               } else {
+                       down_write(&policy->rwsem);
+                       ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
+                       if (!ret)
+                               cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                       up_write(&policy->rwsem);
+
+                       if (ret)
+                               pr_err("%s: Failed to start governor for policy: %p\n",
+                                      __func__, policy);
+               }
        }
 
        /*
@@ -1878,8 +1877,7 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void)
        return NULL;
 }
 
-static int __cpufreq_governor(struct cpufreq_policy *policy,
-                                       unsigned int event)
+static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
 {
        int ret;
 
@@ -1913,21 +1911,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 
        pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
 
-       mutex_lock(&cpufreq_governor_lock);
-       if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
-           || (!policy->governor_enabled
-           && (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) {
-               mutex_unlock(&cpufreq_governor_lock);
-               return -EBUSY;
-       }
-
-       if (event == CPUFREQ_GOV_STOP)
-               policy->governor_enabled = false;
-       else if (event == CPUFREQ_GOV_START)
-               policy->governor_enabled = true;
-
-       mutex_unlock(&cpufreq_governor_lock);
-
        ret = policy->governor->governor(policy, event);
 
        if (!ret) {
@@ -1935,14 +1918,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                        policy->governor->initialized++;
                else if (event == CPUFREQ_GOV_POLICY_EXIT)
                        policy->governor->initialized--;
-       } else {
-               /* Restore original values */
-               mutex_lock(&cpufreq_governor_lock);
-               if (event == CPUFREQ_GOV_STOP)
-                       policy->governor_enabled = true;
-               else if (event == CPUFREQ_GOV_START)
-                       policy->governor_enabled = false;
-               mutex_unlock(&cpufreq_governor_lock);
        }
 
        if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) ||
@@ -2097,7 +2072,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        old_gov = policy->governor;
        /* end old governor */
        if (old_gov) {
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_STOP);
                if (ret) {
                        /* This can happen due to race with other operations */
                        pr_debug("%s: Failed to Stop Governor: %s (%d)\n",
@@ -2105,10 +2080,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
                        return ret;
                }
 
-               up_write(&policy->rwsem);
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-               down_write(&policy->rwsem);
-
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
                if (ret) {
                        pr_err("%s: Failed to Exit Governor: %s (%d)\n",
                               __func__, old_gov->name, ret);
@@ -2118,32 +2090,30 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
        /* start new governor */
        policy->governor = new_policy->governor;
-       ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
+       ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
        if (!ret) {
-               ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
+               ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
                if (!ret)
                        goto out;
 
-               up_write(&policy->rwsem);
-               __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
-               down_write(&policy->rwsem);
+               cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
        }
 
        /* new governor failed, so re-start old one */
        pr_debug("starting governor %s failed\n", policy->governor->name);
        if (old_gov) {
                policy->governor = old_gov;
-               if (__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
+               if (cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
                        policy->governor = NULL;
                else
-                       __cpufreq_governor(policy, CPUFREQ_GOV_START);
+                       cpufreq_governor(policy, CPUFREQ_GOV_START);
        }
 
        return ret;
 
  out:
        pr_debug("governor: change or update limits\n");
-       return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+       return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 }
 
 /**
@@ -2210,11 +2180,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                break;
 
        case CPU_DOWN_PREPARE:
-               cpufreq_offline_prepare(cpu);
-               break;
-
-       case CPU_POST_DEAD:
-               cpufreq_offline_finish(cpu);
+               cpufreq_offline(cpu);
                break;
 
        case CPU_DOWN_FAILED:
@@ -2247,8 +2213,11 @@ static int cpufreq_boost_set_sw(int state)
                                       __func__);
                                break;
                        }
+
+                       down_write(&policy->rwsem);
                        policy->user_policy.max = policy->max;
-                       __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                       cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+                       up_write(&policy->rwsem);
                }
        }