diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 110 |
1 files changed, 56 insertions, 54 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7a511479ae29..9582de1c9cad 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -35,8 +35,8 @@ | |||
35 | * level driver of CPUFreq support, and its spinlock. This lock | 35 | * level driver of CPUFreq support, and its spinlock. This lock |
36 | * also protects the cpufreq_cpu_data array. | 36 | * also protects the cpufreq_cpu_data array. |
37 | */ | 37 | */ |
38 | static struct cpufreq_driver *cpufreq_driver; | 38 | static struct cpufreq_driver *cpufreq_driver; |
39 | static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; | 39 | static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; |
40 | static DEFINE_SPINLOCK(cpufreq_driver_lock); | 40 | static DEFINE_SPINLOCK(cpufreq_driver_lock); |
41 | 41 | ||
42 | /* internal prototypes */ | 42 | /* internal prototypes */ |
@@ -50,15 +50,15 @@ static void handle_update(void *data); | |||
50 | * changes to devices when the CPU clock speed changes. | 50 | * changes to devices when the CPU clock speed changes. |
51 | * The mutex locks both lists. | 51 | * The mutex locks both lists. |
52 | */ | 52 | */ |
53 | static struct notifier_block *cpufreq_policy_notifier_list; | 53 | static struct notifier_block *cpufreq_policy_notifier_list; |
54 | static struct notifier_block *cpufreq_transition_notifier_list; | 54 | static struct notifier_block *cpufreq_transition_notifier_list; |
55 | static DECLARE_RWSEM (cpufreq_notifier_rwsem); | 55 | static DECLARE_RWSEM (cpufreq_notifier_rwsem); |
56 | 56 | ||
57 | 57 | ||
58 | static LIST_HEAD(cpufreq_governor_list); | 58 | static LIST_HEAD(cpufreq_governor_list); |
59 | static DEFINE_MUTEX (cpufreq_governor_mutex); | 59 | static DEFINE_MUTEX (cpufreq_governor_mutex); |
60 | 60 | ||
61 | struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) | 61 | struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) |
62 | { | 62 | { |
63 | struct cpufreq_policy *data; | 63 | struct cpufreq_policy *data; |
64 | unsigned long flags; | 64 | unsigned long flags; |
@@ -85,20 +85,19 @@ struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) | |||
85 | if (!kobject_get(&data->kobj)) | 85 | if (!kobject_get(&data->kobj)) |
86 | goto err_out_put_module; | 86 | goto err_out_put_module; |
87 | 87 | ||
88 | |||
89 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | 88 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); |
90 | |||
91 | return data; | 89 | return data; |
92 | 90 | ||
93 | err_out_put_module: | 91 | err_out_put_module: |
94 | module_put(cpufreq_driver->owner); | 92 | module_put(cpufreq_driver->owner); |
95 | err_out_unlock: | 93 | err_out_unlock: |
96 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | 94 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); |
97 | err_out: | 95 | err_out: |
98 | return NULL; | 96 | return NULL; |
99 | } | 97 | } |
100 | EXPORT_SYMBOL_GPL(cpufreq_cpu_get); | 98 | EXPORT_SYMBOL_GPL(cpufreq_cpu_get); |
101 | 99 | ||
100 | |||
102 | void cpufreq_cpu_put(struct cpufreq_policy *data) | 101 | void cpufreq_cpu_put(struct cpufreq_policy *data) |
103 | { | 102 | { |
104 | kobject_put(&data->kobj); | 103 | kobject_put(&data->kobj); |
@@ -229,44 +228,53 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { | |||
229 | 228 | ||
230 | 229 | ||
231 | /** | 230 | /** |
232 | * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition | 231 | * cpufreq_notify_transition - call notifier chain and adjust_jiffies |
232 | * on frequency transition. | ||
233 | * | 233 | * |
234 | * This function calls the transition notifiers and the "adjust_jiffies" function. It is called | 234 | * This function calls the transition notifiers and the "adjust_jiffies" |
235 | * twice on all CPU frequency changes that have external effects. | 235 | * function. It is called twice on all CPU frequency changes that have |
236 | * external effects. | ||
236 | */ | 237 | */ |
237 | void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) | 238 | void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) |
238 | { | 239 | { |
240 | struct cpufreq_policy *policy; | ||
241 | |||
239 | BUG_ON(irqs_disabled()); | 242 | BUG_ON(irqs_disabled()); |
240 | 243 | ||
241 | freqs->flags = cpufreq_driver->flags; | 244 | freqs->flags = cpufreq_driver->flags; |
242 | dprintk("notification %u of frequency transition to %u kHz\n", state, freqs->new); | 245 | dprintk("notification %u of frequency transition to %u kHz\n", |
246 | state, freqs->new); | ||
243 | 247 | ||
244 | down_read(&cpufreq_notifier_rwsem); | 248 | down_read(&cpufreq_notifier_rwsem); |
249 | |||
250 | policy = cpufreq_cpu_data[freqs->cpu]; | ||
245 | switch (state) { | 251 | switch (state) { |
252 | |||
246 | case CPUFREQ_PRECHANGE: | 253 | case CPUFREQ_PRECHANGE: |
247 | /* detect if the driver reported a value as "old frequency" which | 254 | /* detect if the driver reported a value as "old frequency" |
248 | * is not equal to what the cpufreq core thinks is "old frequency". | 255 | * which is not equal to what the cpufreq core thinks is |
256 | * "old frequency". | ||
249 | */ | 257 | */ |
250 | if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { | 258 | if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { |
251 | if ((likely(cpufreq_cpu_data[freqs->cpu])) && | 259 | if ((policy) && (policy->cpu == freqs->cpu) && |
252 | (likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu)) && | 260 | (policy->cur) && (policy->cur != freqs->old)) { |
253 | (likely(cpufreq_cpu_data[freqs->cpu]->cur)) && | 261 | dprintk(KERN_WARNING "Warning: CPU frequency is" |
254 | (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) | 262 | " %u, cpufreq assumed %u kHz.\n", |
255 | { | 263 | freqs->old, policy->cur); |
256 | dprintk(KERN_WARNING "Warning: CPU frequency is %u, " | 264 | freqs->old = policy->cur; |
257 | "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); | ||
258 | freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; | ||
259 | } | 265 | } |
260 | } | 266 | } |
261 | notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); | 267 | notifier_call_chain(&cpufreq_transition_notifier_list, |
268 | CPUFREQ_PRECHANGE, freqs); | ||
262 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); | 269 | adjust_jiffies(CPUFREQ_PRECHANGE, freqs); |
263 | break; | 270 | break; |
271 | |||
264 | case CPUFREQ_POSTCHANGE: | 272 | case CPUFREQ_POSTCHANGE: |
265 | adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); | 273 | adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); |
266 | notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); | 274 | notifier_call_chain(&cpufreq_transition_notifier_list, |
267 | if ((likely(cpufreq_cpu_data[freqs->cpu])) && | 275 | CPUFREQ_POSTCHANGE, freqs); |
268 | (likely(cpufreq_cpu_data[freqs->cpu]->cpu == freqs->cpu))) | 276 | if (likely(policy) && likely(policy->cpu == freqs->cpu)) |
269 | cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; | 277 | policy->cur = freqs->new; |
270 | break; | 278 | break; |
271 | } | 279 | } |
272 | up_read(&cpufreq_notifier_rwsem); | 280 | up_read(&cpufreq_notifier_rwsem); |
@@ -308,7 +316,7 @@ static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, | |||
308 | return 0; | 316 | return 0; |
309 | } | 317 | } |
310 | } | 318 | } |
311 | out: | 319 | out: |
312 | mutex_unlock(&cpufreq_governor_mutex); | 320 | mutex_unlock(&cpufreq_governor_mutex); |
313 | } | 321 | } |
314 | return -EINVAL; | 322 | return -EINVAL; |
@@ -415,7 +423,6 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, | |||
415 | return -EINVAL; | 423 | return -EINVAL; |
416 | 424 | ||
417 | ret = cpufreq_set_policy(&new_policy); | 425 | ret = cpufreq_set_policy(&new_policy); |
418 | |||
419 | return ret ? ret : count; | 426 | return ret ? ret : count; |
420 | } | 427 | } |
421 | 428 | ||
@@ -446,7 +453,7 @@ static ssize_t show_scaling_available_governors (struct cpufreq_policy * policy, | |||
446 | goto out; | 453 | goto out; |
447 | i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name); | 454 | i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name); |
448 | } | 455 | } |
449 | out: | 456 | out: |
450 | i += sprintf(&buf[i], "\n"); | 457 | i += sprintf(&buf[i], "\n"); |
451 | return i; | 458 | return i; |
452 | } | 459 | } |
@@ -789,7 +796,6 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) | |||
789 | kfree(data); | 796 | kfree(data); |
790 | 797 | ||
791 | cpufreq_debug_enable_ratelimit(); | 798 | cpufreq_debug_enable_ratelimit(); |
792 | |||
793 | return 0; | 799 | return 0; |
794 | } | 800 | } |
795 | 801 | ||
@@ -870,8 +876,7 @@ unsigned int cpufreq_get(unsigned int cpu) | |||
870 | 876 | ||
871 | ret = cpufreq_driver->get(cpu); | 877 | ret = cpufreq_driver->get(cpu); |
872 | 878 | ||
873 | if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) | 879 | if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { |
874 | { | ||
875 | /* verify no discrepancy between actual and saved value exists */ | 880 | /* verify no discrepancy between actual and saved value exists */ |
876 | if (unlikely(ret != policy->cur)) { | 881 | if (unlikely(ret != policy->cur)) { |
877 | cpufreq_out_of_sync(cpu, policy->cur, ret); | 882 | cpufreq_out_of_sync(cpu, policy->cur, ret); |
@@ -881,7 +886,7 @@ unsigned int cpufreq_get(unsigned int cpu) | |||
881 | 886 | ||
882 | mutex_unlock(&policy->lock); | 887 | mutex_unlock(&policy->lock); |
883 | 888 | ||
884 | out: | 889 | out: |
885 | cpufreq_cpu_put(policy); | 890 | cpufreq_cpu_put(policy); |
886 | 891 | ||
887 | return (ret); | 892 | return (ret); |
@@ -962,7 +967,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg) | |||
962 | cpu_policy->cur = cur_freq; | 967 | cpu_policy->cur = cur_freq; |
963 | } | 968 | } |
964 | 969 | ||
965 | out: | 970 | out: |
966 | cpufreq_cpu_put(cpu_policy); | 971 | cpufreq_cpu_put(cpu_policy); |
967 | return 0; | 972 | return 0; |
968 | } | 973 | } |
@@ -1169,7 +1174,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, | |||
1169 | mutex_unlock(&policy->lock); | 1174 | mutex_unlock(&policy->lock); |
1170 | 1175 | ||
1171 | cpufreq_cpu_put(policy); | 1176 | cpufreq_cpu_put(policy); |
1172 | |||
1173 | return ret; | 1177 | return ret; |
1174 | } | 1178 | } |
1175 | EXPORT_SYMBOL_GPL(cpufreq_driver_target); | 1179 | EXPORT_SYMBOL_GPL(cpufreq_driver_target); |
@@ -1208,7 +1212,6 @@ int cpufreq_governor(unsigned int cpu, unsigned int event) | |||
1208 | mutex_unlock(&policy->lock); | 1212 | mutex_unlock(&policy->lock); |
1209 | 1213 | ||
1210 | cpufreq_cpu_put(policy); | 1214 | cpufreq_cpu_put(policy); |
1211 | |||
1212 | return ret; | 1215 | return ret; |
1213 | } | 1216 | } |
1214 | EXPORT_SYMBOL_GPL(cpufreq_governor); | 1217 | EXPORT_SYMBOL_GPL(cpufreq_governor); |
@@ -1232,7 +1235,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) | |||
1232 | list_add(&governor->governor_list, &cpufreq_governor_list); | 1235 | list_add(&governor->governor_list, &cpufreq_governor_list); |
1233 | 1236 | ||
1234 | mutex_unlock(&cpufreq_governor_mutex); | 1237 | mutex_unlock(&cpufreq_governor_mutex); |
1235 | |||
1236 | return 0; | 1238 | return 0; |
1237 | } | 1239 | } |
1238 | EXPORT_SYMBOL_GPL(cpufreq_register_governor); | 1240 | EXPORT_SYMBOL_GPL(cpufreq_register_governor); |
@@ -1277,7 +1279,6 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) | |||
1277 | mutex_unlock(&cpu_policy->lock); | 1279 | mutex_unlock(&cpu_policy->lock); |
1278 | 1280 | ||
1279 | cpufreq_cpu_put(cpu_policy); | 1281 | cpufreq_cpu_put(cpu_policy); |
1280 | |||
1281 | return 0; | 1282 | return 0; |
1282 | } | 1283 | } |
1283 | EXPORT_SYMBOL(cpufreq_get_policy); | 1284 | EXPORT_SYMBOL(cpufreq_get_policy); |
@@ -1291,9 +1292,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli | |||
1291 | dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, | 1292 | dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu, |
1292 | policy->min, policy->max); | 1293 | policy->min, policy->max); |
1293 | 1294 | ||
1294 | memcpy(&policy->cpuinfo, | 1295 | memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); |
1295 | &data->cpuinfo, | ||
1296 | sizeof(struct cpufreq_cpuinfo)); | ||
1297 | 1296 | ||
1298 | /* verify the cpu speed can be set within this limit */ | 1297 | /* verify the cpu speed can be set within this limit */ |
1299 | ret = cpufreq_driver->verify(policy); | 1298 | ret = cpufreq_driver->verify(policy); |
@@ -1324,8 +1323,8 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli | |||
1324 | 1323 | ||
1325 | up_read(&cpufreq_notifier_rwsem); | 1324 | up_read(&cpufreq_notifier_rwsem); |
1326 | 1325 | ||
1327 | data->min = policy->min; | 1326 | data->min = policy->min; |
1328 | data->max = policy->max; | 1327 | data->max = policy->max; |
1329 | 1328 | ||
1330 | dprintk("new min and max freqs are %u - %u kHz\n", data->min, data->max); | 1329 | dprintk("new min and max freqs are %u - %u kHz\n", data->min, data->max); |
1331 | 1330 | ||
@@ -1362,7 +1361,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli | |||
1362 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); | 1361 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); |
1363 | } | 1362 | } |
1364 | 1363 | ||
1365 | error_out: | 1364 | error_out: |
1366 | cpufreq_debug_enable_ratelimit(); | 1365 | cpufreq_debug_enable_ratelimit(); |
1367 | return ret; | 1366 | return ret; |
1368 | } | 1367 | } |
@@ -1421,9 +1420,7 @@ int cpufreq_update_policy(unsigned int cpu) | |||
1421 | mutex_lock(&data->lock); | 1420 | mutex_lock(&data->lock); |
1422 | 1421 | ||
1423 | dprintk("updating policy for CPU %u\n", cpu); | 1422 | dprintk("updating policy for CPU %u\n", cpu); |
1424 | memcpy(&policy, | 1423 | memcpy(&policy, data, sizeof(struct cpufreq_policy)); |
1425 | data, | ||
1426 | sizeof(struct cpufreq_policy)); | ||
1427 | policy.min = data->user_policy.min; | 1424 | policy.min = data->user_policy.min; |
1428 | policy.max = data->user_policy.max; | 1425 | policy.max = data->user_policy.max; |
1429 | policy.policy = data->user_policy.policy; | 1426 | policy.policy = data->user_policy.policy; |
@@ -1433,8 +1430,13 @@ int cpufreq_update_policy(unsigned int cpu) | |||
1433 | -> ask driver for current freq and notify governors about a change */ | 1430 | -> ask driver for current freq and notify governors about a change */ |
1434 | if (cpufreq_driver->get) { | 1431 | if (cpufreq_driver->get) { |
1435 | policy.cur = cpufreq_driver->get(cpu); | 1432 | policy.cur = cpufreq_driver->get(cpu); |
1436 | if (data->cur != policy.cur) | 1433 | if (!data->cur) { |
1437 | cpufreq_out_of_sync(cpu, data->cur, policy.cur); | 1434 | dprintk("Driver did not initialize current freq"); |
1435 | data->cur = policy.cur; | ||
1436 | } else { | ||
1437 | if (data->cur != policy.cur) | ||
1438 | cpufreq_out_of_sync(cpu, data->cur, policy.cur); | ||
1439 | } | ||
1438 | } | 1440 | } |
1439 | 1441 | ||
1440 | ret = __cpufreq_set_policy(data, &policy); | 1442 | ret = __cpufreq_set_policy(data, &policy); |