diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2013-09-12 07:36:33 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-09-17 18:01:27 -0400 |
commit | 9c8f1ee40b6368e6b2775c9c9f816e2a5dca3c07 (patch) | |
tree | 40ecbfa5c590cb9b04f13ec9f62ac6a209233834 /drivers | |
parent | 272b98c6455f00884f0350f775c5342358ebb73f (diff) |
cpufreq: Clear policy->cpus bits in __cpufreq_remove_dev_finish()
This broke after a recent change "cedb70a cpufreq: Split __cpufreq_remove_dev()
into two parts" from Srivatsa.
Consider a scenario where we have two CPUs in a policy (0 & 1) and we are
removing CPU 1. On the call to __cpufreq_remove_dev_prepare() we have cleared 1
from policy->cpus and now on a call to __cpufreq_remove_dev_finish() we read
cpumask_weight of policy->cpus, which will come as 1 and this code will behave
as if we are removing the last CPU from policy :)
Fix it by clearing the CPU mask in __cpufreq_remove_dev_finish() instead of
__cpufreq_remove_dev_prepare().
Tested-by: Stephen Warren <swarren@wwwdotorg.org>
Reviewed-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 43c24aa756f6..dbfe219667d3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1125,7 +1125,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, | |||
1125 | int ret; | 1125 | int ret; |
1126 | 1126 | ||
1127 | /* first sibling now owns the new sysfs dir */ | 1127 | /* first sibling now owns the new sysfs dir */ |
1128 | cpu_dev = get_cpu_device(cpumask_first(policy->cpus)); | 1128 | cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); |
1129 | 1129 | ||
1130 | /* Don't touch sysfs files during light-weight tear-down */ | 1130 | /* Don't touch sysfs files during light-weight tear-down */ |
1131 | if (frozen) | 1131 | if (frozen) |
@@ -1189,12 +1189,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1189 | policy->governor->name, CPUFREQ_NAME_LEN); | 1189 | policy->governor->name, CPUFREQ_NAME_LEN); |
1190 | #endif | 1190 | #endif |
1191 | 1191 | ||
1192 | WARN_ON(lock_policy_rwsem_write(cpu)); | 1192 | lock_policy_rwsem_read(cpu); |
1193 | cpus = cpumask_weight(policy->cpus); | 1193 | cpus = cpumask_weight(policy->cpus); |
1194 | 1194 | unlock_policy_rwsem_read(cpu); | |
1195 | if (cpus > 1) | ||
1196 | cpumask_clear_cpu(cpu, policy->cpus); | ||
1197 | unlock_policy_rwsem_write(cpu); | ||
1198 | 1195 | ||
1199 | if (cpu != policy->cpu) { | 1196 | if (cpu != policy->cpu) { |
1200 | if (!frozen) | 1197 | if (!frozen) |
@@ -1237,9 +1234,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev, | |||
1237 | return -EINVAL; | 1234 | return -EINVAL; |
1238 | } | 1235 | } |
1239 | 1236 | ||
1240 | lock_policy_rwsem_read(cpu); | 1237 | WARN_ON(lock_policy_rwsem_write(cpu)); |
1241 | cpus = cpumask_weight(policy->cpus); | 1238 | cpus = cpumask_weight(policy->cpus); |
1242 | unlock_policy_rwsem_read(cpu); | 1239 | |
1240 | if (cpus > 1) | ||
1241 | cpumask_clear_cpu(cpu, policy->cpus); | ||
1242 | unlock_policy_rwsem_write(cpu); | ||
1243 | 1243 | ||
1244 | /* If cpu is last user of policy, free policy */ | 1244 | /* If cpu is last user of policy, free policy */ |
1245 | if (cpus == 1) { | 1245 | if (cpus == 1) { |