Commit 4eabfbb6 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-dj.bkbits.net/cpufreq

into home.osdl.org:/home/torvalds/v2.5/linux
parents 85bce232 2342d6cb
...@@ -21,6 +21,8 @@ Contents: ...@@ -21,6 +21,8 @@ Contents:
1.1 ARM 1.1 ARM
1.2 x86 1.2 x86
1.3 sparc64 1.3 sparc64
1.4 ppc
1.5 SuperH
2. "Policy" / "Governor"? 2. "Policy" / "Governor"?
2.1 Policy 2.1 Policy
...@@ -77,6 +79,20 @@ cpufreq: ...@@ -77,6 +79,20 @@ cpufreq:
UltraSPARC-III UltraSPARC-III
1.4 ppc
-------
Several "PowerBook" and "iBook2" notebooks are supported.
1.5 SuperH
----------
The following SuperH processors are supported by cpufreq:
SH-3
SH-4
2. "Policy" / "Governor" ? 2. "Policy" / "Governor" ?
========================== ==========================
......
#CPUfreq governors and cross-arch helpers # CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define CPUFREQ_ALL_CPUS ((NR_CPUS))
/** /**
* cpufreq_parse_policy - parse a policy string * cpufreq_parse_policy - parse a policy string
* @input_string: the string to parse. * @input_string: the string to parse.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/completion.h>
#define CPUFREQ_NAME_LEN 16 #define CPUFREQ_NAME_LEN 16
...@@ -34,8 +35,6 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); ...@@ -34,8 +35,6 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
#define CPUFREQ_TRANSITION_NOTIFIER (0) #define CPUFREQ_TRANSITION_NOTIFIER (0)
#define CPUFREQ_POLICY_NOTIFIER (1) #define CPUFREQ_POLICY_NOTIFIER (1)
#define CPUFREQ_ALL_CPUS ((NR_CPUS))
/********************** cpufreq policy notifiers *********************/ /********************** cpufreq policy notifiers *********************/
...@@ -56,21 +55,25 @@ struct cpufreq_governor; ...@@ -56,21 +55,25 @@ struct cpufreq_governor;
struct cpufreq_cpuinfo { struct cpufreq_cpuinfo {
unsigned int max_freq; unsigned int max_freq;
unsigned int min_freq; unsigned int min_freq;
unsigned int transition_latency; unsigned int transition_latency; /* in 10^(-9) s */
}; };
struct cpufreq_policy { struct cpufreq_policy {
unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ unsigned int cpu; /* cpu nr */
struct cpufreq_cpuinfo cpuinfo;/* see above */
unsigned int min; /* in kHz */ unsigned int min; /* in kHz */
unsigned int max; /* in kHz */ unsigned int max; /* in kHz */
unsigned int cur; /* in kHz, only needed if cpufreq unsigned int cur; /* in kHz, only needed if cpufreq
* governors are used */ * governors are used */
unsigned int policy; /* see above */ unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */ struct cpufreq_governor *governor; /* see below */
struct cpufreq_cpuinfo cpuinfo; /* see above */
struct kobject kobj;
struct semaphore lock; /* CPU ->setpolicy or ->target may struct semaphore lock; /* CPU ->setpolicy or ->target may
only be called once a time */ only be called once a time */
struct kobject kobj;
struct completion kobj_unregister;
}; };
#define CPUFREQ_ADJUST (0) #define CPUFREQ_ADJUST (0)
...@@ -84,7 +87,7 @@ struct cpufreq_policy { ...@@ -84,7 +87,7 @@ struct cpufreq_policy {
#define CPUFREQ_POSTCHANGE (1) #define CPUFREQ_POSTCHANGE (1)
struct cpufreq_freqs { struct cpufreq_freqs {
unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ unsigned int cpu; /* cpu nr */
unsigned int old; unsigned int old;
unsigned int new; unsigned int new;
}; };
...@@ -154,18 +157,22 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor); ...@@ -154,18 +157,22 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor);
struct freq_attr; struct freq_attr;
struct cpufreq_driver { struct cpufreq_driver {
struct module *owner;
char name[CPUFREQ_NAME_LEN];
struct cpufreq_policy *policy;
/* needed by all drivers */ /* needed by all drivers */
int (*init) (struct cpufreq_policy *policy);
int (*verify) (struct cpufreq_policy *policy); int (*verify) (struct cpufreq_policy *policy);
struct cpufreq_policy *policy;
char name[CPUFREQ_NAME_LEN];
/* define one out of two */ /* define one out of two */
int (*setpolicy) (struct cpufreq_policy *policy); int (*setpolicy) (struct cpufreq_policy *policy);
int (*target) (struct cpufreq_policy *policy, int (*target) (struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation); unsigned int relation);
struct module *owner;
/* optional, for the moment */ /* optional */
int (*init) (struct cpufreq_policy *policy);
int (*exit) (struct cpufreq_policy *policy); int (*exit) (struct cpufreq_policy *policy);
struct freq_attr **attr; struct freq_attr **attr;
}; };
...@@ -306,8 +313,4 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu); ...@@ -306,8 +313,4 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu);
#endif /* CONFIG_CPU_FREQ_TABLE */ #endif /* CONFIG_CPU_FREQ_TABLE */
/* Currently exported only for the proc interface, remove when that goes */
extern struct cpufreq_driver *cpufreq_driver;
#endif /* _LINUX_CPUFREQ_H */ #endif /* _LINUX_CPUFREQ_H */
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/completion.h>
/** /**
* The "cpufreq driver" - the arch- or hardware-dependend low * The "cpufreq driver" - the arch- or hardware-dependend low
...@@ -297,6 +298,12 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, ...@@ -297,6 +298,12 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr,
return ret; return ret;
} }
static void cpufreq_sysfs_release(struct kobject * kobj)
{
struct cpufreq_policy * policy = to_policy(kobj);
complete(&policy->kobj_unregister);
}
static struct sysfs_ops sysfs_ops = { static struct sysfs_ops sysfs_ops = {
.show = show, .show = show,
.store = store, .store = store,
...@@ -305,6 +312,7 @@ static struct sysfs_ops sysfs_ops = { ...@@ -305,6 +312,7 @@ static struct sysfs_ops sysfs_ops = {
static struct kobj_type ktype_cpufreq = { static struct kobj_type ktype_cpufreq = {
.sysfs_ops = &sysfs_ops, .sysfs_ops = &sysfs_ops,
.default_attrs = default_attrs, .default_attrs = default_attrs,
.release = cpufreq_sysfs_release,
}; };
...@@ -329,11 +337,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -329,11 +337,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
*/ */
policy = &cpufreq_driver->policy[cpu]; policy = &cpufreq_driver->policy[cpu];
policy->cpu = cpu; policy->cpu = cpu;
if (cpufreq_driver->init) {
ret = cpufreq_driver->init(policy); ret = cpufreq_driver->init(policy);
if (ret) if (ret)
goto out; goto out;
}
/* set default policy on this CPU */ /* set default policy on this CPU */
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
...@@ -343,6 +349,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -343,6 +349,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
init_MUTEX(&policy->lock); init_MUTEX(&policy->lock);
init_completion(&policy->kobj_unregister);
/* prepare interface data */ /* prepare interface data */
policy->kobj.parent = &sys_dev->kobj; policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq; policy->kobj.ktype = &ktype_cpufreq;
...@@ -352,18 +360,19 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -352,18 +360,19 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
if (ret) if (ret)
goto out; goto out;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr; drv_attr = cpufreq_driver->attr;
while ((drv_attr) && (*drv_attr)) { while ((drv_attr) && (*drv_attr)) {
sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
drv_attr++; drv_attr++;
} }
/* set up files for this cpu device */
/* set default policy */ /* set default policy */
ret = cpufreq_set_policy(&new_policy); ret = cpufreq_set_policy(&new_policy);
if (ret) if (ret) {
kobject_unregister(&policy->kobj); kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
}
out: out:
module_put(cpufreq_driver->owner); module_put(cpufreq_driver->owner);
...@@ -401,10 +410,39 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) ...@@ -401,10 +410,39 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
kobject_put(&cpufreq_driver->policy[cpu].kobj); kobject_put(&cpufreq_driver->policy[cpu].kobj);
/* we need to make sure that the underlying kobj is actually
* destroyed before we proceed e.g. with cpufreq driver module
* unloading
*/
wait_for_completion(&cpufreq_driver->policy[cpu].kobj_unregister);
return 0; return 0;
} }
static int cpufreq_restore(struct sys_device *); /**
* cpufreq_restore - restore the CPU clock frequency after resume
*
* Restore the CPU clock frequency so that our idea of the current
* frequency reflects the actual hardware.
*/
static int cpufreq_restore(struct sys_device * sysdev)
{
int cpu = sysdev->id;
unsigned int ret = 0;
struct cpufreq_policy policy;
if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) {
down(&cpufreq_driver_sem);
memcpy(&policy, &cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem);
ret = cpufreq_set_policy(&policy);
cpufreq_cpu_put(cpu);
}
return ret;
}
static struct sysdev_driver cpufreq_sysdev_driver = { static struct sysdev_driver cpufreq_sysdev_driver = {
.add = cpufreq_add_dev, .add = cpufreq_add_dev,
...@@ -587,33 +625,10 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor); ...@@ -587,33 +625,10 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor) void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{ {
unsigned int i;
if (!governor) if (!governor)
return; return;
down(&cpufreq_governor_sem); down(&cpufreq_governor_sem);
/*
* Unless the user uses rmmod -f, we can be safe. But we never
* know, so check whether if it's currently used. If so,
* stop it and replace it with the default governor.
*/
for (i=0; i<NR_CPUS; i++)
{
if (!cpufreq_cpu_get(i))
continue;
if ((cpufreq_driver->policy[i].policy == CPUFREQ_POLICY_GOVERNOR) &&
(cpufreq_driver->policy[i].governor == governor)) {
cpufreq_governor(i, CPUFREQ_GOV_STOP);
cpufreq_driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE;
cpufreq_governor(i, CPUFREQ_GOV_START);
cpufreq_governor(i, CPUFREQ_GOV_LIMITS);
}
cpufreq_cpu_put(i);
}
/* now we can safely remove it from the list */
list_del(&governor->governor_list); list_del(&governor->governor_list);
up(&cpufreq_governor_sem); up(&cpufreq_governor_sem);
return; return;
...@@ -859,37 +874,3 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) ...@@ -859,37 +874,3 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
#ifdef CONFIG_PM
/**
* cpufreq_restore - restore the CPU clock frequency after resume
*
* Restore the CPU clock frequency so that our idea of the current
* frequency reflects the actual hardware.
*/
static int cpufreq_restore(struct sys_device * sysdev)
{
int cpu = sysdev->id;
unsigned int ret = 0;
struct cpufreq_policy policy;
if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) {
down(&cpufreq_driver_sem);
memcpy(&policy, &cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem);
ret = cpufreq_set_policy(&policy);
cpufreq_cpu_put(cpu);
}
return ret;
}
#else
static int cpufreq_restore(struct sys_device * sysdev)
{
return 0;
}
#endif /* CONFIG_PM */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment