Commit d97c3377 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] cpufreq: per-CPU initialization

Allow for per-CPU initialization of CPUfreq. Therefore, it's not
necessary any longer to kmalloc the per-CPU policy struct. To use
this, cpufreq_driver->policy has to be set to NULL. Of course,
cpufreq_driver->init is needed then, which is the appropriate function
for CPU initialization. cpufreq_driver->exit is available for cleanup.

All existing drivers continue to work without any changes, just for
clarity ->init and ->exit are set to NULL, and the names accordingly.
parent 01c1180e
...@@ -166,6 +166,7 @@ static struct cpufreq_driver integrator_driver = { ...@@ -166,6 +166,7 @@ static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_speed, .verify = integrator_verify_speed,
.setpolicy = integrator_set_policy, .setpolicy = integrator_set_policy,
.policy = &integrator_policy, .policy = &integrator_policy,
.name = "integrator",
}; };
#endif #endif
......
...@@ -214,6 +214,7 @@ static struct cpufreq_driver sa1100_driver = { ...@@ -214,6 +214,7 @@ static struct cpufreq_driver sa1100_driver = {
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.setpolicy = sa1100_setspeed, .setpolicy = sa1100_setspeed,
.policy = &sa1100_policy, .policy = &sa1100_policy,
.name = "sa1100",
}; };
static int __init sa1100_dram_init(void) static int __init sa1100_dram_init(void)
......
...@@ -309,6 +309,7 @@ static struct cpufreq_driver sa1110_driver = { ...@@ -309,6 +309,7 @@ static struct cpufreq_driver sa1110_driver = {
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.setpolicy = sa1110_setspeed, .setpolicy = sa1110_setspeed,
.policy = &sa1110_policy, .policy = &sa1110_policy,
.name = "sa1110",
}; };
static int __init sa1110_clk_init(void) static int __init sa1110_clk_init(void)
......
...@@ -260,6 +260,9 @@ static int __init elanfreq_init(void) ...@@ -260,6 +260,9 @@ 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);
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
ret = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &elanfreq_table[0]); ret = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &elanfreq_table[0]);
......
...@@ -771,6 +771,9 @@ static int __init longhaul_init (void) ...@@ -771,6 +771,9 @@ 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);
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
driver->policy[0].min = (unsigned int) lowest_speed; driver->policy[0].min = (unsigned int) lowest_speed;
......
...@@ -251,6 +251,9 @@ static int __init longrun_init(void) ...@@ -251,6 +251,9 @@ 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);
longrun_get_policy(&driver->policy[0]); longrun_get_policy(&driver->policy[0]);
......
...@@ -240,6 +240,9 @@ static int __init cpufreq_p4_init(void) ...@@ -240,6 +240,9 @@ 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);
for (i=0;i<NR_CPUS;i++) { for (i=0;i<NR_CPUS;i++) {
driver->policy[i].cpu = i; driver->policy[i].cpu = i;
......
...@@ -184,6 +184,9 @@ static int __init powernow_k6_init(void) ...@@ -184,6 +184,9 @@ 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);
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
driver->policy[0].cpu = 0; driver->policy[0].cpu = 0;
......
...@@ -690,6 +690,9 @@ static int __init speedstep_init(void) ...@@ -690,6 +690,9 @@ 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);
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
......
...@@ -1823,6 +1823,9 @@ acpi_cpufreq_init ( ...@@ -1823,6 +1823,9 @@ acpi_cpufreq_init (
driver->verify = &acpi_cpufreq_verify; driver->verify = &acpi_cpufreq_verify;
driver->setpolicy = &acpi_cpufreq_setpolicy; driver->setpolicy = &acpi_cpufreq_setpolicy;
driver->init = NULL;
driver->exit = NULL;
strncpy(driver->name, "acpi-processor", CPUFREQ_NAME_LEN);
for (i=0;i<NR_CPUS;i++) { for (i=0;i<NR_CPUS;i++) {
driver->policy[i].cpu = pr->id; driver->policy[i].cpu = pr->id;
......
...@@ -109,19 +109,29 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu ...@@ -109,19 +109,29 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu
* CPUFREQ DRIVER INTERFACE * * CPUFREQ DRIVER INTERFACE *
*********************************************************************/ *********************************************************************/
#define CPUFREQ_NAME_LEN 16
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); int (*setpolicy) (struct cpufreq_policy *policy);
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
char name[CPUFREQ_NAME_LEN];
/* optional, for the moment */
int (*init) (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
}; };
int cpufreq_register(struct cpufreq_driver *driver_data); int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister(void); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
/* deprecated */
#define cpufreq_register(x) cpufreq_register_driver(x)
#define cpufreq_unregister(x) cpufreq_unregister_driver(NULL)
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state); void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
......
...@@ -57,18 +57,6 @@ static struct notifier_block *cpufreq_transition_notifier_list; ...@@ -57,18 +57,6 @@ static struct notifier_block *cpufreq_transition_notifier_list;
static DECLARE_MUTEX (cpufreq_notifier_sem); static DECLARE_MUTEX (cpufreq_notifier_sem);
/**
* The cpufreq default policy. Can be set by a "cpufreq=..." command
* line option.
*/
static struct cpufreq_policy default_policy = {
.cpu = CPUFREQ_ALL_CPUS,
.min = 0,
.max = 0,
.policy = 0,
};
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
/** /**
* A few values needed by the 2.4.-compatible API * A few values needed by the 2.4.-compatible API
...@@ -234,6 +222,25 @@ store_scaling_governor (struct device *dev, const char *buf, size_t count) ...@@ -234,6 +222,25 @@ store_scaling_governor (struct device *dev, const char *buf, size_t count)
} }
/**
* show_scaling_governor - show the current policy for the specified CPU
*/
static ssize_t show_scaling_driver (struct device *dev, char *buf)
{
char value[CPUFREQ_NAME_LEN];
if (!dev)
return 0;
down(&cpufreq_driver_sem);
if (cpufreq_driver)
strncpy(value, cpufreq_driver->name, CPUFREQ_NAME_LEN);
up(&cpufreq_driver_sem);
return sprintf(buf, "%s\n", value);
}
/** /**
* cpufreq_per_cpu_attr_ro - read-only cpufreq per-CPU file * cpufreq_per_cpu_attr_ro - read-only cpufreq per-CPU file
*/ */
...@@ -258,6 +265,7 @@ cpufreq_per_cpu_attr_rw(scaling_min_freq, min); ...@@ -258,6 +265,7 @@ cpufreq_per_cpu_attr_rw(scaling_min_freq, min);
cpufreq_per_cpu_attr_rw(scaling_max_freq, max); 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);
/** /**
...@@ -269,6 +277,7 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -269,6 +277,7 @@ static int cpufreq_add_dev (struct device * dev)
{ {
unsigned int cpu = to_cpu_nr(dev); unsigned int cpu = to_cpu_nr(dev);
int ret = 0; int ret = 0;
struct cpufreq_policy policy;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
if (!cpufreq_driver) { if (!cpufreq_driver) {
...@@ -276,6 +285,37 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -276,6 +285,37 @@ static int cpufreq_add_dev (struct device * dev)
return -EINVAL; return -EINVAL;
} }
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
cpufreq_driver->policy[cpu].cpu = cpu;
if (cpufreq_driver->init) {
ret = cpufreq_driver->init(&cpufreq_driver->policy[cpu]);
if (ret) {
up(&cpufreq_driver_sem);
return -ENODEV;
}
}
/* set default policy on this CPU */
policy.policy = cpufreq_driver->policy[cpu].policy;
policy.min = cpufreq_driver->policy[cpu].min;
policy.max = cpufreq_driver->policy[cpu].max;
policy.cpu = cpu;
up(&cpufreq_driver_sem);
ret = cpufreq_set_policy(&policy);
if (ret)
return -EINVAL;
down(&cpufreq_driver_sem);
/* 2.4-API init for this CPU */
#ifdef CONFIG_CPU_FREQ_24_API
cpu_min_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.min_freq;
cpu_max_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.max_freq;
cpu_cur_freq[cpu] = cpufreq_driver->cpu_cur_freq[cpu];
#endif
/* prepare interface data */ /* prepare interface data */
cpufreq_driver->policy[cpu].intf.dev = dev; cpufreq_driver->policy[cpu].intf.dev = dev;
cpufreq_driver->policy[cpu].intf.intf = &cpufreq_interface; cpufreq_driver->policy[cpu].intf.intf = &cpufreq_interface;
...@@ -297,6 +337,7 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -297,6 +337,7 @@ static int cpufreq_add_dev (struct device * dev)
device_create_file (dev, &dev_attr_scaling_min_freq); device_create_file (dev, &dev_attr_scaling_min_freq);
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);
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return ret; return ret;
...@@ -312,12 +353,17 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -312,12 +353,17 @@ static int cpufreq_add_dev (struct device * dev)
static int cpufreq_remove_dev (struct intf_data *intf) 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);
if (cpufreq_driver->exit)
cpufreq_driver->exit(&cpufreq_driver->policy[cpu]);
device_remove_file (dev, &dev_attr_cpuinfo_min_freq); device_remove_file (dev, &dev_attr_cpuinfo_min_freq);
device_remove_file (dev, &dev_attr_cpuinfo_max_freq); device_remove_file (dev, &dev_attr_cpuinfo_max_freq);
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);
return 0; return 0;
} }
...@@ -402,20 +448,6 @@ static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *po ...@@ -402,20 +448,6 @@ static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *po
} }
/*
* cpufreq command line parameter. Must be hard values (kHz)
* cpufreq=1000000:2000000:PERFORMANCE
* to set the default CPUFreq policy.
*/
static int __init cpufreq_setup(char *str)
{
cpufreq_parse_policy(str, &default_policy);
default_policy.cpu = CPUFREQ_ALL_CPUS;
return 1;
}
__setup("cpufreq=", cpufreq_setup);
/** /**
* cpufreq_proc_read - read /proc/cpufreq * cpufreq_proc_read - read /proc/cpufreq
* *
...@@ -1203,19 +1235,18 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); ...@@ -1203,19 +1235,18 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
*********************************************************************/ *********************************************************************/
/** /**
* cpufreq_register - register a CPU Frequency driver * cpufreq_register_driver - register a CPU Frequency driver
* @driver_data: A struct cpufreq_driver containing the values submitted by the CPU Frequency driver. * @driver_data: A struct cpufreq_driver containing the values#
* submitted by the CPU Frequency driver.
* *
* Registers a CPU Frequency driver to this core code. This code * Registers a CPU Frequency driver to this core code. This code
* returns zero on success, -EBUSY when another driver got here first * returns zero on success, -EBUSY when another driver got here first
* (and isn't unregistered in the meantime). * (and isn't unregistered in the meantime).
* *
*/ */
int cpufreq_register(struct cpufreq_driver *driver_data) int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{ {
unsigned int ret; int ret = 0;
unsigned int i;
struct cpufreq_policy policy;
if (cpufreq_driver) if (cpufreq_driver)
return -EBUSY; return -EBUSY;
...@@ -1225,36 +1256,19 @@ int cpufreq_register(struct cpufreq_driver *driver_data) ...@@ -1225,36 +1256,19 @@ int cpufreq_register(struct cpufreq_driver *driver_data)
return -EINVAL; return -EINVAL;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
cpufreq_driver = driver_data;
/* check for a default policy - if it exists, use it on _all_ CPUs*/ cpufreq_driver = driver_data;
for (i=0; i<NR_CPUS; i++)
{
if (default_policy.policy)
cpufreq_driver->policy[i].policy = default_policy.policy;
if (default_policy.min)
cpufreq_driver->policy[i].min = default_policy.min;
if (default_policy.max)
cpufreq_driver->policy[i].max = default_policy.max;
}
/* set default policy on all CPUs. Must be called per-CPU and not if (!cpufreq_driver->policy) {
* with CPUFREQ_ALL_CPUs as there might be no common policy for all /* then we need per-CPU init */
* CPUs (UltraSPARC etc.) if (!cpufreq_driver->init) {
*/
for (i=0; i<NR_CPUS; i++)
{
policy.policy = cpufreq_driver->policy[i].policy;
policy.min = cpufreq_driver->policy[i].min;
policy.max = cpufreq_driver->policy[i].max;
policy.cpu = i;
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
ret = cpufreq_set_policy(&policy); return -EINVAL;
down(&cpufreq_driver_sem); }
if (ret) { cpufreq_driver->policy = kmalloc(NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
cpufreq_driver = NULL; if (!cpufreq_driver->policy) {
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return ret; return -ENOMEM;
} }
} }
...@@ -1263,15 +1277,6 @@ int cpufreq_register(struct cpufreq_driver *driver_data) ...@@ -1263,15 +1277,6 @@ int cpufreq_register(struct cpufreq_driver *driver_data)
cpufreq_proc_init(); cpufreq_proc_init();
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
down(&cpufreq_driver_sem);
for (i=0; i<NR_CPUS; i++)
{
cpu_min_freq[i] = driver_data->policy[i].cpuinfo.min_freq;
cpu_max_freq[i] = driver_data->policy[i].cpuinfo.max_freq;
cpu_cur_freq[i] = driver_data->cpu_cur_freq[i];
}
up(&cpufreq_driver_sem);
cpufreq_sysctl_init(); cpufreq_sysctl_init();
#endif #endif
...@@ -1279,40 +1284,53 @@ int cpufreq_register(struct cpufreq_driver *driver_data) ...@@ -1279,40 +1284,53 @@ int cpufreq_register(struct cpufreq_driver *driver_data)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(cpufreq_register); EXPORT_SYMBOL_GPL(cpufreq_register_driver);
/** /**
* cpufreq_unregister - unregister the current CPUFreq driver * cpufreq_unregister_driver - unregister the current CPUFreq driver
* *
* Unregister the current CPUFreq driver. Only call this if you have * Unregister the current CPUFreq driver. Only call this if you have
* the right to do so, i.e. if you have succeeded in initialising before! * the right to do so, i.e. if you have succeeded in initialising before!
* Returns zero if successful, and -EINVAL if the cpufreq_driver is * Returns zero if successful, and -EINVAL if the cpufreq_driver is
* currently not initialised. * currently not initialised.
*/ */
int cpufreq_unregister(void) int cpufreq_unregister_driver(struct cpufreq_driver *driver)
{ {
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
if (!cpufreq_driver) { if (!cpufreq_driver ||
((driver != cpufreq_driver) && (driver != NULL))) { /* compat */
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
return -EINVAL; return -EINVAL;
} }
interface_unregister(&cpufreq_interface);
cpufreq_driver = NULL;
up(&cpufreq_driver_sem);
cpufreq_proc_exit(); cpufreq_proc_exit();
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
cpufreq_sysctl_exit(); cpufreq_sysctl_exit();
#endif #endif
/* remove this workaround as soon as interface_add_data works */
{
unsigned int i;
for (i=0; i<NR_CPUS; i++) {
if (cpu_online(i))
cpufreq_remove_dev(&cpufreq_driver->policy[i].intf);
}
}
interface_unregister(&cpufreq_interface);
if (driver)
kfree(cpufreq_driver->policy);
cpufreq_driver = NULL;
up(&cpufreq_driver_sem);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cpufreq_unregister); EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
#ifdef CONFIG_PM #ifdef 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