aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorXiaoguang Chen <chenxg@marvell.com>2013-06-19 03:00:07 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-20 18:56:04 -0400
commit95731ebb114c5f0c028459388560fc2a72fe5049 (patch)
tree7e1acaa2d116dad92e83355eb36dc26831d1accf /drivers/cpufreq
parentd1922f02562fe230396400e466e6e38dfeb072f5 (diff)
cpufreq: Fix governor start/stop race condition
Cpufreq governors' stop and start operations should be carried out in sequence. Otherwise, there will be unexpected behavior, like in the example below. Suppose there are 4 CPUs and policy->cpu=CPU0, CPU1/2/3 are linked to CPU0. The normal sequence is: 1) Current governor is userspace. An application tries to set the governor to ondemand. It will call __cpufreq_set_policy() in which it will stop the userspace governor and then start the ondemand governor. 2) Current governor is userspace. The online of CPU3 runs on CPU0. It will call cpufreq_add_policy_cpu() in which it will first stop the userspace governor, and then start it again. If the sequence of the above two cases interleaves, it becomes: 1) Application stops userspace governor 2) Hotplug stops userspace governor which is a problem, because the governor shouldn't be stopped twice in a row. What happens next is: 3) Application starts ondemand governor 4) Hotplug starts a governor In step 4, the hotplug is supposed to start the userspace governor, but now the governor has been changed by the application to ondemand, so the ondemand governor is started once again, which is incorrect. The solution is to prevent policy governors from being stopped multiple times in a row. A governor should only be stopped once for one policy. After it has been stopped, no more governor stop operations should be executed. Also add a mutex to serialize governor operations. [rjw: Changelog. And you owe me a beverage of my choice.] Signed-off-by: Xiaoguang Chen <chenxg@marvell.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f8c28607ccd6..43cf60832468 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -49,6 +49,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
49static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor); 49static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
50#endif 50#endif
51static DEFINE_RWLOCK(cpufreq_driver_lock); 51static DEFINE_RWLOCK(cpufreq_driver_lock);
52static DEFINE_MUTEX(cpufreq_governor_lock);
52 53
53/* 54/*
54 * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure 55 * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -1635,6 +1636,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
1635 1636
1636 pr_debug("__cpufreq_governor for CPU %u, event %u\n", 1637 pr_debug("__cpufreq_governor for CPU %u, event %u\n",
1637 policy->cpu, event); 1638 policy->cpu, event);
1639
1640 mutex_lock(&cpufreq_governor_lock);
1641 if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
1642 (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
1643 mutex_unlock(&cpufreq_governor_lock);
1644 return -EBUSY;
1645 }
1646
1647 if (event == CPUFREQ_GOV_STOP)
1648 policy->governor_enabled = false;
1649 else if (event == CPUFREQ_GOV_START)
1650 policy->governor_enabled = true;
1651
1652 mutex_unlock(&cpufreq_governor_lock);
1653
1638 ret = policy->governor->governor(policy, event); 1654 ret = policy->governor->governor(policy, event);
1639 1655
1640 if (!ret) { 1656 if (!ret) {
@@ -1642,6 +1658,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
1642 policy->governor->initialized++; 1658 policy->governor->initialized++;
1643 else if (event == CPUFREQ_GOV_POLICY_EXIT) 1659 else if (event == CPUFREQ_GOV_POLICY_EXIT)
1644 policy->governor->initialized--; 1660 policy->governor->initialized--;
1661 } else {
1662 /* Restore original values */
1663 mutex_lock(&cpufreq_governor_lock);
1664 if (event == CPUFREQ_GOV_STOP)
1665 policy->governor_enabled = true;
1666 else if (event == CPUFREQ_GOV_START)
1667 policy->governor_enabled = false;
1668 mutex_unlock(&cpufreq_governor_lock);
1645 } 1669 }
1646 1670
1647 /* we keep one module reference alive for 1671 /* we keep one module reference alive for