Commit 5787e471 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] cpufreq (1/5): x86 driver updates #1 (elanfreq, gx-suspmod, powernow-k6)

- switch the AMD Elan, AMD PowerNow-K6 and the Cyrix/MediaGX driver
  to use the advanced cpufreq_driver registration process
- cleanups
parent e4caae91
......@@ -31,15 +31,11 @@
#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */
#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */
static struct cpufreq_driver *elanfreq_driver;
static struct cpufreq_driver elanfreq_driver;
/* Module parameter */
static int max_freq;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
struct s_elan_multiplier {
int clock; /* frequency in kHz */
int val40h; /* PMU Force Mode register */
......@@ -127,11 +123,6 @@ static void elanfreq_set_cpu_state (unsigned int state) {
struct cpufreq_freqs freqs;
if (!elanfreq_driver) {
printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
return;
}
freqs.old = elanfreq_get_cpu_frequency();
freqs.new = elan_multiplier[state].clock;
freqs.cpu = 0; /* elanfreq.c is UP only driver */
......@@ -187,11 +178,13 @@ static int elanfreq_verify (struct cpufreq_policy *policy)
return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]);
}
static int elanfreq_setpolicy (struct cpufreq_policy *policy)
static int elanfreq_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int newstate = 0;
if (cpufreq_frequency_table_setpolicy(policy, &elanfreq_table[0], &newstate))
if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate))
return -EINVAL;
elanfreq_set_cpu_state(newstate);
......@@ -204,6 +197,37 @@ static int elanfreq_setpolicy (struct cpufreq_policy *policy)
* Module init and exit code
*/
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned int i;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
(c->x86 != 4) || (c->x86_model!=10))
return -ENODEV;
/* max freq */
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency();
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
/* cpuinfo and default policy values */
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
#ifdef CONFIG_CPU_FREQ_24_API
elanfreq_driver.cpu_cur_freq[policy->cpu] = elanfreq_get_cpu_frequency();
#endif
return cpufreq_frequency_table_cpuinfo(policy, &elanfreq_table[0]);;
}
#ifndef MODULE
/**
* elanfreq_setup - elanfreq command line parameter parsing
......@@ -224,11 +248,18 @@ static int __init elanfreq_setup(char *str)
__setup("elanfreq=", elanfreq_setup);
#endif
static struct cpufreq_driver elanfreq_driver = {
.verify = elanfreq_verify,
.target = elanfreq_target,
.init = elanfreq_cpu_init,
.name = "elanfreq",
};
static int __init elanfreq_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver;
int ret, i;
/* Test if we have the right hardware */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
......@@ -238,63 +269,22 @@ static int __init elanfreq_init(void)
return -ENODEV;
}
driver = kmalloc(sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver)
return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1);
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency();
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (elanfreq_table[i].frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency();
#endif
driver->verify = &elanfreq_verify;
driver->setpolicy = &elanfreq_setpolicy;
strncpy(driver->name, "elanfreq", CPUFREQ_NAME_LEN);
driver->policy[0].cpu = 0;
ret = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &elanfreq_table[0]);
if (ret) {
kfree(driver);
return ret;
}
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
elanfreq_driver = driver;
ret = cpufreq_register(driver);
if (ret) {
elanfreq_driver = NULL;
kfree(driver);
}
return ret;
return cpufreq_register_driver(&elanfreq_driver);
}
static void __exit elanfreq_exit(void)
{
if (elanfreq_driver) {
cpufreq_unregister();
kfree(elanfreq_driver);
}
cpufreq_unregister_driver(&elanfreq_driver);
}
module_init(elanfreq_init);
module_exit(elanfreq_exit);
MODULE_PARM (max_freq, "i");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
module_init(elanfreq_init);
module_exit(elanfreq_exit);
......@@ -106,6 +106,8 @@
#define PWRSVE_ISA (1<<3) /* stop ISA clock */
#define PWRSVE (1<<4) /* active idle */
static struct cpufreq_driver gx_suspmod_driver;
struct gxfreq_params {
u8 on_duration;
u8 off_duration;
......@@ -116,7 +118,6 @@ struct gxfreq_params {
struct pci_dev *cs55x0;
};
static struct cpufreq_driver *gx_driver;
static struct gxfreq_params *gx_params;
static int stock_freq;
......@@ -345,7 +346,7 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
unsigned int tmp_freq = 0;
u8 tmp1, tmp2;
if (!gx_driver || !stock_freq || !policy)
if (!stock_freq || !policy)
return -EINVAL;
policy->cpu = 0;
......@@ -375,33 +376,73 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
}
/*
* cpufreq_gx_setpolicy:
* cpufreq_gx_target:
*
*/
static int cpufreq_gx_setpolicy(struct cpufreq_policy *policy)
static int cpufreq_gx_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
u8 tmp1, tmp2;
unsigned int tmp_freq;
if (!gx_driver || !stock_freq || !policy)
if (!stock_freq || !policy)
return -EINVAL;
policy->cpu = 0;
if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
/* here we need to make sure that we don't set the
* frequency below policy->min (see comment in
* cpufreq_gx_verify() - guarantee of processing
* capacity.
*/
u8 tmp1, tmp2;
unsigned int tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2);
while (tmp_freq < policy->min) {
tmp_freq += stock_freq / max_duration;
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
}
gx_set_cpuspeed(tmp_freq);
tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2);
while (tmp_freq < policy->min) {
tmp_freq += stock_freq / max_duration;
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
}
while (tmp_freq > policy->max) {
tmp_freq -= stock_freq / max_duration;
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
}
gx_set_cpuspeed(tmp_freq);
return 0;
}
static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
{
int maxfreq, curfreq;
if (!policy || policy->cpu != 0)
return -ENODEV;
/* determine maximum frequency */
if (pci_busclk) {
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} else if (cpu_khz) {
maxfreq = cpu_khz;
} else {
gx_set_cpuspeed(policy->max);
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
}
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed();
dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq);
/* setup basic struct for cpufreq API */
policy->cpu = 0;
if (max_duration < POLICY_MIN_DIV)
policy->min = maxfreq / max_duration;
else
policy->min = maxfreq / POLICY_MIN_DIV;
policy->max = maxfreq;
#ifdef CONFIG_CPU_FREQ_24_API
gx_suspmod_driver.cpu_cur_freq[policy->cpu] = curfreq;
#endif
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.min_freq = maxfreq / max_duration;
policy->cpuinfo.max_freq = maxfreq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0;
}
......@@ -409,11 +450,16 @@ static int cpufreq_gx_setpolicy(struct cpufreq_policy *policy)
* cpufreq_gx_init:
* MediaGX/Geode GX initilize cpufreq driver
*/
static struct cpufreq_driver gx_suspmod_driver = {
.verify = cpufreq_gx_verify,
.target = cpufreq_gx_target,
.init = cpufreq_gx_cpu_init,
.name = "gx-suspmod",
};
static int __init cpufreq_gx_init(void)
{
int maxfreq,ret,curfreq;
struct cpufreq_driver *driver;
int ret;
struct gxfreq_params *params;
struct pci_dev *gx_pci;
u32 class_rev;
......@@ -428,21 +474,13 @@ static int __init cpufreq_gx_init(void)
dprintk("geode suspend modulation available.\n");
driver = kmalloc(sizeof(struct cpufreq_driver) + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (driver == NULL)
return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
if (params == NULL) {
kfree(driver);
if (params == NULL)
return -ENOMEM;
}
memset(params, 0, sizeof(struct gxfreq_params));
driver->policy = (struct cpufreq_policy *)(driver + 1);
params->cs55x0 = gx_pci;
gx_params = params;
/* keep cs55x0 configurations */
pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg));
......@@ -453,45 +491,7 @@ static int __init cpufreq_gx_init(void)
pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev);
params->pci_rev = class_rev && 0xff;
gx_params = params;
/* determine maximum frequency */
if (pci_busclk) {
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} else if (cpu_khz) {
maxfreq = cpu_khz;
} else {
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
}
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed();
dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq);
/* setup basic struct for cpufreq API */
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = curfreq;
#endif
driver->policy[0].cpu = 0;
if (max_duration < POLICY_MIN_DIV)
driver->policy[0].min = maxfreq / max_duration;
else
driver->policy[0].min = maxfreq / POLICY_MIN_DIV;
driver->policy[0].max = maxfreq;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.min_freq = maxfreq / max_duration;
driver->policy[0].cpuinfo.max_freq = maxfreq;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->verify = &cpufreq_gx_verify;
driver->setpolicy = &cpufreq_gx_setpolicy;
strncpy(driver->name, "gx-suspmod", CPUFREQ_NAME_LEN);
gx_driver = driver;
if ((ret = cpufreq_register(driver))) {
kfree(driver);
if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
kfree(params);
return ret; /* register error! */
}
......@@ -501,13 +501,8 @@ static int __init cpufreq_gx_init(void)
static void __exit cpufreq_gx_exit(void)
{
if (gx_driver) {
/* disable throttling */
gx_set_cpuspeed(stock_freq);
cpufreq_unregister();
kfree(gx_driver);
kfree(gx_params);
}
cpufreq_unregister_driver(&gx_suspmod_driver);
kfree(gx_params);
}
MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>");
......
/*
* $Id: powernow-k6.c,v 1.36 2002/10/31 21:17:40 db Exp $
* $Id: powernow-k6.c,v 1.46 2003/01/20 17:31:47 db Exp $
* This file was part of Powertweak Linux (http://powertweak.sf.net)
* and is shared with the Linux Kernel module.
*
* (C) 2000-2002 Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski.
* (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski.
*
* Licensed under the terms of the GNU GPL License version 2.
*
......@@ -25,7 +25,7 @@
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
as it is unused */
static struct cpufreq_driver *powernow_driver;
static struct cpufreq_driver powernow_k6_driver;
static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier;
......@@ -77,8 +77,8 @@ static void powernow_k6_set_state (unsigned int best_i)
unsigned long msrval;
struct cpufreq_freqs freqs;
if (!powernow_driver) {
printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
if (clock_ratio[best_i].index > max_multiplier) {
printk(KERN_ERR "cpufreq: invalid target frequency\n");
return;
}
......@@ -126,11 +126,13 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
*
* sets a new CPUFreq policy
*/
static int powernow_k6_setpolicy (struct cpufreq_policy *policy)
static int powernow_k6_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int newstate = 0;
if (cpufreq_frequency_table_setpolicy(policy, &clock_ratio[0], &newstate))
if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate))
return -EINVAL;
powernow_k6_set_state(newstate);
......@@ -139,43 +141,22 @@ static int powernow_k6_setpolicy (struct cpufreq_policy *policy)
}
/**
* powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
*
* Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
* devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
* on success.
*/
static int __init powernow_k6_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
struct cpufreq_driver *driver;
unsigned int result;
unsigned int i;
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned int i;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13)))
((c->x86_model != 12) && (c->x86_model != 13)))
return -ENODEV;
if (policy->cpu != 0)
return -ENODEV;
/* get frequencies */
max_multiplier = powernow_k6_get_cpu_multiplier();
busfreq = cpu_khz / max_multiplier;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk("cpufreq: PowerNow IOPORT region already used.\n");
return -EIO;
}
/* initialization of main "cpufreq" code*/
driver = kmalloc(sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver) {
release_region (POWERNOW_IOPORT, 16);
return -ENOMEM;
}
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1);
/* table init */
for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].index > max_multiplier)
......@@ -184,33 +165,63 @@ static int __init powernow_k6_init(void)
clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
}
driver->verify = &powernow_k6_verify;
driver->setpolicy = &powernow_k6_setpolicy;
strncpy(driver->name, "powernow-k6", CPUFREQ_NAME_LEN);
/* cpuinfo and default policy values */
driver->policy[0].cpu = 0;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = busfreq * max_multiplier;
powernow_k6_driver.cpu_cur_freq[policy->cpu] = busfreq * max_multiplier;
#endif
result = cpufreq_frequency_table_cpuinfo(&driver->policy[0], &clock_ratio[0]);
if (result) {
kfree(driver);
return result;
return cpufreq_frequency_table_cpuinfo(policy, &clock_ratio[0]);
}
static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int i;
for (i=0; i<8; i++) {
if (i==max_multiplier)
powernow_k6_set_state(i);
}
return 0;
}
static struct cpufreq_driver powernow_k6_driver = {
.verify = powernow_k6_verify,
.target = powernow_k6_target,
.init = powernow_k6_cpu_init,
.exit = powernow_k6_cpu_exit,
.name = "powernow-k6",
};
/**
* powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
*
* Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
* devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
* on success.
*/
static int __init powernow_k6_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
powernow_driver = driver;
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
((c->x86_model != 12) && (c->x86_model != 13)))
return -ENODEV;
result = cpufreq_register(driver);
if (result) {
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk("cpufreq: PowerNow IOPORT region already used.\n");
return -EIO;
}
if (cpufreq_register_driver(&powernow_k6_driver)) {
release_region (POWERNOW_IOPORT, 16);
powernow_driver = NULL;
kfree(driver);
return -EINVAL;
}
return result;
return 0;
}
......@@ -221,20 +232,14 @@ static int __init powernow_k6_init(void)
*/
static void __exit powernow_k6_exit(void)
{
unsigned int i;
if (powernow_driver) {
for (i=0;i<8;i++)
if (clock_ratio[i].index == max_multiplier)
powernow_k6_set_state(i);
cpufreq_unregister();
kfree(powernow_driver);
}
cpufreq_unregister_driver(&powernow_k6_driver);
release_region (POWERNOW_IOPORT, 16);
}
MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
MODULE_LICENSE ("GPL");
module_init(powernow_k6_init);
module_exit(powernow_k6_exit);
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