diff options
author | Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 2007-02-05 19:12:45 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2007-02-10 20:01:48 -0500 |
commit | 56463b78cdca8e9ff8cc1759bca0c0777a061d6b (patch) | |
tree | 435e98e919e96da931b1874eae6c888b734dea6d /drivers/cpufreq/cpufreq_ondemand.c | |
parent | 529af7a14f04f92213bac371931a2b2b060c63fa (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>
Diffstat (limited to 'drivers/cpufreq/cpufreq_ondemand.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_ondemand.c | 34 |
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 | ||
460 | static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) | 467 | static 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 | ||
480 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | 487 | static 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 | ||
594 | static int __init cpufreq_gov_dbs_init(void) | 585 | static 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 | ||
599 | static void __exit cpufreq_gov_dbs_exit(void) | 595 | static 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 | ||
611 | module_init(cpufreq_gov_dbs_init); | 608 | module_init(cpufreq_gov_dbs_init); |
612 | module_exit(cpufreq_gov_dbs_exit); | 609 | module_exit(cpufreq_gov_dbs_exit); |
610 | |||