diff options
| -rw-r--r-- | drivers/cpufreq/cpufreq_ondemand.c | 72 |
1 files changed, 32 insertions, 40 deletions
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index a2add11e56f1..18b016ea5f48 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c | |||
| @@ -64,6 +64,7 @@ struct cpu_dbs_info_s { | |||
| 64 | cputime64_t prev_cpu_idle; | 64 | cputime64_t prev_cpu_idle; |
| 65 | cputime64_t prev_cpu_wall; | 65 | cputime64_t prev_cpu_wall; |
| 66 | struct cpufreq_policy *cur_policy; | 66 | struct cpufreq_policy *cur_policy; |
| 67 | struct work_struct work; | ||
| 67 | unsigned int enable; | 68 | unsigned int enable; |
| 68 | }; | 69 | }; |
| 69 | static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); | 70 | static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); |
| @@ -81,7 +82,7 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ | |||
| 81 | static DEFINE_MUTEX (dbs_mutex); | 82 | static DEFINE_MUTEX (dbs_mutex); |
| 82 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); | 83 | static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); |
| 83 | 84 | ||
| 84 | static struct workqueue_struct *dbs_workq; | 85 | static struct workqueue_struct *kondemand_wq; |
| 85 | 86 | ||
| 86 | struct dbs_tuners { | 87 | struct dbs_tuners { |
| 87 | unsigned int sampling_rate; | 88 | unsigned int sampling_rate; |
| @@ -233,17 +234,15 @@ static struct attribute_group dbs_attr_group = { | |||
| 233 | 234 | ||
| 234 | /************************** sysfs end ************************/ | 235 | /************************** sysfs end ************************/ |
| 235 | 236 | ||
| 236 | static void dbs_check_cpu(int cpu) | 237 | static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) |
| 237 | { | 238 | { |
| 238 | unsigned int idle_ticks, total_ticks; | 239 | unsigned int idle_ticks, total_ticks; |
| 239 | unsigned int load; | 240 | unsigned int load; |
| 240 | struct cpu_dbs_info_s *this_dbs_info; | ||
| 241 | cputime64_t cur_jiffies; | 241 | cputime64_t cur_jiffies; |
| 242 | 242 | ||
| 243 | struct cpufreq_policy *policy; | 243 | struct cpufreq_policy *policy; |
| 244 | unsigned int j; | 244 | unsigned int j; |
| 245 | 245 | ||
| 246 | this_dbs_info = &per_cpu(cpu_dbs_info, cpu); | ||
| 247 | if (!this_dbs_info->enable) | 246 | if (!this_dbs_info->enable) |
| 248 | return; | 247 | return; |
| 249 | 248 | ||
| @@ -314,35 +313,29 @@ static void dbs_check_cpu(int cpu) | |||
| 314 | 313 | ||
| 315 | static void do_dbs_timer(void *data) | 314 | static void do_dbs_timer(void *data) |
| 316 | { | 315 | { |
| 317 | int i; | 316 | unsigned int cpu = smp_processor_id(); |
| 318 | lock_cpu_hotplug(); | 317 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); |
| 319 | mutex_lock(&dbs_mutex); | 318 | |
| 320 | for_each_online_cpu(i) | 319 | dbs_check_cpu(dbs_info); |
| 321 | dbs_check_cpu(i); | 320 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, |
| 322 | queue_delayed_work(dbs_workq, &dbs_work, | 321 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); |
| 323 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | ||
| 324 | mutex_unlock(&dbs_mutex); | ||
| 325 | unlock_cpu_hotplug(); | ||
| 326 | } | 322 | } |
| 327 | 323 | ||
| 328 | static inline void dbs_timer_init(void) | 324 | static inline void dbs_timer_init(unsigned int cpu) |
| 329 | { | 325 | { |
| 330 | INIT_WORK(&dbs_work, do_dbs_timer, NULL); | 326 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); |
| 331 | if (!dbs_workq) | 327 | |
| 332 | dbs_workq = create_singlethread_workqueue("ondemand"); | 328 | INIT_WORK(&dbs_info->work, do_dbs_timer, 0); |
| 333 | if (!dbs_workq) { | 329 | queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, |
| 334 | printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n"); | 330 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); |
| 335 | return; | ||
| 336 | } | ||
| 337 | queue_delayed_work(dbs_workq, &dbs_work, | ||
| 338 | usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); | ||
| 339 | return; | 331 | return; |
| 340 | } | 332 | } |
| 341 | 333 | ||
| 342 | static inline void dbs_timer_exit(void) | 334 | static inline void dbs_timer_exit(unsigned int cpu) |
| 343 | { | 335 | { |
| 344 | if (dbs_workq) | 336 | struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); |
| 345 | cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work); | 337 | |
| 338 | cancel_rearming_delayed_workqueue(kondemand_wq, &dbs_info->work); | ||
| 346 | } | 339 | } |
| 347 | 340 | ||
| 348 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | 341 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, |
| @@ -370,6 +363,16 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
| 370 | break; | 363 | break; |
| 371 | 364 | ||
| 372 | mutex_lock(&dbs_mutex); | 365 | mutex_lock(&dbs_mutex); |
| 366 | dbs_enable++; | ||
| 367 | if (dbs_enable == 1) { | ||
| 368 | kondemand_wq = create_workqueue("kondemand"); | ||
| 369 | if (!kondemand_wq) { | ||
| 370 | printk(KERN_ERR "Creation of kondemand failed\n"); | ||
| 371 | dbs_enable--; | ||
| 372 | mutex_unlock(&dbs_mutex); | ||
| 373 | return -ENOSPC; | ||
| 374 | } | ||
| 375 | } | ||
| 373 | for_each_cpu_mask(j, policy->cpus) { | 376 | for_each_cpu_mask(j, policy->cpus) { |
| 374 | struct cpu_dbs_info_s *j_dbs_info; | 377 | struct cpu_dbs_info_s *j_dbs_info; |
| 375 | j_dbs_info = &per_cpu(cpu_dbs_info, j); | 378 | j_dbs_info = &per_cpu(cpu_dbs_info, j); |
| @@ -380,7 +383,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
| 380 | } | 383 | } |
| 381 | this_dbs_info->enable = 1; | 384 | this_dbs_info->enable = 1; |
| 382 | sysfs_create_group(&policy->kobj, &dbs_attr_group); | 385 | sysfs_create_group(&policy->kobj, &dbs_attr_group); |
| 383 | dbs_enable++; | ||
| 384 | /* | 386 | /* |
| 385 | * Start the timerschedule work, when this governor | 387 | * Start the timerschedule work, when this governor |
| 386 | * is used for first time | 388 | * is used for first time |
| @@ -399,23 +401,20 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | |||
| 399 | def_sampling_rate = MIN_STAT_SAMPLING_RATE; | 401 | def_sampling_rate = MIN_STAT_SAMPLING_RATE; |
| 400 | 402 | ||
| 401 | dbs_tuners_ins.sampling_rate = def_sampling_rate; | 403 | dbs_tuners_ins.sampling_rate = def_sampling_rate; |
| 402 | dbs_timer_init(); | ||
| 403 | } | 404 | } |
| 405 | dbs_timer_init(policy->cpu); | ||
| 404 | 406 | ||
| 405 | mutex_unlock(&dbs_mutex); | 407 | mutex_unlock(&dbs_mutex); |
| 406 | break; | 408 | break; |
| 407 | 409 | ||
| 408 | case CPUFREQ_GOV_STOP: | 410 | case CPUFREQ_GOV_STOP: |
| 409 | mutex_lock(&dbs_mutex); | 411 | mutex_lock(&dbs_mutex); |
| 412 | dbs_timer_exit(policy->cpu); | ||
| 410 | this_dbs_info->enable = 0; | 413 | this_dbs_info->enable = 0; |
| 411 | sysfs_remove_group(&policy->kobj, &dbs_attr_group); | 414 | sysfs_remove_group(&policy->kobj, &dbs_attr_group); |
| 412 | dbs_enable--; | 415 | dbs_enable--; |
| 413 | /* | ||
| 414 | * Stop the timerschedule work, when this governor | ||
| 415 | * is used for first time | ||
| 416 | */ | ||
| 417 | if (dbs_enable == 0) | 416 | if (dbs_enable == 0) |
| 418 | dbs_timer_exit(); | 417 | destroy_workqueue(kondemand_wq); |
| 419 | 418 | ||
| 420 | mutex_unlock(&dbs_mutex); | 419 | mutex_unlock(&dbs_mutex); |
| 421 | 420 | ||
| @@ -452,13 +451,6 @@ static int __init cpufreq_gov_dbs_init(void) | |||
| 452 | 451 | ||
| 453 | static void __exit cpufreq_gov_dbs_exit(void) | 452 | static void __exit cpufreq_gov_dbs_exit(void) |
| 454 | { | 453 | { |
| 455 | /* Make sure that the scheduled work is indeed not running. | ||
| 456 | Assumes the timer has been cancelled first. */ | ||
| 457 | if (dbs_workq) { | ||
| 458 | flush_workqueue(dbs_workq); | ||
| 459 | destroy_workqueue(dbs_workq); | ||
| 460 | } | ||
| 461 | |||
| 462 | cpufreq_unregister_governor(&cpufreq_gov_dbs); | 454 | cpufreq_unregister_governor(&cpufreq_gov_dbs); |
| 463 | } | 455 | } |
| 464 | 456 | ||
