[PATCH 2/3] CPUFREQ: Revert patch to only allow one governor per machine not per core

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Goal was to make locking easier, but after going through this in detail,
I doubt that can be achieved by machine wide cpufreq governors.
Most governors, especially the more complex ondemand and conservative ones,
still have to intialize things on a per core basis.
Providing ondemand, conservative and other governors with the ability to
use global sysfs structure is the real cleanup that avoids two locks:
  - rwsem held by all per core sysfs accesses
  - a governor internal lock to serialize tuning variable access

CC: Dave Jones <davej@xxxxxxxxxx>
Signed-off-by: Thomas Renninger <trenn@xxxxxxx>
---
 drivers/cpufreq/cpufreq.c |  229 +++++++++++----------------------------------
 1 files changed, 53 insertions(+), 176 deletions(-)

diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 9d9251f..40045d8 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -39,6 +39,10 @@
  */
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+#ifdef CONFIG_HOTPLUG_CPU
+/* This one keeps track of the previously set governor of a removed CPU */
+static DEFINE_PER_CPU(struct cpufreq_governor *, cpufreq_cpu_governor);
+#endif
 static DEFINE_SPINLOCK(cpufreq_driver_lock);
 
 /*
@@ -126,10 +130,6 @@ static int __init init_cpufreq_transition_notifier_list(void)
 }
 pure_initcall(init_cpufreq_transition_notifier_list);
 
-static struct cpufreq_governor *cpufreq_current_governor =
-	CPUFREQ_DEFAULT_GOVERNOR;
-static int current_driver_policy;
-
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX(cpufreq_governor_mutex);
 
@@ -505,99 +505,48 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
 /**
  * show_scaling_governor - show the current policy for the specified CPU
  */
-
-static ssize_t show_scaling_governor(struct kobject *kobj,
-				     struct attribute *attr, char *buf)
+static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
 {
-	if (current_driver_policy) {
-		if (current_driver_policy == CPUFREQ_POLICY_POWERSAVE)
-			return sprintf(buf, "powersave\n");
-		else if (current_driver_policy == CPUFREQ_POLICY_PERFORMANCE)
-			return sprintf(buf, "performance\n");
-	} else if (cpufreq_current_governor)
+	if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
+		return sprintf(buf, "powersave\n");
+	else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
+		return sprintf(buf, "performance\n");
+	else if (policy->governor)
 		return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n",
-				 cpufreq_current_governor->name);
+				policy->governor->name);
 	return -EINVAL;
 }
 
+
 /**
  * store_scaling_governor - store policy for the specified CPU
  */
