aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>2007-02-05 19:12:45 -0500
committerDave Jones <davej@redhat.com>2007-02-10 20:01:48 -0500
commit56463b78cdca8e9ff8cc1759bca0c0777a061d6b (patch)
tree435e98e919e96da931b1874eae6c888b734dea6d
parent529af7a14f04f92213bac371931a2b2b060c63fa (diff)
[CPUFREQ] ondemand governor use new cpufreq rwsem locking in work callback
Eliminate flush_workqueue in cpufreq_governor(STOP) callpath. Using flush there has a deadlock potential as in http://uwsg.iu.edu/hypermail/linux/kernel/0611.3/1223.html Also, cleanup the locking issues with do_dbs_timer delayed_work callback. As it changes the CPU frequency using __cpufreq_target, it needs to have policy_rwsem in write mode, which also protects it from hot plug. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Cc: Gautham R Shenoy <ego@in.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index a480834c9627..bcf8bb877a8b 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -437,8 +437,14 @@ static void do_dbs_timer(struct work_struct *work)
437 437
438 delay -= jiffies % delay; 438 delay -= jiffies % delay;
439 439
440 if (!dbs_info->enable) 440 if (lock_policy_rwsem_write(cpu) < 0)
441 return; 441 return;
442
443 if (!dbs_info->enable) {
444 unlock_policy_rwsem_write(cpu);
445 return;
446 }
447
442 /* Common NORMAL_SAMPLE setup */ 448 /* Common NORMAL_SAMPLE setup */
443 dbs_info->sample_type = DBS_NORMAL_SAMPLE; 449 dbs_info->sample_type = DBS_NORMAL_SAMPLE;
444 if (!dbs_tuners_ins.powersave_bias || 450 if (!dbs_tuners_ins.powersave_bias ||
@@ -455,6 +461,7 @@ static void do_dbs_timer(struct work_struct *work)
455 CPUFREQ_RELATION_H); 461 CPUFREQ_RELATION_H);
456 } 462 }
457 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); 463 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
464 unlock_policy_rwsem_write(cpu);
458} 465}
459 466
460static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) 467static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
@@ -463,6 +470,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
463 int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); 470 int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
464 delay -= jiffies % delay; 471 delay -= jiffies % delay;
465 472
473 dbs_info->enable = 1;
466 ondemand_powersave_bias_init(); 474 ondemand_powersave_bias_init();
467 dbs_info->sample_type = DBS_NORMAL_SAMPLE; 475 dbs_info->sample_type = DBS_NORMAL_SAMPLE;
468 INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); 476 INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer);
@@ -474,7 +482,6 @@ static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
474{ 482{
475 dbs_info->enable = 0; 483 dbs_info->enable = 0;
476 cancel_delayed_work(&dbs_info->work); 484 cancel_delayed_work(&dbs_info->work);
477 flush_workqueue(kondemand_wq);
478} 485}
479 486
480static int cpufreq_governor_dbs(struct cpufreq_policy *policy, 487static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -503,21 +510,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
503 510
504 mutex_lock(&dbs_mutex); 511 mutex_lock(&dbs_mutex);
505 dbs_enable++; 512 dbs_enable++;
506 if (dbs_enable == 1) {
507 kondemand_wq = create_workqueue("kondemand");
508 if (!kondemand_wq) {
509 printk(KERN_ERR
510 "Creation of kondemand failed\n");
511 dbs_enable--;
512 mutex_unlock(&dbs_mutex);
513 return -ENOSPC;
514 }
515 }
516 513
517 rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); 514 rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
518 if (rc) { 515 if (rc) {
519 if (dbs_enable == 1)
520 destroy_workqueue(kondemand_wq);
521 dbs_enable--; 516 dbs_enable--;
522 mutex_unlock(&dbs_mutex); 517 mutex_unlock(&dbs_mutex);
523 return rc; 518 return rc;
@@ -532,7 +527,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
532 j_dbs_info->prev_cpu_wall = get_jiffies_64(); 527 j_dbs_info->prev_cpu_wall = get_jiffies_64();
533 } 528 }
534 this_dbs_info->cpu = cpu; 529 this_dbs_info->cpu = cpu;
535 this_dbs_info->enable = 1;
536 /* 530 /*
537 * Start the timerschedule work, when this governor 531 * Start the timerschedule work, when this governor
538 * is used for first time 532 * is used for first time
@@ -562,9 +556,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
562 dbs_timer_exit(this_dbs_info); 556 dbs_timer_exit(this_dbs_info);
563 sysfs_remove_group(&policy->kobj, &dbs_attr_group); 557 sysfs_remove_group(&policy->kobj, &dbs_attr_group);
564 dbs_enable--; 558 dbs_enable--;
565 if (dbs_enable == 0)
566 destroy_workqueue(kondemand_wq);
567
568 mutex_unlock(&dbs_mutex); 559 mutex_unlock(&dbs_mutex);
569 560
570 break; 561 break;
@@ -593,12 +584,18 @@ static struct cpufreq_governor cpufreq_gov_dbs = {
593 584
594static int __init cpufreq_gov_dbs_init(void) 585static int __init cpufreq_gov_dbs_init(void)
595{ 586{
587 kondemand_wq = create_workqueue("kondemand");
588 if (!kondemand_wq) {
589 printk(KERN_ERR "Creation of kondemand failed\n");
590 return -EFAULT;
591 }
596 return cpufreq_register_governor(&cpufreq_gov_dbs); 592 return cpufreq_register_governor(&cpufreq_gov_dbs);
597} 593}
598 594
599static void __exit cpufreq_gov_dbs_exit(void) 595static void __exit cpufreq_gov_dbs_exit(void)
600{ 596{
601 cpufreq_unregister_governor(&cpufreq_gov_dbs); 597 cpufreq_unregister_governor(&cpufreq_gov_dbs);
598 destroy_workqueue(kondemand_wq);
602} 599}
603 600
604 601
@@ -610,3 +607,4 @@ MODULE_LICENSE("GPL");
610 607
611module_init(cpufreq_gov_dbs_init); 608module_init(cpufreq_gov_dbs_init);
612module_exit(cpufreq_gov_dbs_exit); 609module_exit(cpufreq_gov_dbs_exit);
610