summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.osdl.org>2003-07-08 19:02:56 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-07-08 19:02:56 -0700
commit4eabfbb6a9262dfd7847bf012a877550622109ff (patch)
treeb91a0cd331e9e26cb4fa573f3b20557af3f21bd8
parent85bce232bf44169f8110229ff5a238f5f41aff92 (diff)
parent2342d6cbe6cd1c7d0fa7a16decab5ff346f17c07 (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.txt16
-rw-r--r--drivers/cpufreq/Makefile7
-rw-r--r--drivers/cpufreq/proc_intf.c2
-rw-r--r--include/linux/cpufreq.h73
-rw-r--r--kernel/cpufreq.c115
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 */