diff options
| author | Linus Torvalds <torvalds@home.osdl.org> | 2003-07-08 19:02:56 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-07-08 19:02:56 -0700 |
| commit | 4eabfbb6a9262dfd7847bf012a877550622109ff (patch) | |
| tree | b91a0cd331e9e26cb4fa573f3b20557af3f21bd8 | |
| parent | 85bce232bf44169f8110229ff5a238f5f41aff92 (diff) | |
| parent | 2342d6cbe6cd1c7d0fa7a16decab5ff346f17c07 (diff) | |
Merge bk://linux-dj.bkbits.net/cpufreq
into home.osdl.org:/home/torvalds/v2.5/linux
| -rw-r--r-- | Documentation/cpu-freq/user-guide.txt | 16 | ||||
| -rw-r--r-- | drivers/cpufreq/Makefile | 7 | ||||
| -rw-r--r-- | drivers/cpufreq/proc_intf.c | 2 | ||||
| -rw-r--r-- | include/linux/cpufreq.h | 73 | ||||
| -rw-r--r-- | kernel/cpufreq.c | 115 |
5 files changed, 109 insertions, 104 deletions
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt index fc206075944d..76934ca5030c 100644 --- a/Documentation/cpu-freq/user-guide.txt +++ b/Documentation/cpu-freq/user-guide.txt @@ -21,6 +21,8 @@ Contents: 1.1 ARM 1.2 x86 1.3 sparc64 +1.4 ppc +1.5 SuperH 2. "Policy" / "Governor"? 2.1 Policy @@ -77,6 +79,20 @@ cpufreq: 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" ? ========================== diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b05d3948b8e1..85b512348acd 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -1,4 +1,7 @@ -#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_PROC_INTF) += proc_intf.o -obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o + diff --git a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c index dc89b83710b8..d314e526af9c 100644 --- a/drivers/cpufreq/proc_intf.c +++ b/drivers/cpufreq/proc_intf.c @@ -13,6 +13,8 @@ #include <asm/uaccess.h> +#define CPUFREQ_ALL_CPUS ((NR_CPUS)) + /** * cpufreq_parse_policy - parse a policy string * @input_string: the string to parse. diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 1bdb797bf9bd..dc29d5c4e713 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/kobject.h> #include <linux/sysfs.h> +#include <linux/completion.h> #define CPUFREQ_NAME_LEN 16 @@ -31,17 +32,15 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); -#define CPUFREQ_TRANSITION_NOTIFIER (0) -#define CPUFREQ_POLICY_NOTIFIER (1) - -#define CPUFREQ_ALL_CPUS ((NR_CPUS)) +#define CPUFREQ_TRANSITION_NOTIFIER (0) +#define CPUFREQ_POLICY_NOTIFIER (1) /********************** cpufreq policy notifiers *********************/ -#define CPUFREQ_POLICY_POWERSAVE (1) -#define CPUFREQ_POLICY_PERFORMANCE (2) -#define CPUFREQ_POLICY_GOVERNOR (3) +#define CPUFREQ_POLICY_POWERSAVE (1) +#define CPUFREQ_POLICY_PERFORMANCE (2) +#define CPUFREQ_POLICY_GOVERNOR (3) /* Frequency values here are CPU kHz so that hardware which doesn't run * with some frequencies can complain without having to guess what per @@ -52,30 +51,34 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); struct cpufreq_governor; -#define CPUFREQ_ETERNAL (-1) +#define CPUFREQ_ETERNAL (-1) struct cpufreq_cpuinfo { - unsigned int max_freq; - unsigned int min_freq; - unsigned int transition_latency; + unsigned int max_freq; + unsigned int min_freq; + unsigned int transition_latency; /* in 10^(-9) s */ }; struct cpufreq_policy { - unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ - unsigned int min; /* in kHz */ - unsigned int max; /* in kHz */ - unsigned int cur; /* in kHz, only needed if cpufreq + unsigned int cpu; /* cpu nr */ + struct cpufreq_cpuinfo cpuinfo;/* see above */ + + unsigned int min; /* in kHz */ + unsigned int max; /* in kHz */ + unsigned int cur; /* in kHz, only needed if cpufreq * governors are used */ - unsigned int policy; /* see above */ - struct cpufreq_governor *governor; /* see below */ - struct cpufreq_cpuinfo cpuinfo; /* see above */ - struct kobject kobj; + unsigned int policy; /* see above */ + struct cpufreq_governor *governor; /* see below */ + struct semaphore lock; /* CPU ->setpolicy or ->target may only be called once a time */ + + struct kobject kobj; + struct completion kobj_unregister; }; -#define CPUFREQ_ADJUST (0) -#define CPUFREQ_INCOMPATIBLE (1) -#define CPUFREQ_NOTIFY (2) +#define CPUFREQ_ADJUST (0) +#define CPUFREQ_INCOMPATIBLE (1) +#define CPUFREQ_NOTIFY (2) /******************** cpufreq transition notifiers *******************/ @@ -84,7 +87,7 @@ struct cpufreq_policy { #define CPUFREQ_POSTCHANGE (1) struct cpufreq_freqs { - unsigned int cpu; /* cpu nr or CPUFREQ_ALL_CPUS */ + unsigned int cpu; /* cpu nr */ unsigned int old; unsigned int new; }; @@ -125,11 +128,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu #define CPUFREQ_GOV_LIMITS 3 struct cpufreq_governor { - char name[CPUFREQ_NAME_LEN]; - int (*governor) (struct cpufreq_policy *policy, + char name[CPUFREQ_NAME_LEN]; + int (*governor) (struct cpufreq_policy *policy, unsigned int event); struct list_head governor_list; - struct module *owner; + struct module *owner; }; /* pass a target to the cpufreq driver @@ -154,18 +157,22 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor); struct freq_attr; struct cpufreq_driver { + struct module *owner; + char name[CPUFREQ_NAME_LEN]; + + struct cpufreq_policy *policy; + /* needed by all drivers */ + int (*init) (struct cpufreq_policy *policy); int (*verify) (struct cpufreq_policy *policy); - struct cpufreq_policy *policy; - char name[CPUFREQ_NAME_LEN]; + /* define one out of two */ int (*setpolicy) (struct cpufreq_policy *policy); int (*target) (struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation); - struct module *owner; - /* optional, for the moment */ - int (*init) (struct cpufreq_policy *policy); + + /* optional */ int (*exit) (struct cpufreq_policy *policy); struct freq_attr **attr; }; @@ -306,8 +313,4 @@ void cpufreq_frequency_table_put_attr(unsigned int cpu); #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 */ diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c index 6ae2b821830e..f4864ce54aae 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -23,6 +23,7 @@ #include <linux/device.h> #include <linux/slab.h> #include <linux/cpu.h> +#include <linux/completion.h> /** * The "cpufreq driver" - the arch- or hardware-dependend low @@ -297,6 +298,12 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, 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 = { .show = show, .store = store, @@ -305,6 +312,7 @@ static struct sysfs_ops sysfs_ops = { static struct kobj_type ktype_cpufreq = { .sysfs_ops = &sysfs_ops, .default_attrs = default_attrs, + .release = cpufreq_sysfs_release, }; @@ -329,11 +337,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) */ policy = &cpufreq_driver->policy[cpu]; policy->cpu = cpu; - if (cpufreq_driver->init) { - ret = cpufreq_driver->init(policy); - if (ret) - goto out; - } + ret = cpufreq_driver->init(policy); + if (ret) + goto out; /* set default policy on this CPU */ down(&cpufreq_driver_sem); @@ -343,6 +349,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) up(&cpufreq_driver_sem); init_MUTEX(&policy->lock); + init_completion(&policy->kobj_unregister); + /* prepare interface data */ policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; @@ -352,18 +360,19 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) if (ret) goto out; + /* set up files for this cpu device */ drv_attr = cpufreq_driver->attr; while ((drv_attr) && (*drv_attr)) { sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); drv_attr++; } - /* set up files for this cpu device */ - /* set default policy */ ret = cpufreq_set_policy(&new_policy); - if (ret) + if (ret) { kobject_unregister(&policy->kobj); + wait_for_completion(&policy->kobj_unregister); + } out: module_put(cpufreq_driver->owner); @@ -401,10 +410,39 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) up(&cpufreq_driver_sem); 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; } -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 = { .add = cpufreq_add_dev, @@ -587,33 +625,10 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor); void cpufreq_unregister_governor(struct cpufreq_governor *governor) { - unsigned int i; - if (!governor) return; 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); up(&cpufreq_governor_sem); return; @@ -781,7 +796,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) switch (state) { case CPUFREQ_PRECHANGE: notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); - adjust_jiffies(CPUFREQ_PRECHANGE, freqs); + adjust_jiffies(CPUFREQ_PRECHANGE, freqs); break; case CPUFREQ_POSTCHANGE: adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); @@ -859,37 +874,3 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) return 0; } 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 */ |
