diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 78 |
1 files changed, 35 insertions, 43 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index aed2b0cb83dc..d9fdeddcef96 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1076,10 +1076,20 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) | |||
1076 | kfree(policy); | 1076 | kfree(policy); |
1077 | } | 1077 | } |
1078 | 1078 | ||
1079 | static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) | 1079 | static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu, |
1080 | struct device *cpu_dev) | ||
1080 | { | 1081 | { |
1082 | int ret; | ||
1083 | |||
1081 | if (WARN_ON(cpu == policy->cpu)) | 1084 | if (WARN_ON(cpu == policy->cpu)) |
1082 | return; | 1085 | return 0; |
1086 | |||
1087 | /* Move kobject to the new policy->cpu */ | ||
1088 | ret = kobject_move(&policy->kobj, &cpu_dev->kobj); | ||
1089 | if (ret) { | ||
1090 | pr_err("%s: Failed to move kobj: %d\n", __func__, ret); | ||
1091 | return ret; | ||
1092 | } | ||
1083 | 1093 | ||
1084 | down_write(&policy->rwsem); | 1094 | down_write(&policy->rwsem); |
1085 | 1095 | ||
@@ -1090,6 +1100,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) | |||
1090 | 1100 | ||
1091 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, | 1101 | blocking_notifier_call_chain(&cpufreq_policy_notifier_list, |
1092 | CPUFREQ_UPDATE_POLICY_CPU, policy); | 1102 | CPUFREQ_UPDATE_POLICY_CPU, policy); |
1103 | |||
1104 | return 0; | ||
1093 | } | 1105 | } |
1094 | 1106 | ||
1095 | static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | 1107 | static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) |
@@ -1154,7 +1166,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
1154 | * by invoking update_policy_cpu(). | 1166 | * by invoking update_policy_cpu(). |
1155 | */ | 1167 | */ |
1156 | if (recover_policy && cpu != policy->cpu) | 1168 | if (recover_policy && cpu != policy->cpu) |
1157 | update_policy_cpu(policy, cpu); | 1169 | WARN_ON(update_policy_cpu(policy, cpu, dev)); |
1158 | else | 1170 | else |
1159 | policy->cpu = cpu; | 1171 | policy->cpu = cpu; |
1160 | 1172 | ||
@@ -1307,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) | |||
1307 | return __cpufreq_add_dev(dev, sif); | 1319 | return __cpufreq_add_dev(dev, sif); |
1308 | } | 1320 | } |
1309 | 1321 | ||
1310 | static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy, | ||
1311 | unsigned int old_cpu) | ||
1312 | { | ||
1313 | struct device *cpu_dev; | ||
1314 | int ret; | ||
1315 | |||
1316 | /* first sibling now owns the new sysfs dir */ | ||
1317 | cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu)); | ||
1318 | |||
1319 | sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); | ||
1320 | ret = kobject_move(&policy->kobj, &cpu_dev->kobj); | ||
1321 | if (ret) { | ||
1322 | pr_err("%s: Failed to move kobj: %d\n", __func__, ret); | ||
1323 | |||
1324 | down_write(&policy->rwsem); | ||
1325 | cpumask_set_cpu(old_cpu, policy->cpus); | ||
1326 | up_write(&policy->rwsem); | ||
1327 | |||
1328 | ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj, | ||
1329 | "cpufreq"); | ||
1330 | |||
1331 | return -EINVAL; | ||
1332 | } | ||
1333 | |||
1334 | return cpu_dev->id; | ||
1335 | } | ||
1336 | |||
1337 | static int __cpufreq_remove_dev_prepare(struct device *dev, | 1322 | static int __cpufreq_remove_dev_prepare(struct device *dev, |
1338 | struct subsys_interface *sif) | 1323 | struct subsys_interface *sif) |
1339 | { | 1324 | { |
1340 | unsigned int cpu = dev->id, cpus; | 1325 | unsigned int cpu = dev->id, cpus; |
1341 | int new_cpu, ret; | 1326 | int ret; |
1342 | unsigned long flags; | 1327 | unsigned long flags; |
1343 | struct cpufreq_policy *policy; | 1328 | struct cpufreq_policy *policy; |
1344 | 1329 | ||
@@ -1378,14 +1363,23 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, | |||
1378 | if (cpu != policy->cpu) { | 1363 | if (cpu != policy->cpu) { |
1379 | sysfs_remove_link(&dev->kobj, "cpufreq"); | 1364 | sysfs_remove_link(&dev->kobj, "cpufreq"); |
1380 | } else if (cpus > 1) { | 1365 | } else if (cpus > 1) { |
1381 | new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); | 1366 | /* Nominate new CPU */ |
1382 | if (new_cpu >= 0) { | 1367 | int new_cpu = cpumask_any_but(policy->cpus, cpu); |
1383 | update_policy_cpu(policy, new_cpu); | 1368 | struct device *cpu_dev = get_cpu_device(new_cpu); |
1384 | 1369 | ||
1385 | if (!cpufreq_suspended) | 1370 | sysfs_remove_link(&cpu_dev->kobj, "cpufreq"); |
1386 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", | 1371 | ret = update_policy_cpu(policy, new_cpu, cpu_dev); |
1387 | __func__, new_cpu, cpu); | 1372 | if (ret) { |
1373 | if (sysfs_create_link(&cpu_dev->kobj, &policy->kobj, | ||
1374 | "cpufreq")) | ||
1375 | pr_err("%s: Failed to restore kobj link to cpu:%d\n", | ||
1376 | __func__, cpu_dev->id); | ||
1377 | return ret; | ||
1388 | } | 1378 | } |
1379 | |||
1380 | if (!cpufreq_suspended) | ||
1381 | pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", | ||
1382 | __func__, new_cpu, cpu); | ||
1389 | } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) { | 1383 | } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) { |
1390 | cpufreq_driver->stop_cpu(policy); | 1384 | cpufreq_driver->stop_cpu(policy); |
1391 | } | 1385 | } |
@@ -2242,10 +2236,8 @@ int cpufreq_update_policy(unsigned int cpu) | |||
2242 | struct cpufreq_policy new_policy; | 2236 | struct cpufreq_policy new_policy; |
2243 | int ret; | 2237 | int ret; |
2244 | 2238 | ||
2245 | if (!policy) { | 2239 | if (!policy) |
2246 | ret = -ENODEV; | 2240 | return -ENODEV; |
2247 | goto no_policy; | ||
2248 | } | ||
2249 | 2241 | ||
2250 | down_write(&policy->rwsem); | 2242 | down_write(&policy->rwsem); |
2251 | 2243 | ||
@@ -2264,7 +2256,7 @@ int cpufreq_update_policy(unsigned int cpu) | |||
2264 | new_policy.cur = cpufreq_driver->get(cpu); | 2256 | new_policy.cur = cpufreq_driver->get(cpu); |
2265 | if (WARN_ON(!new_policy.cur)) { | 2257 | if (WARN_ON(!new_policy.cur)) { |
2266 | ret = -EIO; | 2258 | ret = -EIO; |
2267 | goto no_policy; | 2259 | goto unlock; |
2268 | } | 2260 | } |
2269 | 2261 | ||
2270 | if (!policy->cur) { | 2262 | if (!policy->cur) { |
@@ -2279,10 +2271,10 @@ int cpufreq_update_policy(unsigned int cpu) | |||
2279 | 2271 | ||
2280 | ret = cpufreq_set_policy(policy, &new_policy); | 2272 | ret = cpufreq_set_policy(policy, &new_policy); |
2281 | 2273 | ||
2274 | unlock: | ||
2282 | up_write(&policy->rwsem); | 2275 | up_write(&policy->rwsem); |
2283 | 2276 | ||
2284 | cpufreq_cpu_put(policy); | 2277 | cpufreq_cpu_put(policy); |
2285 | no_policy: | ||
2286 | return ret; | 2278 | return ret; |
2287 | } | 2279 | } |
2288 | EXPORT_SYMBOL(cpufreq_update_policy); | 2280 | EXPORT_SYMBOL(cpufreq_update_policy); |