Commit 7cc3ef9a authored by Linus Torvalds's avatar Linus Torvalds

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

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 26a97bb1 ce2d3f00
...@@ -242,6 +242,8 @@ static int __init elanfreq_init(void) ...@@ -242,6 +242,8 @@ static int __init elanfreq_init(void)
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
...@@ -260,8 +262,6 @@ static int __init elanfreq_init(void) ...@@ -260,8 +262,6 @@ static int __init elanfreq_init(void)
driver->verify = &elanfreq_verify; driver->verify = &elanfreq_verify;
driver->setpolicy = &elanfreq_setpolicy; driver->setpolicy = &elanfreq_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "elanfreq", CPUFREQ_NAME_LEN); strncpy(driver->name, "elanfreq", CPUFREQ_NAME_LEN);
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
......
...@@ -431,11 +431,15 @@ static int __init cpufreq_gx_init(void) ...@@ -431,11 +431,15 @@ static int __init cpufreq_gx_init(void)
driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (driver == NULL) if (driver == NULL)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL); params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
if (params == NULL) { if (params == NULL) {
kfree(driver); kfree(driver);
return -ENOMEM; return -ENOMEM;
} }
memset(params, 0, sizeof(struct gxfreq_params));
driver->policy = (struct cpufreq_policy *)(driver + 1); driver->policy = (struct cpufreq_policy *)(driver + 1);
params->cs55x0 = gx_pci; params->cs55x0 = gx_pci;
......
...@@ -762,6 +762,8 @@ static int __init longhaul_init (void) ...@@ -762,6 +762,8 @@ static int __init longhaul_init (void)
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
...@@ -771,8 +773,7 @@ static int __init longhaul_init (void) ...@@ -771,8 +773,7 @@ static int __init longhaul_init (void)
driver->verify = &longhaul_verify; driver->verify = &longhaul_verify;
driver->setpolicy = &longhaul_setpolicy; driver->setpolicy = &longhaul_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "longhaul", CPUFREQ_NAME_LEN); strncpy(driver->name, "longhaul", CPUFREQ_NAME_LEN);
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
......
...@@ -54,7 +54,7 @@ static void longrun_get_policy(struct cpufreq_policy *policy) ...@@ -54,7 +54,7 @@ static void longrun_get_policy(struct cpufreq_policy *policy)
policy->min = longrun_low_freq + msr_lo * policy->min = longrun_low_freq + msr_lo *
((longrun_high_freq - longrun_low_freq) / 100); ((longrun_high_freq - longrun_low_freq) / 100);
policy->min = longrun_low_freq + msr_hi * policy->max = longrun_low_freq + msr_hi *
((longrun_high_freq - longrun_low_freq) / 100); ((longrun_high_freq - longrun_low_freq) / 100);
policy->cpu = 0; policy->cpu = 0;
} }
...@@ -241,6 +241,8 @@ static int __init longrun_init(void) ...@@ -241,6 +241,8 @@ static int __init longrun_init(void)
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
...@@ -251,8 +253,7 @@ static int __init longrun_init(void) ...@@ -251,8 +253,7 @@ static int __init longrun_init(void)
driver->policy[0].cpuinfo.min_freq = longrun_low_freq; driver->policy[0].cpuinfo.min_freq = longrun_low_freq;
driver->policy[0].cpuinfo.max_freq = longrun_high_freq; driver->policy[0].cpuinfo.max_freq = longrun_high_freq;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "longrun", CPUFREQ_NAME_LEN); strncpy(driver->name, "longrun", CPUFREQ_NAME_LEN);
longrun_get_policy(&driver->policy[0]); longrun_get_policy(&driver->policy[0]);
......
...@@ -220,6 +220,8 @@ static int __init cpufreq_p4_init(void) ...@@ -220,6 +220,8 @@ static int __init cpufreq_p4_init(void)
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
...@@ -240,8 +242,6 @@ static int __init cpufreq_p4_init(void) ...@@ -240,8 +242,6 @@ static int __init cpufreq_p4_init(void)
driver->verify = &cpufreq_p4_verify; driver->verify = &cpufreq_p4_verify;
driver->setpolicy = &cpufreq_p4_setpolicy; driver->setpolicy = &cpufreq_p4_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "p4-clockmod", CPUFREQ_NAME_LEN); strncpy(driver->name, "p4-clockmod", CPUFREQ_NAME_LEN);
for (i=0;i<NR_CPUS;i++) { for (i=0;i<NR_CPUS;i++) {
......
...@@ -172,6 +172,8 @@ static int __init powernow_k6_init(void) ...@@ -172,6 +172,8 @@ static int __init powernow_k6_init(void)
release_region (POWERNOW_IOPORT, 16); release_region (POWERNOW_IOPORT, 16);
return -ENOMEM; return -ENOMEM;
} }
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
/* table init */ /* table init */
...@@ -184,8 +186,6 @@ static int __init powernow_k6_init(void) ...@@ -184,8 +186,6 @@ static int __init powernow_k6_init(void)
driver->verify = &powernow_k6_verify; driver->verify = &powernow_k6_verify;
driver->setpolicy = &powernow_k6_setpolicy; driver->setpolicy = &powernow_k6_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "powernow-k6", CPUFREQ_NAME_LEN); strncpy(driver->name, "powernow-k6", CPUFREQ_NAME_LEN);
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
......
...@@ -674,6 +674,8 @@ static int __init speedstep_init(void) ...@@ -674,6 +674,8 @@ static int __init speedstep_init(void)
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1); driver->policy = (struct cpufreq_policy *) (driver + 1);
...@@ -690,8 +692,6 @@ static int __init speedstep_init(void) ...@@ -690,8 +692,6 @@ static int __init speedstep_init(void)
driver->verify = &speedstep_verify; driver->verify = &speedstep_verify;
driver->setpolicy = &speedstep_setpolicy; driver->setpolicy = &speedstep_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "speedstep", CPUFREQ_NAME_LEN); strncpy(driver->name, "speedstep", CPUFREQ_NAME_LEN);
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
* linux/include/linux/cpufreq.h * linux/include/linux/cpufreq.h
* *
* Copyright (C) 2001 Russell King * Copyright (C) 2001 Russell King
* (C) 2002 Dominik Brodowski <linux@brodo.de> * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
* *
* *
* $Id: cpufreq.h,v 1.29 2002/11/11 15:35:47 db Exp $ * $Id: cpufreq.h,v 1.36 2003/01/20 17:31:48 db Exp $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <linux/device.h> #include <linux/device.h>
#define CPUFREQ_NAME_LEN 16
/********************************************************************* /*********************************************************************
* CPUFREQ NOTIFIER INTERFACE * * CPUFREQ NOTIFIER INTERFACE *
*********************************************************************/ *********************************************************************/
...@@ -37,14 +40,17 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); ...@@ -37,14 +40,17 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
#define CPUFREQ_POLICY_POWERSAVE (1) #define CPUFREQ_POLICY_POWERSAVE (1)
#define CPUFREQ_POLICY_PERFORMANCE (2) #define CPUFREQ_POLICY_PERFORMANCE (2)
#define CPUFREQ_POLICY_GOVERNOR (3)
/* Frequency values here are CPU kHz so that hardware which doesn't run /* Frequency values here are CPU kHz so that hardware which doesn't run
* with some frequencies can complain without having to guess what per * with some frequencies can complain without having to guess what per
* cent / per mille means. * cent / per mille means.
* Maximum transition latency is in nanoseconds - if it's unknown, * Maximum transition latency is in microseconds - if it's unknown,
* CPUFREQ_ETERNAL shall be used. * CPUFREQ_ETERNAL shall be used.
*/ */
struct cpufreq_governor;
#define CPUFREQ_ETERNAL (-1) #define CPUFREQ_ETERNAL (-1)
struct cpufreq_cpuinfo { struct cpufreq_cpuinfo {
unsigned int max_freq; unsigned int max_freq;
...@@ -57,6 +63,7 @@ struct cpufreq_policy { ...@@ -57,6 +63,7 @@ struct cpufreq_policy {
unsigned int min; /* in kHz */ unsigned int min; /* in kHz */
unsigned int max; /* in kHz */ unsigned int max; /* in kHz */
unsigned int policy; /* see above */ unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
struct cpufreq_cpuinfo cpuinfo; /* see above */ struct cpufreq_cpuinfo cpuinfo; /* see above */
struct intf_data intf; /* interface data */ struct intf_data intf; /* interface data */
}; };
...@@ -104,25 +111,62 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu ...@@ -104,25 +111,62 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu
return carry + val; return carry + val;
}; };
/*********************************************************************
* CPUFREQ GOVERNORS *
*********************************************************************/
#define CPUFREQ_GOV_START 1
#define CPUFREQ_GOV_STOP 2
#define CPUFREQ_GOV_LIMITS 3
struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN];
int (*governor) (struct cpufreq_policy *policy,
unsigned int event);
struct list_head governor_list;
struct module *owner;
};
/* pass a target to the cpufreq driver
* _l : (cpufreq_driver_sem is not held)
*/
inline int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
inline int cpufreq_driver_target_l(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
/* pass an event to the cpufreq governor */
int cpufreq_governor_l(unsigned int cpu, unsigned int event);
int cpufreq_register_governor(struct cpufreq_governor *governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor);
/********************************************************************* /*********************************************************************
* CPUFREQ DRIVER INTERFACE * * CPUFREQ DRIVER INTERFACE *
*********************************************************************/ *********************************************************************/
#define CPUFREQ_NAME_LEN 16 #define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */
struct cpufreq_driver { struct cpufreq_driver {
/* needed by all drivers */ /* needed by all drivers */
int (*verify) (struct cpufreq_policy *policy); int (*verify) (struct cpufreq_policy *policy);
int (*setpolicy) (struct cpufreq_policy *policy); struct cpufreq_policy *policy;
struct cpufreq_policy *policy; char name[CPUFREQ_NAME_LEN];
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);
/* optional, for the moment */ /* optional, for the moment */
int (*init) (struct cpufreq_policy *policy); int (*init) (struct cpufreq_policy *policy);
int (*exit) (struct cpufreq_policy *policy); int (*exit) (struct cpufreq_policy *policy);
/* 2.4. compatible API */ /* 2.4. compatible API */
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
unsigned int cpu_cur_freq[NR_CPUS]; unsigned int cpu_cur_freq[NR_CPUS];
#endif #endif
}; };
...@@ -276,4 +320,10 @@ int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy, ...@@ -276,4 +320,10 @@ int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table, struct cpufreq_frequency_table *table,
unsigned int *index); unsigned int *index);
int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int target_freq,
unsigned int relation,
unsigned int *index);
#endif /* _LINUX_CPUFREQ_H */ #endif /* _LINUX_CPUFREQ_H */
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
* linux/kernel/cpufreq.c * linux/kernel/cpufreq.c
* *
* Copyright (C) 2001 Russell King * Copyright (C) 2001 Russell King
* (C) 2002 Dominik Brodowski <linux@brodo.de> * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
* *
* $Id: cpufreq.c,v 1.50 2002/11/11 15:35:48 db Exp $ * $Id: cpufreq.c,v 1.59 2003/01/20 17:31:48 db Exp $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif #endif
/** /**
* The "cpufreq driver" - the arch- or hardware-dependend low * The "cpufreq driver" - the arch- or hardware-dependend low
* level driver of CPUFreq support, and its locking mutex. * level driver of CPUFreq support, and its locking mutex.
...@@ -67,6 +66,9 @@ static unsigned int cpu_min_freq[NR_CPUS]; ...@@ -67,6 +66,9 @@ static unsigned int cpu_min_freq[NR_CPUS];
static unsigned int cpu_cur_freq[NR_CPUS]; static unsigned int cpu_cur_freq[NR_CPUS];
#endif #endif
LIST_HEAD(cpufreq_governor_list);
static int cpufreq_governor(unsigned int cpu, unsigned int event);
/********************************************************************* /*********************************************************************
* SYSFS INTERFACE * * SYSFS INTERFACE *
...@@ -75,16 +77,31 @@ static unsigned int cpu_cur_freq[NR_CPUS]; ...@@ -75,16 +77,31 @@ static unsigned int cpu_cur_freq[NR_CPUS];
/** /**
* cpufreq_parse_governor - parse a governor string * cpufreq_parse_governor - parse a governor string
*/ */
static int cpufreq_parse_governor (char *str_governor, unsigned int *governor) static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor)
{ {
if (!strnicmp(str_governor, "performance", 11)) { if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*governor = CPUFREQ_POLICY_PERFORMANCE; *policy = CPUFREQ_POLICY_PERFORMANCE;
return 0; return 0;
} else if (!strnicmp(str_governor, "powersave", 9)) { } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
*governor = CPUFREQ_POLICY_POWERSAVE; *policy = CPUFREQ_POLICY_POWERSAVE;
return 0; return 0;
} else } else {
return -EINVAL; struct cpufreq_governor *t;
down(&cpufreq_driver_sem);
if (!cpufreq_driver || !cpufreq_driver->target)
goto out;
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
*governor = t;
*policy = CPUFREQ_POLICY_GOVERNOR;
up(&cpufreq_driver_sem);
return 0;
}
}
out:
up(&cpufreq_driver_sem);
}
return -EINVAL;
} }
...@@ -171,6 +188,8 @@ static ssize_t store_##file_name \ ...@@ -171,6 +188,8 @@ static ssize_t store_##file_name \
static ssize_t show_scaling_governor (struct device *dev, char *buf) static ssize_t show_scaling_governor (struct device *dev, char *buf)
{ {
unsigned int value = 0; unsigned int value = 0;
char value2[CPUFREQ_NAME_LEN];
if (!dev) if (!dev)
return 0; return 0;
...@@ -178,6 +197,8 @@ static ssize_t show_scaling_governor (struct device *dev, char *buf) ...@@ -178,6 +197,8 @@ static ssize_t show_scaling_governor (struct device *dev, char *buf)
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
if (cpufreq_driver) if (cpufreq_driver)
value = cpufreq_driver->policy[to_cpu_nr(dev)].policy; value = cpufreq_driver->policy[to_cpu_nr(dev)].policy;
if (value == CPUFREQ_POLICY_GOVERNOR)
strncpy(value2, cpufreq_driver->policy[to_cpu_nr(dev)].governor->name, CPUFREQ_NAME_LEN);
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
switch (value) { switch (value) {
...@@ -185,6 +206,8 @@ static ssize_t show_scaling_governor (struct device *dev, char *buf) ...@@ -185,6 +206,8 @@ static ssize_t show_scaling_governor (struct device *dev, char *buf)
return sprintf(buf, "powersave\n"); return sprintf(buf, "powersave\n");
case CPUFREQ_POLICY_PERFORMANCE: case CPUFREQ_POLICY_PERFORMANCE:
return sprintf(buf, "performance\n"); return sprintf(buf, "performance\n");
case CPUFREQ_POLICY_GOVERNOR:
return sprintf(buf, "%s\n", value2);
} }
return -EINVAL; return -EINVAL;
...@@ -212,7 +235,7 @@ store_scaling_governor (struct device *dev, const char *buf, size_t count) ...@@ -212,7 +235,7 @@ store_scaling_governor (struct device *dev, const char *buf, size_t count)
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
if (cpufreq_parse_governor(str_governor, &policy.policy)) if (cpufreq_parse_governor(str_governor, &policy.policy, &policy.governor))
return -EINVAL; return -EINVAL;
ret = cpufreq_set_policy(&policy); ret = cpufreq_set_policy(&policy);
...@@ -241,6 +264,34 @@ static ssize_t show_scaling_driver (struct device *dev, char *buf) ...@@ -241,6 +264,34 @@ static ssize_t show_scaling_driver (struct device *dev, char *buf)
return sprintf(buf, "%s\n", value); return sprintf(buf, "%s\n", value);
} }
/**
* show_available_govs - show the available CPUfreq governors
*/
static ssize_t show_available_govs(struct device *dev, char *buf)
{
ssize_t i = 0;
struct cpufreq_governor *t;
if (!dev)
return 0;
i += sprintf(buf, "performance powersave");
down(&cpufreq_driver_sem);
if (!cpufreq_driver || !cpufreq_driver->target)
goto out;
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2)))
goto out;
i += snprintf(&buf[i], CPUFREQ_NAME_LEN, " %s", t->name);
}
out:
up(&cpufreq_driver_sem);
i += sprintf(&buf[i], "\n");
return i;
}
/** /**
* cpufreq_per_cpu_attr_ro - read-only cpufreq per-CPU file * cpufreq_per_cpu_attr_ro - read-only cpufreq per-CPU file
...@@ -267,6 +318,7 @@ cpufreq_per_cpu_attr_rw(scaling_max_freq, max); ...@@ -267,6 +318,7 @@ cpufreq_per_cpu_attr_rw(scaling_max_freq, max);
static DEVICE_ATTR(scaling_governor, (S_IRUGO | S_IWUSR), show_scaling_governor, store_scaling_governor); static DEVICE_ATTR(scaling_governor, (S_IRUGO | S_IWUSR), show_scaling_governor, store_scaling_governor);
static DEVICE_ATTR(scaling_driver, S_IRUGO, show_scaling_driver, NULL); static DEVICE_ATTR(scaling_driver, S_IRUGO, show_scaling_driver, NULL);
static DEVICE_ATTR(available_scaling_governors, S_IRUGO, show_available_govs, NULL);
/** /**
...@@ -299,10 +351,12 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -299,10 +351,12 @@ static int cpufreq_add_dev (struct device * dev)
} }
/* set default policy on this CPU */ /* set default policy on this CPU */
policy.policy = cpufreq_driver->policy[cpu].policy; memcpy(&policy,
policy.min = cpufreq_driver->policy[cpu].min; &cpufreq_driver->policy[cpu],
policy.max = cpufreq_driver->policy[cpu].max; sizeof(struct cpufreq_policy));
policy.cpu = cpu;
if (cpufreq_driver->target)
cpufreq_governor(cpu, CPUFREQ_GOV_START);
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
ret = cpufreq_set_policy(&policy); ret = cpufreq_set_policy(&policy);
...@@ -339,6 +393,7 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -339,6 +393,7 @@ static int cpufreq_add_dev (struct device * dev)
device_create_file (dev, &dev_attr_scaling_max_freq); device_create_file (dev, &dev_attr_scaling_max_freq);
device_create_file (dev, &dev_attr_scaling_governor); device_create_file (dev, &dev_attr_scaling_governor);
device_create_file (dev, &dev_attr_scaling_driver); device_create_file (dev, &dev_attr_scaling_driver);
device_create_file (dev, &dev_attr_available_scaling_governors);
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return ret; return ret;
...@@ -356,6 +411,9 @@ static int cpufreq_remove_dev (struct intf_data *intf) ...@@ -356,6 +411,9 @@ static int cpufreq_remove_dev (struct intf_data *intf)
struct device * dev = intf->dev; struct device * dev = intf->dev;
unsigned int cpu = to_cpu_nr(dev); unsigned int cpu = to_cpu_nr(dev);
if (cpufreq_driver->target)
cpufreq_governor(cpu, CPUFREQ_GOV_STOP);
if (cpufreq_driver->exit) if (cpufreq_driver->exit)
cpufreq_driver->exit(&cpufreq_driver->policy[cpu]); cpufreq_driver->exit(&cpufreq_driver->policy[cpu]);
...@@ -364,7 +422,8 @@ static int cpufreq_remove_dev (struct intf_data *intf) ...@@ -364,7 +422,8 @@ static int cpufreq_remove_dev (struct intf_data *intf)
device_remove_file (dev, &dev_attr_scaling_min_freq); device_remove_file (dev, &dev_attr_scaling_min_freq);
device_remove_file (dev, &dev_attr_scaling_max_freq); device_remove_file (dev, &dev_attr_scaling_max_freq);
device_remove_file (dev, &dev_attr_scaling_governor); device_remove_file (dev, &dev_attr_scaling_governor);
device_remove_file (dev, &dev_attr_scaling_governor); device_remove_file (dev, &dev_attr_scaling_driver);
device_remove_file (dev, &dev_attr_available_scaling_governors);
return 0; return 0;
} }
...@@ -443,12 +502,11 @@ static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *po ...@@ -443,12 +502,11 @@ static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *po
return -EINVAL; return -EINVAL;
scan_policy: scan_policy:
result = cpufreq_parse_governor(str_governor, &policy->policy); result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
return result; return result;
} }
/** /**
* cpufreq_proc_read - read /proc/cpufreq * cpufreq_proc_read - read /proc/cpufreq
* *
...@@ -477,7 +535,8 @@ static int cpufreq_proc_read ( ...@@ -477,7 +535,8 @@ static int cpufreq_proc_read (
if (!cpu_online(i)) if (!cpu_online(i))
continue; continue;
cpufreq_get_policy(&policy, i); if (cpufreq_get_policy(&policy, i))
continue;
if (!policy.cpuinfo.max_freq) if (!policy.cpuinfo.max_freq)
continue; continue;
...@@ -494,6 +553,9 @@ static int cpufreq_proc_read ( ...@@ -494,6 +553,9 @@ static int cpufreq_proc_read (
case CPUFREQ_POLICY_PERFORMANCE: case CPUFREQ_POLICY_PERFORMANCE:
p += sprintf(p, "performance\n"); p += sprintf(p, "performance\n");
break; break;
case CPUFREQ_POLICY_GOVERNOR:
p += snprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
break;
default: default:
p += sprintf(p, "INVALID\n"); p += sprintf(p, "INVALID\n");
break; break;
...@@ -1065,6 +1127,136 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) ...@@ -1065,6 +1127,136 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
EXPORT_SYMBOL(cpufreq_unregister_notifier); EXPORT_SYMBOL(cpufreq_unregister_notifier);
/*********************************************************************
* GOVERNORS *
*********************************************************************/
inline int cpufreq_driver_target_l(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int ret;
down(&cpufreq_driver_sem);
if (!cpufreq_driver)
ret = -EINVAL;
else
ret = cpufreq_driver->target(policy, target_freq, relation);
up(&cpufreq_driver_sem);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target_l);
inline int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
return cpufreq_driver->target(policy, target_freq, relation);
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
static int cpufreq_governor(unsigned int cpu, unsigned int event)
{
int ret = 0;
struct cpufreq_policy *policy = &cpufreq_driver->policy[cpu];
switch (policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START))
ret = cpufreq_driver->target(policy, policy->min, CPUFREQ_RELATION_L);
break;
case CPUFREQ_POLICY_PERFORMANCE:
if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START))
ret = cpufreq_driver->target(policy, policy->max, CPUFREQ_RELATION_H);
break;
case CPUFREQ_POLICY_GOVERNOR:
ret = -EINVAL;
if (event == CPUFREQ_GOV_START)
if (!try_module_get(cpufreq_driver->policy[cpu].governor->owner))
break;
ret = cpufreq_driver->policy[cpu].governor->governor(policy, event);
if ((event == CPUFREQ_GOV_STOP) ||
(ret && (event == CPUFREQ_GOV_START)))
module_put(cpufreq_driver->policy[cpu].governor->owner);
break;
default:
ret = -EINVAL;
}
return ret;
}
int cpufreq_governor_l(unsigned int cpu, unsigned int event)
{
int ret = 0;
down(&cpufreq_driver_sem);
ret = cpufreq_governor(cpu, event);
up(&cpufreq_driver_sem);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_governor_l);
int cpufreq_register_governor(struct cpufreq_governor *governor)
{
struct cpufreq_governor *t;
if (!governor)
return -EINVAL;
if (!strnicmp(governor->name,"powersave",CPUFREQ_NAME_LEN))
return -EBUSY;
if (!strnicmp(governor->name,"performance",CPUFREQ_NAME_LEN))
return -EBUSY;
down(&cpufreq_driver_sem);
list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
up(&cpufreq_driver_sem);
return -EBUSY;
}
}
list_add(&governor->governor_list, &cpufreq_governor_list);
up(&cpufreq_driver_sem);
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
unsigned int i;
if (!governor)
return;
down(&cpufreq_driver_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_driver &&
(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);
}
}
/* now we can safely remove it from the list */
list_del(&governor->governor_list);
up(&cpufreq_driver_sem);
return;
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
/********************************************************************* /*********************************************************************
* POLICY INTERFACE * * POLICY INTERFACE *
...@@ -1084,15 +1276,11 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) ...@@ -1084,15 +1276,11 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return -EINVAL; return -EINVAL;
} }
policy->min = cpufreq_driver->policy[cpu].min;
policy->max = cpufreq_driver->policy[cpu].max;
policy->policy = cpufreq_driver->policy[cpu].policy;
policy->cpuinfo.max_freq = cpufreq_driver->policy[cpu].cpuinfo.max_freq;
policy->cpuinfo.min_freq = cpufreq_driver->policy[cpu].cpuinfo.min_freq;
policy->cpuinfo.transition_latency = cpufreq_driver->policy[cpu].cpuinfo.transition_latency;
policy->cpu = cpu;
memcpy(policy,
&cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return 0; return 0;
...@@ -1111,16 +1299,15 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) ...@@ -1111,16 +1299,15 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
int ret; int ret;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
if (!cpufreq_driver || !cpufreq_driver->verify || if (!cpufreq_driver || !policy ||
!cpufreq_driver->setpolicy || !policy ||
(policy->cpu >= NR_CPUS) || (!cpu_online(policy->cpu))) { (policy->cpu >= NR_CPUS) || (!cpu_online(policy->cpu))) {
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return -EINVAL; return -EINVAL;
} }
policy->cpuinfo.max_freq = cpufreq_driver->policy[policy->cpu].cpuinfo.max_freq; memcpy(&policy->cpuinfo,
policy->cpuinfo.min_freq = cpufreq_driver->policy[policy->cpu].cpuinfo.min_freq; &cpufreq_driver->policy[policy->cpu].cpuinfo,
policy->cpuinfo.transition_latency = cpufreq_driver->policy[policy->cpu].cpuinfo.transition_latency; sizeof(struct cpufreq_cpuinfo));
/* verify the cpu speed can be set within this limit */ /* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(policy); ret = cpufreq_driver->verify(policy);
...@@ -1156,13 +1343,35 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) ...@@ -1156,13 +1343,35 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
cpufreq_driver->policy[policy->cpu].min = policy->min; cpufreq_driver->policy[policy->cpu].min = policy->min;
cpufreq_driver->policy[policy->cpu].max = policy->max; cpufreq_driver->policy[policy->cpu].max = policy->max;
cpufreq_driver->policy[policy->cpu].policy = policy->policy;
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
cpu_cur_freq[policy->cpu] = policy->max; cpu_cur_freq[policy->cpu] = policy->max;
#endif #endif
ret = cpufreq_driver->setpolicy(policy); if (cpufreq_driver->setpolicy) {
cpufreq_driver->policy[policy->cpu].policy = policy->policy;
ret = cpufreq_driver->setpolicy(policy);
} else {
if ((policy->policy != cpufreq_driver->policy[policy->cpu].policy) ||
((policy->policy == CPUFREQ_POLICY_GOVERNOR) && (policy->governor != cpufreq_driver->policy[policy->cpu].governor))) {
unsigned int old_pol = cpufreq_driver->policy[policy->cpu].policy;
struct cpufreq_governor *old_gov = cpufreq_driver->policy[policy->cpu].governor;
/* end old governor */
cpufreq_governor(policy->cpu, CPUFREQ_GOV_STOP);
cpufreq_driver->policy[policy->cpu].policy = policy->policy;
cpufreq_driver->policy[policy->cpu].governor = policy->governor;
/* start new governor */
if (cpufreq_governor(policy->cpu, CPUFREQ_GOV_START)) {
cpufreq_driver->policy[policy->cpu].policy = old_pol;
cpufreq_driver->policy[policy->cpu].governor = old_gov;
cpufreq_governor(policy->cpu, CPUFREQ_GOV_START);
}
/* might be a policy change, too */
cpufreq_governor(policy->cpu, CPUFREQ_GOV_LIMITS);
} else {
cpufreq_governor(policy->cpu, CPUFREQ_GOV_LIMITS);
}
}
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
...@@ -1253,7 +1462,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -1253,7 +1462,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return -EBUSY; return -EBUSY;
if (!driver_data || !driver_data->verify || if (!driver_data || !driver_data->verify ||
!driver_data->setpolicy) ((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL; return -EINVAL;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
...@@ -1271,6 +1480,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -1271,6 +1480,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return -ENOMEM; return -ENOMEM;
} }
memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy));
} }
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
...@@ -1359,11 +1569,8 @@ int cpufreq_restore(void) ...@@ -1359,11 +1569,8 @@ int cpufreq_restore(void)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return 0; return 0;
} }
policy.min = cpufreq_driver->policy[i].min; memcpy(&policy, &cpufreq_driver->policy[i], sizeof(struct cpufreq_policy));
policy.max = cpufreq_driver->policy[i].max;
policy.policy = cpufreq_driver->policy[i].policy;
policy.cpu = i;
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
ret += cpufreq_set_policy(&policy); ret += cpufreq_set_policy(&policy);
...@@ -1493,3 +1700,73 @@ int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy, ...@@ -1493,3 +1700,73 @@ int cpufreq_frequency_table_setpolicy(struct cpufreq_policy *policy,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_setpolicy); EXPORT_SYMBOL_GPL(cpufreq_frequency_table_setpolicy);
int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table,
unsigned int target_freq,
unsigned int relation,
unsigned int *index)
{
struct cpufreq_frequency_table optimal = { .index = ~0, };
struct cpufreq_frequency_table suboptimal = { .index = ~0, };
unsigned int i;
switch (relation) {
case CPUFREQ_RELATION_H:
optimal.frequency = 0;
suboptimal.frequency = ~0;
break;
case CPUFREQ_RELATION_L:
optimal.frequency = ~0;
suboptimal.frequency = 0;
break;
}
if (!cpu_online(policy->cpu))
return -EINVAL;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
if ((freq < policy->min) || (freq > policy->max))
continue;
switch(relation) {
case CPUFREQ_RELATION_H:
if (freq <= target_freq) {
if (freq >= optimal.frequency) {
optimal.frequency = freq;
optimal.index = i;
}
} else {
if (freq <= suboptimal.frequency) {
suboptimal.frequency = freq;
suboptimal.index = i;
}
}
break;
case CPUFREQ_RELATION_L:
if (freq >= target_freq) {
if (freq <= optimal.frequency) {
optimal.frequency = freq;
optimal.index = i;
}
} else {
if (freq >= suboptimal.frequency) {
suboptimal.frequency = freq;
suboptimal.index = i;
}
}
break;
}
}
if (optimal.index > i) {
if (suboptimal.index > i)
return -EINVAL;
*index = suboptimal.index;
} else
*index = optimal.index;
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
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