summary refs log tree commit diff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>2006-06-28 13:51:19 -0700
committerDave Jones <davej@redhat.com>2006-06-30 01:33:31 -0400
commit2f8a835c705794f71726eb12c06fb0f24fe07ed3 (patch)
treec16b1a4bf85df6822b9bcedc608f1db9ddf6e571 /drivers/cpufreq
parent7a6bc1cdd506cf81f856f0fef4e56a2ba0c5a26d (diff)
downloadlinux-2f8a835c705794f71726eb12c06fb0f24fe07ed3.tar.gz
[CPUFREQ] Make ondemand sampling per CPU and remove the mutex usage in sampling path.
Make ondemand sampling per CPU and remove the mutex usage in sampling path.

Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c72
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 {
 	cputime64_t prev_cpu_idle;
 	cputime64_t prev_cpu_wall;
 	struct cpufreq_policy *cur_policy;
+ 	struct work_struct work;
 	unsigned int enable;
 };
 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 */
 static DEFINE_MUTEX (dbs_mutex);
 static DECLARE_WORK	(dbs_work, do_dbs_timer, NULL);
 
-static struct workqueue_struct *dbs_workq;
+static struct workqueue_struct	*kondemand_wq;
 
 struct dbs_tuners {
 	unsigned int sampling_rate;
@@ -233,17 +234,15 @@ static struct attribute_group dbs_attr_group = {
 
 /************************** sysfs end ************************/
 
-static void dbs_check_cpu(int cpu)
+static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
 {
 	unsigned int idle_ticks, total_ticks;
 	unsigned int load;
-	struct cpu_dbs_info_s *this_dbs_info;
 	cputime64_t cur_jiffies;
 
 	struct cpufreq_policy *policy;
 	unsigned int j;
 
-	this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
 	if (!this_dbs_info->enable)
 		return;
 
@@ -314,35 +313,29 @@ static void dbs_check_cpu(int cpu)
 
 static void do_dbs_timer(void *data)
 {
-	int i;
-	lock_cpu_hotplug();
-	mutex_lock(&dbs_mutex);
-	for_each_online_cpu(i)
-		dbs_check_cpu(i);
-	queue_delayed_work(dbs_workq, &dbs_work,
-			   usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
-	mutex_unlock(&dbs_mutex);
-	unlock_cpu_hotplug();
+	unsigned int cpu = smp_processor_id();
+	struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+	dbs_check_cpu(dbs_info);
+	queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work,
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
 }
 
-static inline void dbs_timer_init(void)
+static inline void dbs_timer_init(unsigned int cpu)
 {
-	INIT_WORK(&dbs_work, do_dbs_timer, NULL);
-	if (!dbs_workq)
-		dbs_workq = create_singlethread_workqueue("ondemand");
-	if (!dbs_workq) {
-		printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n");
-		return;
-	}
-	queue_delayed_work(dbs_workq, &dbs_work,
-			   usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+	struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+	INIT_WORK(&dbs_info->work, do_dbs_timer, 0);
+	queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work,
+			usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
 	return;
 }
 
-static inline void dbs_timer_exit(void)
+static inline void dbs_timer_exit(unsigned int cpu)
 {
-	if (dbs_workq)
-		cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work);
+	struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+	cancel_rearming_delayed_workqueue(kondemand_wq, &dbs_info->work);
 }
 
 static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -370,6 +363,16 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 			break;
 
 		mutex_lock(&dbs_mutex);
+		dbs_enable++;
+		if (dbs_enable == 1) {
+			kondemand_wq = create_workqueue("kondemand");
+			if (!kondemand_wq) {
+				printk(KERN_ERR "Creation of kondemand failed\n");
+				dbs_enable--;
+				mutex_unlock(&dbs_mutex);
+				return -ENOSPC;
+			}
+		}
 		for_each_cpu_mask(j, policy->cpus) {
 			struct cpu_dbs_info_s *j_dbs_info;
 			j_dbs_info = &per_cpu(cpu_dbs_info, j);
@@ -380,7 +383,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 		}
 		this_dbs_info->enable = 1;
 		sysfs_create_group(&policy->kobj, &dbs_attr_group);
-		dbs_enable++;
 		/*
 		 * Start the timerschedule work, when this governor
 		 * is used for first time
@@ -399,23 +401,20 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 				def_sampling_rate = MIN_STAT_SAMPLING_RATE;
 
 			dbs_tuners_ins.sampling_rate = def_sampling_rate;
-			dbs_timer_init();
 		}
+		dbs_timer_init(policy->cpu);
 
 		mutex_unlock(&dbs_mutex);
 		break;
 
 	case CPUFREQ_GOV_STOP:
 		mutex_lock(&dbs_mutex);
+		dbs_timer_exit(policy->cpu);
 		this_dbs_info->enable = 0;
 		sysfs_remove_group(&policy->kobj, &dbs_attr_group);
 		dbs_enable--;
-		/*
-		 * Stop the timerschedule work, when this governor
-		 * is used for first time
-		 */
 		if (dbs_enable == 0)
-			dbs_timer_exit();
+			destroy_workqueue(kondemand_wq);
 
 		mutex_unlock(&dbs_mutex);
 
@@ -452,13 +451,6 @@ static int __init cpufreq_gov_dbs_init(void)
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-	/* Make sure that the scheduled work is indeed not running.
-	   Assumes the timer has been cancelled first. */
-	if (dbs_workq) {
-		flush_workqueue(dbs_workq);
-		destroy_workqueue(dbs_workq);
-	}
-
 	cpufreq_unregister_governor(&cpufreq_gov_dbs);
 }