-static ssize_t store_scaling_governor(struct kobject *kobj,
-				      struct attribute *attr, const char *buf,
-				      size_t count)
+static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
+					const char *buf, size_t count)
 {
 	unsigned int ret = -EINVAL;
-	int i, j;
 	char	str_governor[16];
-	struct cpufreq_policy *old_policy;
 	struct cpufreq_policy new_policy;
-	struct cpufreq_governor *old_gov = cpufreq_current_governor;
-	int    old_driver_policy         = current_driver_policy;
-	struct cpumask already_handled;
-	int is_handled = 0;
-	cpus_clear(already_handled);
+
+	ret = cpufreq_get_policy(&new_policy, policy->cpu);
+	if (ret)
+		return ret;
 
 	ret = sscanf(buf, "%15s", str_governor);
 	if (ret != 1)
 		return -EINVAL;
 
-	if (cpufreq_parse_governor(str_governor, &current_driver_policy,
-				   &cpufreq_current_governor))
+	if (cpufreq_parse_governor(str_governor, &new_policy.policy,
+						&new_policy.governor))
 		return -EINVAL;
 
-	if (old_gov == cpufreq_current_governor &&
-	    old_driver_policy == current_driver_policy)
-		return count;
-
-	for_each_present_cpu(i) {
-		ret = cpufreq_get_policy(&new_policy, i);
-		if (ret) {
-			ret = 0;
-			continue;
-		}
-
-		/* Do not set managed policies/cpus twice */
-		for_each_cpu(j, new_policy.cpus) {
-			if (cpu_isset(j, already_handled))
-				is_handled = 1;
-		}
-		if (is_handled) {
-			dprintk("CPU %d already handled\n", i);
-			is_handled = 0;
-			continue;
-		}
-
-		ret = unlikely(lock_policy_rwsem_write(i));
-		if (ret)
-			continue;
-
-		/* race can happen with offlining, handle it */
-		if (cpu_is_offline(i)) {
-			unlock_policy_rwsem_write(i);
-			continue;
-		}
+	/* Do not use cpufreq_set_policy here or the user_policy.max
+	   will be wrongly overridden */
+	ret = __cpufreq_set_policy(policy, &new_policy);
 
-		old_policy = cpufreq_cpu_get(i);
-		if (!old_policy) {
-			unlock_policy_rwsem_write(i);
-			continue;
-		}
+	policy->user_policy.policy = policy->policy;
+	policy->user_policy.governor = policy->governor;
 
-		new_policy.governor = cpufreq_current_governor;
-		new_policy.policy   = current_driver_policy;
-		ret = __cpufreq_set_policy(old_policy, &new_policy);
-		cpufreq_cpu_put(old_policy);
-		WARN_ON(ret);
-		if (ret) {
-			unlock_policy_rwsem_write(i);
-			continue;
-		}
-		old_policy->user_policy.governor = cpufreq_current_governor;
-		old_policy->user_policy.policy =   current_driver_policy;
-		unlock_policy_rwsem_write(i);
-		cpu_set(new_policy.cpu, already_handled);
-	}
 	if (ret)
 		return ret;
 	else
@@ -607,8 +556,7 @@ static ssize_t store_scaling_governor(struct kobject *kobj,
 /**
  * show_scaling_driver - show the cpufreq driver currently loaded
  */
-static ssize_t show_scaling_driver(struct kobject *kobj,
-				   struct attribute *attr, char *buf)
+static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
 {
 	return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
 }
@@ -616,8 +564,7 @@ static ssize_t show_scaling_driver(struct kobject *kobj,
 /**
  * show_scaling_available_governors - show the available CPUfreq governors
  */
-static ssize_t show_scaling_available_governors(struct kobject *kobj,
-						struct attribute *attr,
+static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
 						char *buf)
 {
 	ssize_t i = 0;
@@ -639,61 +586,6 @@ out:
 	return i;
 }
 
-/*** delete after deprecation time ***/
-
-#define DEPRECATION_MSG(file_name)					\
-	printk_once(KERN_INFO "CPUFREQ: Per core cpufreq sysfs "	\
-		    "interface is deprecated - " #file_name "\n");
-
-static ssize_t show_scaling_governor_old(struct cpufreq_policy *policy,
-					 char *buf)
-{
-	DEPRECATION_MSG(show_scaling_governor);
-	return show_scaling_governor(NULL, NULL, buf);
-};
-
-static ssize_t store_scaling_governor_old(struct cpufreq_policy *policy,
-					  const char *buf, size_t count)
-{
-	int ret;
-
-	DEPRECATION_MSG(store_scaling_governor);
-	cpufreq_cpu_put(policy);
-	ret = store_scaling_governor(NULL, NULL, buf, count);
-	cpufreq_cpu_get(policy->cpu);
-	return ret;
-}
-
-static ssize_t show_scaling_driver_old(struct cpufreq_policy *policy,
-				       char *buf)
-{
-	DEPRECATION_MSG(show_scaling_driver);
-	return show_scaling_driver(NULL, NULL, buf);
-}
-
-static ssize_t show_scaling_available_governors_old(struct cpufreq_policy *p,
-						    char *buf)
-{
-	DEPRECATION_MSG(show_scaling_available_governors);
-	return show_scaling_available_governors(NULL, NULL, buf);
-}
-
-#define define_one_ro_old(object, _name)	\
-static struct freq_attr object =		\
-__ATTR(_name, 0444, show_##_name##_old, NULL)
-
-#define define_one_rw_old(object, _name)	\
-static struct freq_attr object =		\
-__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
-
-define_one_ro_old(scaling_available_governors_old,
-		  scaling_available_governors);
-define_one_ro_old(scaling_driver_old, scaling_driver);
-define_one_rw_old(scaling_governor_old, scaling_governor);
-
-/*** delete after deprecation time ***/
-
-
 static ssize_t show_cpus(const struct cpumask *mask, char *buf)
 {
 	ssize_t i = 0;
@@ -745,11 +637,14 @@ define_one_ro0400(cpuinfo_cur_freq);
 define_one_ro(cpuinfo_min_freq);
 define_one_ro(cpuinfo_max_freq);
 define_one_ro(cpuinfo_transition_latency);
+define_one_ro(scaling_available_governors);
+define_one_ro(scaling_driver);
 define_one_ro(scaling_cur_freq);
 define_one_ro(related_cpus);
 define_one_ro(affected_cpus);
 define_one_rw(scaling_min_freq);
 define_one_rw(scaling_max_freq);
+define_one_rw(scaling_governor);
 
 static struct attribute *default_attrs[] = {
 	&cpuinfo_min_freq.attr,
@@ -759,24 +654,12 @@ static struct attribute *default_attrs[] = {
 	&scaling_max_freq.attr,
 	&affected_cpus.attr,
 	&related_cpus.attr,
-	&scaling_governor_old.attr,
-	&scaling_driver_old.attr,
-	&scaling_available_governors_old.attr,
+	&scaling_governor.attr,
+	&scaling_driver.attr,
+	&scaling_available_governors.attr,
 	NULL
 };
 
-#define define_one_global_ro(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-#define define_one_global_rw(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_global_ro(scaling_available_governors);
-define_one_global_ro(scaling_driver);
-define_one_global_rw(scaling_governor);
-
 struct kobject *cpufreq_global_kobject;
 EXPORT_SYMBOL(cpufreq_global_kobject);
 
@@ -813,33 +696,19 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
 	struct cpufreq_policy *policy = to_policy(kobj);
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret = -EINVAL;
-	/*
-	 * TBD: remove scal_gov and rest after per cpu governor
-	 * deprecation time
-	 */
-	int scal_gov = 0;
 	policy = cpufreq_cpu_get(policy->cpu);
 	if (!policy)
 		goto no_policy;
 
-	if (!strncmp(attr->name, "scaling_governor", 16)) {
-		printk(KERN_INFO "Scaling gov found\n");
-		scal_gov = 1;
-	}
-
-	if (!scal_gov) {
-		if (lock_policy_rwsem_write(policy->cpu) < 0)
-			goto fail;
-	}
+	if (lock_policy_rwsem_write(policy->cpu) < 0)
+		goto fail;
 
 	if (fattr->store)
 		ret = fattr->store(policy, buf, count);
 	else
 		ret = -EIO;
 
-	if (!scal_gov)
-		unlock_policy_rwsem_write(policy->cpu);
-	scal_gov = 0;
+	unlock_policy_rwsem_write(policy->cpu);
 fail:
 	cpufreq_cpu_put(policy);
 no_policy:
@@ -878,6 +747,14 @@ int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
 	unsigned long flags;
 	unsigned int j;
 
+#ifdef CONFIG_HOTPLUG_CPU
+	if (per_cpu(cpufreq_cpu_governor, cpu)) {
+		policy->governor = per_cpu(cpufreq_cpu_governor, cpu);
+		dprintk("Restoring governor %s for cpu %d\n",
+		       policy->governor->name, cpu);
+	}
+#endif
+
 	for_each_cpu(j, policy->cpus) {
 		struct cpufreq_policy *managed_policy;
 
@@ -1090,7 +967,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
 	INIT_WORK(&policy->update, handle_update);
 
 	/* Set governor before ->init, so that driver could check it */
-	policy->governor = cpufreq_current_governor;
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
 	 */
@@ -1201,6 +1078,10 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
 
 #ifdef CONFIG_SMP
 
+#ifdef CONFIG_HOTPLUG_CPU
+	per_cpu(cpufreq_cpu_governor, cpu) = data->governor;
+#endif
+
 	/* if we have other CPUs still registered, we need to unlink them,
 	 * or else wait_for_completion below will lock up. Clean the
 	 * per_cpu(cpufreq_cpu_data) while holding the lock, and remove
@@ -1221,6 +1102,9 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
 			if (j == cpu)
 				continue;
 			dprintk("removing link for cpu %u\n", j);
+#ifdef CONFIG_HOTPLUG_CPU
+			per_cpu(cpufreq_cpu_governor, j) = data->governor;
+#endif
 			cpu_sys_dev = get_cpu_sysdev(j);
 			sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
 			cpufreq_cpu_put(data);
@@ -2115,14 +1999,7 @@ static int __init cpufreq_core_init(void)
 
 	cpufreq_global_kobject = kobject_create_and_add("cpufreq",
 						&cpu_sysdev_class.kset.kobj);
-	WARN_ON(!cpufreq_global_kobject);
-
-	WARN_ON(sysfs_create_file(cpufreq_global_kobject,
-				 &scaling_governor.attr));
-	WARN_ON(sysfs_create_file(cpufreq_global_kobject,
-				 &scaling_driver.attr));
-	WARN_ON(sysfs_create_file(cpufreq_global_kobject,
-				 &scaling_available_governors.attr));
+	BUG_ON(!cpufreq_global_kobject);
 
 	return 0;
 }
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe cpufreq" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Devel]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Forum]     [Linux SCSI]

  Powered by Linux