Merge tag 'v3.10.37' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / cpufreq / cpufreq.c
index 2d53f47d1747360b8968c7c308c0f975777ef9ab..66f6cf5064ece85d201731b58757b594206b2bb7 100644 (file)
@@ -46,6 +46,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
 static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
 #endif
 static DEFINE_RWLOCK(cpufreq_driver_lock);
+static DEFINE_MUTEX(cpufreq_governor_lock);
 
 /*
  * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -1075,14 +1076,11 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
                                __func__, cpu_dev->id, cpu);
        }
 
-       if ((cpus == 1) && (cpufreq_driver->target))
-               __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-       cpufreq_cpu_put(data);
-
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
+               if (cpufreq_driver->target)
+                       __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
                lock_policy_rwsem_read(cpu);
                kobj = &data->kobj;
                cmp = &data->kobj_unregister;
@@ -1103,9 +1101,13 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
                free_cpumask_var(data->related_cpus);
                free_cpumask_var(data->cpus);
                kfree(data);
-       } else if (cpufreq_driver->target) {
-               __cpufreq_governor(data, CPUFREQ_GOV_START);
-               __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+       } else {
+               pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+               cpufreq_cpu_put(data);
+               if (cpufreq_driver->target) {
+                       __cpufreq_governor(data, CPUFREQ_GOV_START);
+                       __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               }
        }
 
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
@@ -1562,6 +1564,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 
        pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
+
+       mutex_lock(&cpufreq_governor_lock);
+       if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
+           (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
+               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) {
@@ -1569,6 +1586,14 @@ 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);
        }
 
        /* we keep one module reference alive for
@@ -1837,13 +1862,15 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
        if (dev) {
                switch (action) {
                case CPU_ONLINE:
+               case CPU_ONLINE_FROZEN:
                        cpufreq_add_dev(dev, NULL);
                        break;
                case CPU_DOWN_PREPARE:
-               case CPU_UP_CANCELED_FROZEN:
+               case CPU_DOWN_PREPARE_FROZEN:
                        __cpufreq_remove_dev(dev, NULL);
                        break;
                case CPU_DOWN_FAILED:
+               case CPU_DOWN_FAILED_FROZEN:
                        cpufreq_add_dev(dev, NULL);
                        break;
                }