diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 43c24aa756f6..04548f7023af 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -952,9 +952,20 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) | |||
952 | if (cpu == policy->cpu) | 952 | if (cpu == policy->cpu) |
953 | return; | 953 | return; |
954 | 954 | ||
955 | /* | ||
956 | * Take direct locks as lock_policy_rwsem_write wouldn't work here. | ||
957 | * Also lock for last cpu is enough here as contention will happen only | ||
958 | * after policy->cpu is changed and after it is changed, other threads | ||
959 | * will try to acquire lock for new cpu. And policy is already updated | ||
960 | * by then. | ||
961 | */ | ||
962 | down_write(&per_cpu(cpu_policy_rwsem, policy->cpu)); | ||
963 | |||
955 | policy->last_cpu = policy->cpu; | 964 | policy->last_cpu = policy->cpu; |
956 | policy->cpu = cpu; | 965 | policy->cpu = cpu; |
957 | 966 | ||
967 | up_write(&per_cpu(cpu_policy_rwsem, policy->last_cpu)); | ||
968 | |||
958 | #ifdef CONFIG_CPU_FREQ_TABLE | 969 | #ifdef CONFIG_CPU_FREQ_TABLE |
959 | cpufreq_frequency_table_update_policy_cpu(policy); | 970 | cpufreq_frequency_table_update_policy_cpu(policy); |
960 | #endif | 971 | #endif |
@@ -1125,7 +1136,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, | |||
1125 | int ret; | 1136 | int ret; |
1126 | 1137 | ||
1127 | /* first sibling now owns the new sysfs dir */ | 1138 | /* first sibling now owns the new sysfs dir */ |
1128 | cpu_dev = get_cpu_device(cpumask_first(policy->cpus)); | 1139 | cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); |
1129 | 1140 | ||
1130 | /* Don't touch sysfs files during light-weight tear-down */ | 1141 | /* Don't touch sysfs files during light-weight tear-down */ |
1131 | if (frozen) | 1142 | if (frozen) |
@@ -1189,12 +1200,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1189 | policy->governor->name, CPUFREQ_NAME_LEN); | 1200 | policy->governor->name, CPUFREQ_NAME_LEN); |
1190 | #endif | 1201 | #endif |
1191 | 1202 | ||
1192 | WARN_ON(lock_policy_rwsem_write(cpu)); | 1203 | lock_policy_rwsem_read(cpu); |
1193 | cpus = cpumask_weight(policy->cpus); | 1204 | cpus = cpumask_weight(policy->cpus); |
1194 | 1205 | unlock_policy_rwsem_read(cpu); | |
1195 | if (cpus > 1) | ||
1196 | cpumask_clear_cpu(cpu, policy->cpus); | ||
1197 | unlock_policy_rwsem_write(cpu); | ||
1198 | 1206 | ||
1199 | if (cpu != policy->cpu) { | 1207 | if (cpu != policy->cpu) { |
1200 | if (!frozen) | 1208 | if (!frozen) |
@@ -1203,9 +1211,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1203 | 1211 | ||
1204 | new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); | 1212 | new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen); |
1205 | if (new_cpu >= 0) { | 1213 | if (new_cpu >= 0) { |
1206 | WARN_ON(lock_policy_rwsem_write(cpu)); | ||
1207 | update_policy_cpu(policy, new_cpu); | 1214 | update_policy_cpu(policy, new_cpu); |
1208 | unlock_policy_rwsem_write(cpu); | ||
1209 | 1215 | ||
1210 | if (!frozen) { | 1216 | if (!frozen) { |
1211 | pr_debug("%s: policy Kobject moved to cpu: %d " | 1217 | pr_debug("%s: policy Kobject moved to cpu: %d " |
@@ -1237,9 +1243,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev, | |||
1237 | return -EINVAL; | 1243 | return -EINVAL; |
1238 | } | 1244 | } |
1239 | 1245 | ||
1240 | lock_policy_rwsem_read(cpu); | 1246 | WARN_ON(lock_policy_rwsem_write(cpu)); |
1241 | cpus = cpumask_weight(policy->cpus); | 1247 | cpus = cpumask_weight(policy->cpus); |
1242 | unlock_policy_rwsem_read(cpu); | 1248 | |
1249 | if (cpus > 1) | ||
1250 | cpumask_clear_cpu(cpu, policy->cpus); | ||
1251 | unlock_policy_rwsem_write(cpu); | ||
1243 | 1252 | ||
1244 | /* If cpu is last user of policy, free policy */ | 1253 | /* If cpu is last user of policy, free policy */ |
1245 | if (cpus == 1) { | 1254 | if (cpus == 1) { |
@@ -1451,6 +1460,9 @@ unsigned int cpufreq_get(unsigned int cpu) | |||
1451 | { | 1460 | { |
1452 | unsigned int ret_freq = 0; | 1461 | unsigned int ret_freq = 0; |
1453 | 1462 | ||
1463 | if (cpufreq_disabled() || !cpufreq_driver) | ||
1464 | return -ENOENT; | ||
1465 | |||
1454 | if (!down_read_trylock(&cpufreq_rwsem)) | 1466 | if (!down_read_trylock(&cpufreq_rwsem)) |
1455 | return 0; | 1467 | return 0; |
1456 | 1468 | ||
@@ -2095,7 +2107,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) | |||
2095 | write_lock_irqsave(&cpufreq_driver_lock, flags); | 2107 | write_lock_irqsave(&cpufreq_driver_lock, flags); |
2096 | if (cpufreq_driver) { | 2108 | if (cpufreq_driver) { |
2097 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2109 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
2098 | return -EBUSY; | 2110 | return -EEXIST; |
2099 | } | 2111 | } |
2100 | cpufreq_driver = driver_data; | 2112 | cpufreq_driver = driver_data; |
2101 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 2113 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |