summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2009-08-19 12:13:06 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2009-08-19 12:13:06 +1000
commitf4efbc23c82e2b232d0ad2b1169f3f4c34efc2b6 (patch)
tree4158426c9a0277d702f36786ed561220235807b6
parent5f3da7f3482b56635c5895e8add01852f24ee569 (diff)
parent5141022ced0ae12f2c8828785c92d29909d7bd17 (diff)
Merge commit 'cpufreq/next'
-rw-r--r--Documentation/cpu-freq/user-guide.txt9
-rw-r--r--drivers/cpufreq/cpufreq.c560
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c139
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c34
-rw-r--r--include/linux/cpufreq.h14
5 files changed, 523 insertions, 233 deletions
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index 5d5f5fadd1c2..2a5b850847c0 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -176,7 +176,9 @@ scaling_governor, and by "echoing" the name of another
work on some specific architectures or
processors.
-cpuinfo_cur_freq : Current speed of the CPU, in KHz.
+cpuinfo_cur_freq : Current frequency of the CPU as obtained from
+ the hardware, in KHz. This is the frequency
+ the CPU actually runs at.
scaling_available_frequencies : List of available frequencies, in KHz.
@@ -196,7 +198,10 @@ related_cpus : List of CPUs that need some sort of frequency
scaling_driver : Hardware driver for cpufreq.
-scaling_cur_freq : Current frequency of the CPU, in KHz.
+scaling_cur_freq : Current frequency of the CPU as determined by
+ the governor and cpufreq core, in KHz. This is
+ the frequency the kernel thinks the CPU runs
+ at.
If you have selected the "userspace" governor which allows you to
set the CPU operating frequency to a specific value, you can read out
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index fd69086d08d5..19230221b030 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -39,10 +39,6 @@
*/
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);
/*
@@ -61,6 +57,8 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
* are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
+ * - Lock should not be held across
+ * __cpufreq_governor(data, CPUFREQ_GOV_STOP);
*/
static DEFINE_PER_CPU(int, policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
@@ -128,6 +126,10 @@ 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);
@@ -503,48 +505,99 @@ 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 cpufreq_policy *policy, char *buf)
+
+static ssize_t show_scaling_governor(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
- 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)
+ 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)
return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n",
- policy->governor->name);
+ cpufreq_current_governor->name);
return -EINVAL;
}
-
/**
* store_scaling_governor - store policy for the specified CPU
*/
-static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
- const char *buf, size_t count)
+static ssize_t store_scaling_governor(struct kobject *kobj,
+ struct attribute *attr, 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;
-
- ret = cpufreq_get_policy(&new_policy, policy->cpu);
- if (ret)
- return ret;
+ 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 = sscanf(buf, "%15s", str_governor);
if (ret != 1)
return -EINVAL;
- if (cpufreq_parse_governor(str_governor, &new_policy.policy,
- &new_policy.governor))
+ if (cpufreq_parse_governor(str_governor, &current_driver_policy,
+ &cpufreq_current_governor))
return -EINVAL;
- /* Do not use cpufreq_set_policy here or the user_policy.max
- will be wrongly overridden */
- ret = __cpufreq_set_policy(policy, &new_policy);
+ if (old_gov == cpufreq_current_governor &&
+ old_driver_policy == current_driver_policy)
+ return count;
- policy->user_policy.policy = policy->policy;
- policy->user_policy.governor = policy->governor;
+ 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;
+ }
+
+ old_policy = cpufreq_cpu_get(i);
+ if (!old_policy) {
+ unlock_policy_rwsem_write(i);
+ continue;
+ }
+ 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
@@ -554,7 +607,8 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
/**
* show_scaling_driver - show the cpufreq driver currently loaded
*/
-static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_scaling_driver(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name);
}
@@ -562,7 +616,8 @@ static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf)
/**
* show_scaling_available_governors - show the available CPUfreq governors
*/
-static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
+static ssize_t show_scaling_available_governors(struct kobject *kobj,
+ struct attribute *attr,
char *buf)
{
ssize_t i = 0;
@@ -584,6 +639,61 @@ 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;
@@ -619,32 +729,6 @@ static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
return show_cpus(policy->cpus, buf);
}
-static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
- const char *buf, size_t count)
-{
- unsigned int freq = 0;
- unsigned int ret;
-
- if (!policy->governor || !policy->governor->store_setspeed)
- return -EINVAL;
-
- ret = sscanf(buf, "%u", &freq);
- if (ret != 1)
- return -EINVAL;
-
- policy->governor->store_setspeed(policy, freq);
-
- return count;
-}
-
-static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
-{
- if (!policy->governor || !policy->governor->show_setspeed)
- return sprintf(buf, "<unsupported>\n");
-
- return policy->governor->show_setspeed(policy, buf);
-}
-
#define define_one_ro(_name) \
static struct freq_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL)
@@ -661,15 +745,11 @@ 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);
-define_one_rw(scaling_setspeed);
static struct attribute *default_attrs[] = {
&cpuinfo_min_freq.attr,
@@ -679,13 +759,27 @@ static struct attribute *default_attrs[] = {
&scaling_max_freq.attr,
&affected_cpus.attr,
&related_cpus.attr,
- &scaling_governor.attr,
- &scaling_driver.attr,
- &scaling_available_governors.attr,
- &scaling_setspeed.attr,
+ &scaling_governor_old.attr,
+ &scaling_driver_old.attr,
+ &scaling_available_governors_old.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);
+
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
#define to_attr(a) container_of(a, struct freq_attr, attr)
@@ -719,19 +813,33 @@ 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 (lock_policy_rwsem_write(policy->cpu) < 0)
- goto fail;
+ 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 (fattr->store)
ret = fattr->store(policy, buf, count);
else
ret = -EIO;
- unlock_policy_rwsem_write(policy->cpu);
+ if (!scal_gov)
+ unlock_policy_rwsem_write(policy->cpu);
+ scal_gov = 0;
fail:
cpufreq_cpu_put(policy);
no_policy:
@@ -756,100 +864,20 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};
-
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
+/*
+ * Returns:
+ * Negative: Failure
+ * 0: Success
+ * Positive: When we have a managed CPU and the sysfs got symlinked
*/
-static int cpufreq_add_dev(struct sys_device *sys_dev)
+int cpufreq_add_dev_policy(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
{
- unsigned int cpu = sys_dev->id;
int ret = 0;
- struct cpufreq_policy new_policy;
- struct cpufreq_policy *policy;
- struct freq_attr **drv_attr;
- struct sys_device *cpu_sys_dev;
+#ifdef CONFIG_SMP
unsigned long flags;
unsigned int j;
- if (cpu_is_offline(cpu))
- return 0;
-
- cpufreq_debug_disable_ratelimit();
- dprintk("adding CPU %u\n", cpu);
-
-#ifdef CONFIG_SMP
- /* check whether a different CPU already registered this
- * CPU because it is in the same boat. */
- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
- cpufreq_debug_enable_ratelimit();
- return 0;
- }
-#endif
-
- if (!try_module_get(cpufreq_driver->owner)) {
- ret = -EINVAL;
- goto module_out;
- }
-
- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
- if (!policy) {
- ret = -ENOMEM;
- goto nomem_out;
- }
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_policy;
- }
- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto err_free_cpumask;
- }
-
- policy->cpu = cpu;
- cpumask_copy(policy->cpus, cpumask_of(cpu));
-
- /* Initially set CPU itself as the policy_cpu */
- per_cpu(policy_cpu, cpu) = cpu;
- ret = (lock_policy_rwsem_write(cpu) < 0);
- WARN_ON(ret);
-
- init_completion(&policy->kobj_unregister);
- INIT_WORK(&policy->update, handle_update);
-
- /* Set governor before ->init, so that driver could check it */
- 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
- */
- ret = cpufreq_driver->init(policy);
- if (ret) {
- dprintk("initialization failed\n");
- goto err_unlock_policy;
- }
- policy->user_policy.min = policy->min;
- policy->user_policy.max = policy->max;
-
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_START, policy);
-
-#ifdef CONFIG_SMP
-
-#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;
@@ -872,9 +900,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
/* Should not go through policy unlock path */
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
- ret = -EBUSY;
cpufreq_cpu_put(managed_policy);
- goto err_free_cpumask;
+ return -EBUSY;
}
spin_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -893,17 +920,62 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
* Call driver->exit() because only the cpu parent of
* the kobj needed to call init().
*/
- goto out_driver_exit; /* call driver->exit() */
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+
+ if (!ret)
+ return 1;
+ else
+ return ret;
}
}
#endif
- memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ return ret;
+}
+
+
+/* symlink affected CPUs */
+int cpufreq_add_dev_symlink(unsigned int cpu, struct cpufreq_policy *policy)
+{
+ unsigned int j;
+ int ret = 0;
+
+ for_each_cpu(j, policy->cpus) {
+ struct cpufreq_policy *managed_policy;
+ struct sys_device *cpu_sys_dev;
+
+ if (j == cpu)
+ continue;
+ if (!cpu_online(j))
+ continue;
+
+ dprintk("CPU %u already managed, adding link\n", j);
+ managed_policy = cpufreq_cpu_get(cpu);
+ cpu_sys_dev = get_cpu_sysdev(j);
+ ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
+ "cpufreq");
+ if (ret) {
+ cpufreq_cpu_put(managed_policy);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+int cpufreq_add_dev_interface(unsigned int cpu, struct cpufreq_policy *policy,
+ struct sys_device *sys_dev)
+{
+ struct cpufreq_policy new_policy;
+ struct freq_attr **drv_attr;
+ unsigned long flags;
+ int ret = 0;
+ unsigned int j;
/* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
- "cpufreq");
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ &sys_dev->kobj, "cpufreq");
if (ret)
- goto out_driver_exit;
+ return ret;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
@@ -926,35 +998,20 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
- if (!cpu_online(j))
- continue;
+ if (!cpu_online(j))
+ continue;
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(policy_cpu, j) = policy->cpu;
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- /* symlink affected CPUs */
- for_each_cpu(j, policy->cpus) {
- struct cpufreq_policy *managed_policy;
-
- if (j == cpu)
- continue;
- if (!cpu_online(j))
- continue;
-
- dprintk("CPU %u already managed, adding link\n", j);
- managed_policy = cpufreq_cpu_get(cpu);
- cpu_sys_dev = get_cpu_sysdev(j);
- ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
- "cpufreq");
- if (ret) {
- cpufreq_cpu_put(managed_policy);
- goto err_out_unregister;
- }
- }
+ ret = cpufreq_add_dev_symlink(cpu, policy);
+ if (ret)
+ goto err_out_kobj_put;
- policy->governor = NULL; /* to assure that the starting sequence is
- * run in cpufreq_set_policy */
+ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+ /* assure that the starting sequence is run in __cpufreq_set_policy */
+ policy->governor = NULL;
/* set default policy */
ret = __cpufreq_set_policy(policy, &new_policy);
@@ -963,9 +1020,108 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
if (ret) {
dprintk("setting policy failed\n");
- goto err_out_unregister;
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+ }
+ return ret;
+
+err_out_kobj_put:
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ return ret;
+}
+
+
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct sys_device *sys_dev)
+{
+ unsigned int cpu = sys_dev->id;
+ int ret = 0;
+ struct cpufreq_policy *policy;
+ unsigned long flags;
+ unsigned int j;
+
+ if (cpu_is_offline(cpu))
+ return 0;
+
+ cpufreq_debug_disable_ratelimit();
+ dprintk("adding CPU %u\n", cpu);
+
+#ifdef CONFIG_SMP
+ /* check whether a different CPU already registered this
+ * CPU because it is in the same boat. */
+ policy = cpufreq_cpu_get(cpu);
+ if (unlikely(policy)) {
+ cpufreq_cpu_put(policy);
+ cpufreq_debug_enable_ratelimit();
+ return 0;
+ }
+#endif
+
+ if (!try_module_get(cpufreq_driver->owner)) {
+ ret = -EINVAL;
+ goto module_out;
+ }
+
+ ret = -ENOMEM;
+ policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
+ if (!policy)
+ goto nomem_out;
+
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+ goto err_free_policy;
+
+ if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+ goto err_free_cpumask;
+
+ policy->cpu = cpu;
+ cpumask_copy(policy->cpus, cpumask_of(cpu));
+
+ /* Initially set CPU itself as the policy_cpu */
+ per_cpu(policy_cpu, cpu) = cpu;
+ ret = (lock_policy_rwsem_write(cpu) < 0);
+ WARN_ON(ret);
+
+ init_completion(&policy->kobj_unregister);
+ INIT_WORK(&policy->update, handle_update);
+
+ /* Set governor before ->init, so that driver could check it */
+ policy->governor = cpufreq_current_governor;
+ /* call driver. From then on the cpufreq must be able
+ * to accept all calls to ->verify and ->setpolicy for this CPU
+ */
+ ret = cpufreq_driver->init(policy);
+ if (ret) {
+ dprintk("initialization failed\n");
+ goto err_unlock_policy;
+ }
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
+
+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+ CPUFREQ_START, policy);
+
+ ret = cpufreq_add_dev_policy(cpu, policy, sys_dev);
+ if (ret) {
+ if (ret > 0)
+ /* This is a managed cpu, symlink created,
+ exit with 0 */
+ ret = 0;
+ goto err_unlock_policy;
}
+ ret = cpufreq_add_dev_interface(cpu, policy, sys_dev);
+ if (ret)
+ goto err_out_unregister;
+
unlock_policy_rwsem_write(cpu);
kobject_uevent(&policy->kobj, KOBJ_ADD);
@@ -982,14 +1138,9 @@ err_out_unregister:
per_cpu(cpufreq_cpu_data, j) = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-err_out_kobj_put:
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
-out_driver_exit:
- if (cpufreq_driver->exit)
- cpufreq_driver->exit(policy);
-
err_unlock_policy:
unlock_policy_rwsem_write(cpu);
err_free_cpumask:
@@ -1054,10 +1205,6 @@ 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
@@ -1078,9 +1225,6 @@ 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);
@@ -1607,7 +1751,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
return ret;
}
-
int cpufreq_register_governor(struct cpufreq_governor *governor)
{
int err;
@@ -1642,7 +1785,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
-
/*********************************************************************
* POLICY INTERFACE *
*********************************************************************/
@@ -1734,8 +1876,17 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
dprintk("governor switch\n");
/* end old governor */
- if (data->governor)
+ if (data->governor) {
+ /*
+ * Need to release the rwsem around governor
+ * stop due to lock dependency between
+ * cancel_delayed_work_sync and the read lock
+ * taken in the delayed work handler.
+ */
+ unlock_policy_rwsem_write(data->cpu);
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ lock_policy_rwsem_write(data->cpu);
+ }
/* start new governor */
data->governor = policy->governor;
@@ -1965,7 +2116,18 @@ static int __init cpufreq_core_init(void)
per_cpu(policy_cpu, cpu) = -1;
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}
+
+ 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));
+
return 0;
}
-
core_initcall(cpufreq_core_init);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index d6ba14276bb1..1a3e5c7252ff 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -55,6 +55,18 @@ static unsigned int min_sampling_rate;
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event);
+
+#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
+static
+#endif
+struct cpufreq_governor cpufreq_gov_ondemand = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
+};
/* Sampling types */
enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
@@ -206,20 +218,23 @@ static void ondemand_powersave_bias_init(void)
}
/************************** sysfs interface ************************/
-static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+
+static ssize_t show_sampling_rate_max(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
printk_once(KERN_INFO "CPUFREQ: ondemand sampling_rate_max "
"sysfs file is deprecated - used by: %s\n", current->comm);
return sprintf(buf, "%u\n", -1U);
}
-static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+static ssize_t show_sampling_rate_min(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", min_sampling_rate);
}
#define define_one_ro(_name) \
-static struct freq_attr _name = \
+static struct global_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL)
define_one_ro(sampling_rate_max);
@@ -228,7 +243,7 @@ define_one_ro(sampling_rate_min);
/* cpufreq_ondemand Governor Tunables */
#define show_one(file_name, object) \
static ssize_t show_##file_name \
-(struct cpufreq_policy *unused, char *buf) \
+(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
}
@@ -237,8 +252,38 @@ show_one(up_threshold, up_threshold);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
-static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+/*** delete after deprecation time ***/
+
+#define DEPRECATION_MSG(file_name) \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n");
+
+#define show_one_old(file_name) \
+static ssize_t show_##file_name##_old \
+(struct cpufreq_policy *unused, char *buf) \
+{ \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n"); \
+ return show_##file_name(NULL, NULL, buf); \
+}
+show_one_old(sampling_rate);
+show_one_old(up_threshold);
+show_one_old(ignore_nice_load);
+show_one_old(powersave_bias);
+show_one_old(sampling_rate_min);
+show_one_old(sampling_rate_max);
+
+#define define_one_ro_old(object, _name) \
+static struct freq_attr object = \
+__ATTR(_name, 0444, show_##_name##_old, NULL)
+
+define_one_ro_old(sampling_rate_min_old, sampling_rate_min);
+define_one_ro_old(sampling_rate_max_old, sampling_rate_max);
+
+/*** delete after deprecation time ***/
+
+static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -253,8 +298,8 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_up_threshold(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -272,8 +317,8 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
- const char *buf, size_t count)
+static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -309,8 +354,8 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
return count;
}
-static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
- const char *buf, size_t count)
+static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
{
unsigned int input;
int ret;
@@ -331,7 +376,7 @@ static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
}
#define define_one_rw(_name) \
-static struct freq_attr _name = \
+static struct global_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
define_one_rw(sampling_rate);
@@ -354,6 +399,47 @@ static struct attribute_group dbs_attr_group = {
.name = "ondemand",
};
+/*** delete after deprecation time ***/
+
+#define write_one_old(file_name) \
+static ssize_t store_##file_name##_old \
+(struct cpufreq_policy *unused, const char *buf, size_t count) \
+{ \
+ printk_once(KERN_INFO "CPUFREQ: Per core ondemand sysfs " \
+ "interface is deprecated - " #file_name "\n"); \
+ return store_##file_name(NULL, NULL, buf, count); \
+}
+write_one_old(sampling_rate);
+write_one_old(up_threshold);
+write_one_old(ignore_nice_load);
+write_one_old(powersave_bias);
+
+#define define_one_rw_old(object, _name) \
+static struct freq_attr object = \
+__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
+
+define_one_rw_old(sampling_rate_old, sampling_rate);
+define_one_rw_old(up_threshold_old, up_threshold);
+define_one_rw_old(ignore_nice_load_old, ignore_nice_load);
+define_one_rw_old(powersave_bias_old, powersave_bias);
+
+static struct attribute *dbs_attributes_old[] = {
+ &sampling_rate_max_old.attr,
+ &sampling_rate_min_old.attr,
+ &sampling_rate_old.attr,
+ &up_threshold_old.attr,
+ &ignore_nice_load_old.attr,
+ &powersave_bias_old.attr,
+ NULL
+};
+
+static struct attribute_group dbs_attr_group_old = {
+ .attrs = dbs_attributes_old,
+ .name = "ondemand",
+};
+
+/*** delete after deprecation time ***/
+
/************************** sysfs end ************************/
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
@@ -544,7 +630,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex);
- rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ rc = sysfs_create_group(&policy->kobj, &dbs_attr_group_old);
if (rc) {
mutex_unlock(&dbs_mutex);
return rc;
@@ -565,13 +651,20 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
this_dbs_info->cpu = cpu;
ondemand_powersave_bias_init_cpu(cpu);
- mutex_init(&this_dbs_info->timer_mutex);
/*
* Start the timerschedule work, when this governor
* is used for first time
*/
if (dbs_enable == 1) {
unsigned int latency;
+
+ rc = sysfs_create_group(cpufreq_global_kobject,
+ &dbs_attr_group);
+ if (rc) {
+ mutex_unlock(&dbs_mutex);
+ return rc;
+ }
+
/* policy latency is in nS. Convert it to uS first */
latency = policy->cpuinfo.transition_latency / 1000;
if (latency == 0)
@@ -585,6 +678,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
mutex_unlock(&dbs_mutex);
+ mutex_init(&this_dbs_info->timer_mutex);
dbs_timer_init(this_dbs_info);
break;
@@ -592,10 +686,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_timer_exit(this_dbs_info);
mutex_lock(&dbs_mutex);
- sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+ sysfs_remove_group(&policy->kobj, &dbs_attr_group_old);
mutex_destroy(&this_dbs_info->timer_mutex);
dbs_enable--;
mutex_unlock(&dbs_mutex);
+ if (!dbs_enable)
+ sysfs_remove_group(cpufreq_global_kobject,
+ &dbs_attr_group);
break;
@@ -613,16 +710,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
-static
-#endif
-struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
-};
-
static int __init cpufreq_gov_dbs_init(void)
{
int err;
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 66d2d1d6c80f..b41f1a69df84 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -40,6 +40,33 @@ static int cpus_using_userspace_governor;
#define dprintk(msg...) \
cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
+static ssize_t show_speed(struct cpufreq_policy *policy, char *buf);
+static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq);
+
+static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ unsigned int freq = 0;
+ unsigned int ret;
+
+ ret = sscanf(buf, "%u", &freq);
+ if (ret != 1)
+ return -EINVAL;
+
+ cpufreq_set(policy, freq);
+
+ return count;
+}
+
+static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
+{
+ return show_speed(policy, buf);
+}
+
+static struct freq_attr scaling_setspeed =
+ __ATTR(scaling_setspeed, 0644, show_scaling_setspeed,
+ store_scaling_setspeed);
+
/* keep track of frequency transitions */
static int
userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -120,6 +147,10 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
if (!cpu_online(cpu))
return -EINVAL;
BUG_ON(!policy->cur);
+ rc = sysfs_create_file(&policy->kobj, &scaling_setspeed.attr);
+ if (rc)
+ return rc;
+
mutex_lock(&userspace_mutex);
if (cpus_using_userspace_governor == 0) {
@@ -144,6 +175,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_STOP:
+ sysfs_remove_file(&policy->kobj, &scaling_setspeed.attr);
mutex_lock(&userspace_mutex);
cpus_using_userspace_governor--;
if (cpus_using_userspace_governor == 0) {
@@ -193,8 +225,6 @@ static
struct cpufreq_governor cpufreq_gov_userspace = {
.name = "userspace",
.governor = cpufreq_governor_userspace,
- .store_setspeed = cpufreq_set,
- .show_setspeed = show_speed,
.owner = THIS_MODULE,
};
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 161042746afc..336017aed597 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -65,6 +65,9 @@ static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
struct cpufreq_governor;
+/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
+extern struct kobject *cpufreq_global_kobject;
+
#define CPUFREQ_ETERNAL (-1)
struct cpufreq_cpuinfo {
unsigned int max_freq;
@@ -166,10 +169,6 @@ struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN];
int (*governor) (struct cpufreq_policy *policy,
unsigned int event);
- ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
- char *buf);
- int (*store_setspeed) (struct cpufreq_policy *policy,
- unsigned int freq);
unsigned int max_transition_latency; /* HW must be able to switch to
next freq faster than this value in nano secs or we
will fallback to performance governor */
@@ -274,6 +273,13 @@ struct freq_attr {
ssize_t (*store)(struct cpufreq_policy *, const char *, size_t count);
};
+struct global_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj,
+ struct attribute *attr, char *buf);
+ ssize_t (*store)(struct kobject *a, struct attribute *b,
+ const char *c, size_t count);
+};
/*********************************************************************
* CPUFREQ 2.6. INTERFACE *