diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 100 |
1 files changed, 73 insertions, 27 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e10922709d13..7ea217c88c2e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -34,11 +34,6 @@ | |||
34 | 34 | ||
35 | static LIST_HEAD(cpufreq_policy_list); | 35 | static LIST_HEAD(cpufreq_policy_list); |
36 | 36 | ||
37 | static inline bool policy_is_inactive(struct cpufreq_policy *policy) | ||
38 | { | ||
39 | return cpumask_empty(policy->cpus); | ||
40 | } | ||
41 | |||
42 | /* Macros to iterate over CPU policies */ | 37 | /* Macros to iterate over CPU policies */ |
43 | #define for_each_suitable_policy(__policy, __active) \ | 38 | #define for_each_suitable_policy(__policy, __active) \ |
44 | list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) \ | 39 | list_for_each_entry(__policy, &cpufreq_policy_list, policy_list) \ |
@@ -250,6 +245,51 @@ void cpufreq_cpu_put(struct cpufreq_policy *policy) | |||
250 | } | 245 | } |
251 | EXPORT_SYMBOL_GPL(cpufreq_cpu_put); | 246 | EXPORT_SYMBOL_GPL(cpufreq_cpu_put); |
252 | 247 | ||
248 | /** | ||
249 | * cpufreq_cpu_release - Unlock a policy and decrement its usage counter. | ||
250 | * @policy: cpufreq policy returned by cpufreq_cpu_acquire(). | ||
251 | */ | ||
252 | void cpufreq_cpu_release(struct cpufreq_policy *policy) | ||
253 | { | ||
254 | if (WARN_ON(!policy)) | ||
255 | return; | ||
256 | |||
257 | lockdep_assert_held(&policy->rwsem); | ||
258 | |||
259 | up_write(&policy->rwsem); | ||
260 | |||
261 | cpufreq_cpu_put(policy); | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * cpufreq_cpu_acquire - Find policy for a CPU, mark it as busy and lock it. | ||
266 | * @cpu: CPU to find the policy for. | ||
267 | * | ||
268 | * Call cpufreq_cpu_get() to get a reference on the cpufreq policy for @cpu and | ||
269 | * if the policy returned by it is not NULL, acquire its rwsem for writing. | ||
270 | * Return the policy if it is active or release it and return NULL otherwise. | ||
271 | * | ||
272 | * The policy returned by this function has to be released with the help of | ||
273 | * cpufreq_cpu_release() in order to release its rwsem and balance its usage | ||
274 | * counter properly. | ||
275 | */ | ||
276 | struct cpufreq_policy *cpufreq_cpu_acquire(unsigned int cpu) | ||
277 | { | ||
278 | struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); | ||
279 | |||
280 | if (!policy) | ||
281 | return NULL; | ||
282 | |||
283 | down_write(&policy->rwsem); | ||
284 | |||
285 | if (policy_is_inactive(policy)) { | ||
286 | cpufreq_cpu_release(policy); | ||
287 | return NULL; | ||
288 | } | ||
289 | |||
290 | return policy; | ||
291 | } | ||
292 | |||
253 | /********************************************************************* | 293 | /********************************************************************* |
254 | * EXTERNALLY AFFECTING FREQUENCY CHANGES * | 294 | * EXTERNALLY AFFECTING FREQUENCY CHANGES * |
255 | *********************************************************************/ | 295 | *********************************************************************/ |
@@ -669,9 +709,6 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf) | |||
669 | return ret; | 709 | return ret; |
670 | } | 710 | } |
671 | 711 | ||
672 | static int cpufreq_set_policy(struct cpufreq_policy *policy, | ||
673 | struct cpufreq_policy *new_policy); | ||
674 | |||
675 | /** | 712 | /** |
676 | * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access | 713 | * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access |
677 | */ | 714 | */ |
@@ -857,11 +894,9 @@ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) | |||
857 | { | 894 | { |
858 | unsigned int limit; | 895 | unsigned int limit; |
859 | int ret; | 896 | int ret; |
860 | if (cpufreq_driver->bios_limit) { | 897 | ret = cpufreq_driver->bios_limit(policy->cpu, &limit); |
861 | ret = cpufreq_driver->bios_limit(policy->cpu, &limit); | 898 | if (!ret) |
862 | if (!ret) | 899 | return sprintf(buf, "%u\n", limit); |
863 | return sprintf(buf, "%u\n", limit); | ||
864 | } | ||
865 | return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); | 900 | return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); |
866 | } | 901 | } |
867 | 902 | ||
@@ -1098,6 +1133,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) | |||
1098 | cpufreq_global_kobject, "policy%u", cpu); | 1133 | cpufreq_global_kobject, "policy%u", cpu); |
1099 | if (ret) { | 1134 | if (ret) { |
1100 | pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret); | 1135 | pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret); |
1136 | kobject_put(&policy->kobj); | ||
1101 | goto err_free_real_cpus; | 1137 | goto err_free_real_cpus; |
1102 | } | 1138 | } |
1103 | 1139 | ||
@@ -1550,7 +1586,7 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy) | |||
1550 | { | 1586 | { |
1551 | unsigned int ret_freq = 0; | 1587 | unsigned int ret_freq = 0; |
1552 | 1588 | ||
1553 | if (unlikely(policy_is_inactive(policy)) || !cpufreq_driver->get) | 1589 | if (unlikely(policy_is_inactive(policy))) |
1554 | return ret_freq; | 1590 | return ret_freq; |
1555 | 1591 | ||
1556 | ret_freq = cpufreq_driver->get(policy->cpu); | 1592 | ret_freq = cpufreq_driver->get(policy->cpu); |
@@ -1588,7 +1624,8 @@ unsigned int cpufreq_get(unsigned int cpu) | |||
1588 | 1624 | ||
1589 | if (policy) { | 1625 | if (policy) { |
1590 | down_read(&policy->rwsem); | 1626 | down_read(&policy->rwsem); |
1591 | ret_freq = __cpufreq_get(policy); | 1627 | if (cpufreq_driver->get) |
1628 | ret_freq = __cpufreq_get(policy); | ||
1592 | up_read(&policy->rwsem); | 1629 | up_read(&policy->rwsem); |
1593 | 1630 | ||
1594 | cpufreq_cpu_put(policy); | 1631 | cpufreq_cpu_put(policy); |
@@ -2229,8 +2266,8 @@ EXPORT_SYMBOL(cpufreq_get_policy); | |||
2229 | * | 2266 | * |
2230 | * The cpuinfo part of @policy is not updated by this function. | 2267 | * The cpuinfo part of @policy is not updated by this function. |
2231 | */ | 2268 | */ |
2232 | static int cpufreq_set_policy(struct cpufreq_policy *policy, | 2269 | int cpufreq_set_policy(struct cpufreq_policy *policy, |
2233 | struct cpufreq_policy *new_policy) | 2270 | struct cpufreq_policy *new_policy) |
2234 | { | 2271 | { |
2235 | struct cpufreq_governor *old_gov; | 2272 | struct cpufreq_governor *old_gov; |
2236 | int ret; | 2273 | int ret; |
@@ -2337,17 +2374,12 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, | |||
2337 | */ | 2374 | */ |
2338 | void cpufreq_update_policy(unsigned int cpu) | 2375 | void cpufreq_update_policy(unsigned int cpu) |
2339 | { | 2376 | { |
2340 | struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); | 2377 | struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu); |
2341 | struct cpufreq_policy new_policy; | 2378 | struct cpufreq_policy new_policy; |
2342 | 2379 | ||
2343 | if (!policy) | 2380 | if (!policy) |
2344 | return; | 2381 | return; |
2345 | 2382 | ||
2346 | down_write(&policy->rwsem); | ||
2347 | |||
2348 | if (policy_is_inactive(policy)) | ||
2349 | goto unlock; | ||
2350 | |||
2351 | /* | 2383 | /* |
2352 | * BIOS might change freq behind our back | 2384 | * BIOS might change freq behind our back |
2353 | * -> ask driver for current freq and notify governors about a change | 2385 | * -> ask driver for current freq and notify governors about a change |
@@ -2364,12 +2396,26 @@ void cpufreq_update_policy(unsigned int cpu) | |||
2364 | cpufreq_set_policy(policy, &new_policy); | 2396 | cpufreq_set_policy(policy, &new_policy); |
2365 | 2397 | ||
2366 | unlock: | 2398 | unlock: |
2367 | up_write(&policy->rwsem); | 2399 | cpufreq_cpu_release(policy); |
2368 | |||
2369 | cpufreq_cpu_put(policy); | ||
2370 | } | 2400 | } |
2371 | EXPORT_SYMBOL(cpufreq_update_policy); | 2401 | EXPORT_SYMBOL(cpufreq_update_policy); |
2372 | 2402 | ||
2403 | /** | ||
2404 | * cpufreq_update_limits - Update policy limits for a given CPU. | ||
2405 | * @cpu: CPU to update the policy limits for. | ||
2406 | * | ||
2407 | * Invoke the driver's ->update_limits callback if present or call | ||
2408 | * cpufreq_update_policy() for @cpu. | ||
2409 | */ | ||
2410 | void cpufreq_update_limits(unsigned int cpu) | ||
2411 | { | ||
2412 | if (cpufreq_driver->update_limits) | ||
2413 | cpufreq_driver->update_limits(cpu); | ||
2414 | else | ||
2415 | cpufreq_update_policy(cpu); | ||
2416 | } | ||
2417 | EXPORT_SYMBOL_GPL(cpufreq_update_limits); | ||
2418 | |||
2373 | /********************************************************************* | 2419 | /********************************************************************* |
2374 | * BOOST * | 2420 | * BOOST * |
2375 | *********************************************************************/ | 2421 | *********************************************************************/ |
@@ -2426,7 +2472,7 @@ int cpufreq_boost_trigger_state(int state) | |||
2426 | 2472 | ||
2427 | static bool cpufreq_boost_supported(void) | 2473 | static bool cpufreq_boost_supported(void) |
2428 | { | 2474 | { |
2429 | return likely(cpufreq_driver) && cpufreq_driver->set_boost; | 2475 | return cpufreq_driver->set_boost; |
2430 | } | 2476 | } |
2431 | 2477 | ||
2432 | static int create_boost_sysfs_file(void) | 2478 | static int create_boost_sysfs_file(void) |