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:
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" ?
==========================
......
#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
......@@ -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.
......
......@@ -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 */
......@@ -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 */
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