Commit 3537d161 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Linus Torvalds

[PATCH] cpufreq (2/5): x86 driver updates #2 (acpi, longhaul)

- update the VIA Longhaul driver to use frequency table helpers and
  the advanced cpufreq driver registration interface.
- cleanup of the ACPI P-States cpufreq driver
- very small update of the core -- set 24API values ahead of the setpolicy
  call.
parent 5787e471
......@@ -56,6 +56,16 @@ config X86_ACPI_CPUFREQ
If in doubt, say N.
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on X86_ACPI_CPUFREQ && PROC_FS
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
cross-architecture cpufreq interfaces should be used.
If in doubt, say N.
config ELAN_CPUFREQ
tristate "AMD Elan"
depends on CPU_FREQ_TABLE && MELAN
......@@ -139,7 +149,7 @@ config X86_LONGRUN
config X86_LONGHAUL
tristate "VIA Cyrix III Longhaul"
depends on CPU_FREQ
depends on CPU_FREQ_TABLE
help
This adds the CPUFreq driver for VIA Samuel/CyrixIII,
VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T
......
......@@ -50,23 +50,13 @@ MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
MODULE_LICENSE("GPL");
/* Performance Management */
static struct acpi_processor_performance *performance;
static struct cpufreq_driver acpi_cpufreq_driver;
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_processor_perf_fops = {
.open = acpi_processor_perf_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int
acpi_processor_get_performance_control (
struct acpi_processor *pr)
struct acpi_processor_performance *perf)
{
int result = 0;
acpi_status status = 0;
......@@ -77,7 +67,7 @@ acpi_processor_get_performance_control (
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control");
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
status = acpi_evaluate_object(perf->pr->handle, "_PCT", NULL, &buffer);
if(ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
return_VALUE(-ENODEV);
......@@ -116,7 +106,7 @@ acpi_processor_get_performance_control (
goto end;
}
pr->performance->control_register = (u16) reg->address;
perf->control_register = (u16) reg->address;
/*
* status_register
......@@ -143,12 +133,12 @@ acpi_processor_get_performance_control (
goto end;
}
pr->performance->status_register = (u16) reg->address;
perf->status_register = (u16) reg->address;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"control_register[0x%04x] status_register[0x%04x]\n",
pr->performance->control_register,
pr->performance->status_register));
perf->control_register,
perf->status_register));
end:
acpi_os_free(buffer.pointer);
......@@ -159,7 +149,7 @@ acpi_processor_get_performance_control (
static int
acpi_processor_get_performance_states (
struct acpi_processor* pr)
struct acpi_processor_performance * perf)
{
int result = 0;
acpi_status status = AE_OK;
......@@ -171,7 +161,7 @@ acpi_processor_get_performance_states (
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states");
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
status = acpi_evaluate_object(perf->pr->handle, "_PSS", NULL, &buffer);
if(ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
return_VALUE(-ENODEV);
......@@ -188,20 +178,20 @@ acpi_processor_get_performance_states (
pss->package.count));
if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) {
pr->performance->state_count = ACPI_PROCESSOR_MAX_PERFORMANCE;
perf->state_count = ACPI_PROCESSOR_MAX_PERFORMANCE;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Limiting number of states to max (%d)\n",
ACPI_PROCESSOR_MAX_PERFORMANCE));
}
else
pr->performance->state_count = pss->package.count;
perf->state_count = pss->package.count;
if (pr->performance->state_count > 1)
pr->flags.performance = 1;
if (perf->state_count > 1)
perf->pr->flags.performance = 1;
for (i = 0; i < pr->performance->state_count; i++) {
for (i = 0; i < perf->state_count; i++) {
struct acpi_processor_px *px = &(pr->performance->states[i]);
struct acpi_processor_px *px = &(perf->states[i]);
state.length = sizeof(struct acpi_processor_px);
state.pointer = px;
......@@ -236,7 +226,7 @@ acpi_processor_get_performance_states (
static int
acpi_processor_set_performance (
struct acpi_processor *pr,
struct acpi_processor_performance *perf,
int state)
{
u16 port = 0;
......@@ -246,38 +236,38 @@ acpi_processor_set_performance (
ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
if (!pr)
if (!perf || !perf->pr)
return_VALUE(-EINVAL);
if (!pr->flags.performance)
if (!perf->pr->flags.performance)
return_VALUE(-ENODEV);
if (state >= pr->performance->state_count) {
if (state >= perf->state_count) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Invalid target state (P%d)\n", state));
return_VALUE(-ENODEV);
}
if (state < pr->performance_platform_limit) {
if (state < perf->pr->performance_platform_limit) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Platform limit (P%d) overrides target state (P%d)\n",
pr->performance->platform_limit, state));
perf->pr->performance_platform_limit, state));
return_VALUE(-ENODEV);
}
if (state == pr->performance->state) {
if (state == perf->state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Already at target state (P%d)\n", state));
return_VALUE(0);
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
pr->performance->state, state));
perf->state, state));
/* cpufreq frequency struct */
cpufreq_freqs.cpu = pr->id;
cpufreq_freqs.old = pr->performance->states[pr->performance->state].core_frequency;
cpufreq_freqs.new = pr->performance->states[state].core_frequency;
cpufreq_freqs.cpu = perf->pr->id;
cpufreq_freqs.old = perf->states[perf->state].core_frequency;
cpufreq_freqs.new = perf->states[state].core_frequency;
/* notify cpufreq */
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
......@@ -287,8 +277,8 @@ acpi_processor_set_performance (
* control_register.
*/
port = pr->performance->control_register;
value = (u16) pr->performance->states[state].control;
port = perf->control_register;
value = (u16) perf->states[state].control;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Writing 0x%02x to port 0x%04x\n", value, port));
......@@ -302,15 +292,15 @@ acpi_processor_set_performance (
* giving up.
*/
port = pr->performance->status_register;
port = perf->status_register;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Looking for 0x%02x from port 0x%04x\n",
(u8) pr->performance->states[state].status, port));
(u8) perf->states[state].status, port));
for (i=0; i<100; i++) {
value = inb(port);
if (value == (u8) pr->performance->states[state].status)
if (value == (u8) perf->states[state].status)
break;
udelay(10);
}
......@@ -318,7 +308,7 @@ acpi_processor_set_performance (
/* notify cpufreq */
cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
if (value != pr->performance->states[state].status) {
if (value != perf->states[state].status) {
unsigned int tmp = cpufreq_freqs.new;
cpufreq_freqs.new = cpufreq_freqs.old;
cpufreq_freqs.old = tmp;
......@@ -332,11 +322,23 @@ acpi_processor_set_performance (
"Transition successful after %d microseconds\n",
i * 10));
pr->performance->state = state;
perf->state = state;
return_VALUE(0);
}
#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
/* /proc/acpi/processor/../performance interface (DEPRECATED) */
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_processor_perf_fops = {
.open = acpi_processor_perf_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
......@@ -347,7 +349,7 @@ static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
if (!pr)
goto end;
if (!pr->flags.performance) {
if (!pr->flags.performance || !pr->performance) {
seq_puts(seq, "<not supported>\n");
goto end;
}
......@@ -379,8 +381,8 @@ static int
acpi_processor_write_performance (
struct file *file,
const char *buffer,
unsigned long count,
void *data)
size_t count,
loff_t *data)
{
int result = 0;
struct acpi_processor *pr = (struct acpi_processor *) data;
......@@ -411,24 +413,78 @@ acpi_processor_write_performance (
return_VALUE(count);
}
static void
acpi_cpufreq_add_file (
struct acpi_processor *pr)
{
struct proc_dir_entry *entry = NULL;
struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
if (acpi_bus_get_device(pr->handle, &device))
return_VOID;
/* add file 'performance' [R/W] */
entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
if (!entry)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_PROCESSOR_FILE_PERFORMANCE));
else {
entry->proc_fops = &acpi_processor_perf_fops;
entry->proc_fops->write = acpi_processor_write_performance;
entry->data = acpi_driver_data(device);
}
return_VOID;
}
static void
acpi_cpufreq_remove_file (
struct acpi_processor *pr)
{
struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
if (acpi_bus_get_device(pr->handle, &device))
return_VOID;
/* remove file 'performance' */
remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
acpi_device_dir(device));
return_VOID;
}
#else
static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; }
static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; }
#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
static int
acpi_cpufreq_setpolicy (
struct cpufreq_policy *policy)
acpi_cpufreq_target (
struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct acpi_processor *pr = performance[policy->cpu].pr;
struct acpi_processor_performance *perf = &performance[policy->cpu];
unsigned int next_state = 0;
unsigned int result = 0;
ACPI_FUNCTION_TRACE("acpi_cpufreq_setpolicy");
result = cpufreq_frequency_table_setpolicy(policy,
&performance[policy->cpu].freq_table[pr->limit.state.px],
result = cpufreq_frequency_table_target(policy,
&perf->freq_table[perf->pr->limit.state.px],
target_freq,
relation,
&next_state);
if (result)
return_VALUE(result);
result = acpi_processor_set_performance (pr, next_state);
result = acpi_processor_set_performance (perf, next_state);
return_VALUE(result);
}
......@@ -439,18 +495,17 @@ acpi_cpufreq_verify (
struct cpufreq_policy *policy)
{
unsigned int result = 0;
unsigned int cpu = policy->cpu;
struct acpi_processor *pr = performance[policy->cpu].pr;
struct acpi_processor_performance *perf = &performance[policy->cpu];
ACPI_FUNCTION_TRACE("acpi_cpufreq_verify");
result = cpufreq_frequency_table_verify(policy,
&performance[cpu].freq_table[pr->limit.state.px]);
&perf->freq_table[perf->pr->limit.state.px]);
cpufreq_verify_within_limits(
policy,
performance[cpu].states[performance[cpu].state_count - 1].core_frequency * 1000,
performance[cpu].states[pr->limit.state.px].core_frequency * 1000);
perf->states[perf->state_count - 1].core_frequency * 1000,
perf->states[perf->pr->limit.state.px].core_frequency * 1000);
return_VALUE(result);
}
......@@ -458,7 +513,7 @@ acpi_cpufreq_verify (
static int
acpi_processor_get_performance_info (
struct acpi_processor *pr)
struct acpi_processor_performance *perf)
{
int result = 0;
acpi_status status = AE_OK;
......@@ -466,31 +521,32 @@ acpi_processor_get_performance_info (
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info");
if (!pr)
if (!perf || !perf->pr || !perf->pr->handle)
return_VALUE(-EINVAL);
status = acpi_get_handle(pr->handle, "_PCT", &handle);
status = acpi_get_handle(perf->pr->handle, "_PCT", &handle);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"ACPI-based processor performance control unavailable\n"));
return_VALUE(-ENODEV);
}
result = acpi_processor_get_performance_control(pr);
result = acpi_processor_get_performance_control(perf);
if (result)
return_VALUE(result);
result = acpi_processor_get_performance_states(pr);
result = acpi_processor_get_performance_states(perf);
if (result)
return_VALUE(result);
result = acpi_processor_get_platform_limit(pr);
result = acpi_processor_get_platform_limit(perf->pr);
if (result)
return_VALUE(result);
return_VALUE(0);
}
static int
acpi_cpufreq_cpu_init (
struct cpufreq_policy *policy)
......@@ -498,22 +554,18 @@ acpi_cpufreq_cpu_init (
unsigned int i;
unsigned int cpu = policy->cpu;
struct acpi_processor *pr = NULL;
struct acpi_processor_performance *perf = &performance[policy->cpu];
unsigned int result = 0;
struct proc_dir_entry *entry = NULL;
struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init");
acpi_processor_register_performance(&performance[cpu], &pr, cpu);
acpi_processor_register_performance(perf, &pr, cpu);
pr = performance[cpu].pr;
if (!pr)
return_VALUE(-ENODEV);
if (acpi_bus_get_device(pr->handle, &device))
return_VALUE(-ENODEV);
result = acpi_processor_get_performance_info(performance[cpu].pr);
result = acpi_processor_get_performance_info(perf);
if (result)
return_VALUE(-ENODEV);
......@@ -523,52 +575,64 @@ acpi_cpufreq_cpu_init (
/* detect transition latency */
policy->cpuinfo.transition_latency = 0;
for (i=0;i<performance[cpu].state_count;i++) {
if (performance[cpu].states[i].transition_latency > policy->cpuinfo.transition_latency)
policy->cpuinfo.transition_latency = performance[cpu].states[i].transition_latency;
for (i=0;i<perf->state_count;i++) {
if (perf->states[i].transition_latency > policy->cpuinfo.transition_latency)
policy->cpuinfo.transition_latency = perf->states[i].transition_latency;
}
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
#ifdef CONFIG_CPU_FREQ_24_API
acpi_cpufreq_driver.cpu_cur_freq[policy->cpu] = perf->states[pr->limit.state.px].core_frequency * 1000;
#endif
/* table init */
for (i=0; i<=performance[cpu].state_count; i++)
for (i=0; i<=perf->state_count; i++)
{
performance[cpu].freq_table[i].index = i;
if (i<performance[cpu].state_count)
performance[cpu].freq_table[i].frequency = performance[cpu].states[i].core_frequency * 1000;
perf->freq_table[i].index = i;
if (i<perf->state_count)
perf->freq_table[i].frequency = perf->states[i].core_frequency * 1000;
else
performance[cpu].freq_table[i].frequency = CPUFREQ_TABLE_END;
perf->freq_table[i].frequency = CPUFREQ_TABLE_END;
}
#ifdef CONFIG_CPU_FREQ_24_API
acpi_cpufreq_driver.cpu_cur_freq[policy->cpu] = performance[cpu].states[pr->limit.state.px].core_frequency * 1000;
#endif
result = cpufreq_frequency_table_cpuinfo(policy, &performance[cpu].freq_table[0]);
result = cpufreq_frequency_table_cpuinfo(policy, &perf->freq_table[0]);
/* add file 'performance' [R/W] */
entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
if (!entry)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to create '%s' fs entry\n",
ACPI_PROCESSOR_FILE_PERFORMANCE));
else {
entry->proc_fops = &acpi_processor_perf_fops;
entry->write_proc = acpi_processor_write_performance;
entry->data = acpi_driver_data(device);
}
acpi_cpufreq_add_file(pr);
return_VALUE(result);
}
static int
acpi_cpufreq_cpu_exit (
struct cpufreq_policy *policy)
{
struct acpi_processor *pr = performance[policy->cpu].pr;
ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_exit");
acpi_cpufreq_remove_file(pr);
return_VALUE(0);
}
static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = acpi_cpufreq_verify,
.target = acpi_cpufreq_target,
.init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit,
.name = "acpi-cpufreq",
};
static int __init
acpi_cpufreq_init (void)
{
int result = 0;
int current_state = 0;
int i = 0;
struct acpi_processor *pr;
struct acpi_processor *pr = NULL;
struct acpi_processor_performance *perf = NULL;
ACPI_FUNCTION_TRACE("acpi_cpufreq_init");
......@@ -579,10 +643,9 @@ acpi_cpufreq_init (void)
performance = kmalloc(NR_CPUS * sizeof(struct acpi_processor_performance), GFP_KERNEL);
if (!performance)
return_VALUE(-ENOMEM);
memset(performance, 0, NR_CPUS * sizeof(struct acpi_processor_performance));
/* register struct acpi_performance performance */
/* register struct acpi_processor_performance performance */
for (i=0; i<NR_CPUS; i++) {
if (cpu_online(i))
acpi_processor_register_performance(&performance[i], &pr, i);
......@@ -591,11 +654,13 @@ acpi_cpufreq_init (void)
/* initialize */
for (i=0; i<NR_CPUS; i++) {
if (cpu_online(i) && performance[i].pr)
result = acpi_processor_get_performance_info(performance[i].pr);
result = acpi_processor_get_performance_info(&performance[i]);
}
/* test it on one CPU */
for (i=0; i<NR_CPUS; i++) {
if (cpu_online(i))
continue;
pr = performance[i].pr;
if (pr && pr->flags.performance)
goto found_capable_cpu;
......@@ -604,10 +669,11 @@ acpi_cpufreq_init (void)
goto err;
found_capable_cpu:
current_state = pr->performance->state;
perf = pr->performance;
current_state = perf->state;
if (current_state == pr->limit.state.px) {
result = acpi_processor_set_performance(pr, (pr->performance->state_count - 1));
result = acpi_processor_set_performance(perf, (perf->state_count - 1));
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n"));
result = -ENODEV;
......@@ -615,7 +681,7 @@ acpi_cpufreq_init (void)
}
}
result = acpi_processor_set_performance(pr, pr->limit.state.px);
result = acpi_processor_set_performance(perf, pr->limit.state.px);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n"));
result = -ENODEV;
......@@ -623,7 +689,7 @@ acpi_cpufreq_init (void)
}
if (current_state != 0) {
result = acpi_processor_set_performance(pr, current_state);
result = acpi_processor_set_performance(perf, current_state);
if (result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n"));
result = -ENODEV;
......@@ -639,7 +705,7 @@ acpi_cpufreq_init (void)
/* error handling */
err:
/* unregister struct acpi_performance performance */
/* unregister struct acpi_processor_performance performance */
for (i=0; i<NR_CPUS; i++) {
if (performance[i].pr) {
performance[i].pr->flags.performance = 0;
......@@ -647,9 +713,7 @@ acpi_cpufreq_init (void)
performance[i].pr = NULL;
}
}
kfree(performance);
return_VALUE(result);
}
......@@ -668,7 +732,7 @@ acpi_cpufreq_exit (void)
cpufreq_unregister_driver(&acpi_cpufreq_driver);
/* unregister struct acpi_performance performance */
/* unregister struct acpi_processor_performance performance */
for (i=0; i<NR_CPUS; i++) {
if (performance[i].pr) {
performance[i].pr->flags.performance = 0;
......@@ -682,15 +746,6 @@ acpi_cpufreq_exit (void)
return_VOID;
}
static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = acpi_cpufreq_verify,
.setpolicy = acpi_cpufreq_setpolicy,
.init = acpi_cpufreq_cpu_init,
.exit = NULL,
.policy = NULL,
.name = "acpi-cpufreq",
};
late_initcall(acpi_cpufreq_init);
module_exit(acpi_cpufreq_exit);
/*
* $Id: longhaul.c,v 1.77 2002/10/31 21:17:40 db Exp $
* $Id: longhaul.c,v 1.86 2003/02/12 13:59:11 davej Exp $
*
* (C) 2001 Dave Jones. <davej@suse.de>
* (C) 2002 Padraig Brady. <padraig@antefacto.com>
......@@ -48,6 +48,7 @@ static int vrmrev;
/* Module parameters */
static int prefer_slow_fsb;
static int dont_scale_voltage;
static int dont_scale_fsb;
static int current_fsb;
......@@ -237,7 +238,6 @@ static unsigned int power_fsb_table[] = { 66, 100, 133, -1 };
/* fsb values to favour high fsb speed (for e.g. if lowering CPU
freq because of heat, but want to maintain highest performance possible) */
static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 };
static unsigned int *fsb_search_table;
/* Voltage scales. Div by 1000 to get actual voltage. */
static int __initdata vrm85scales[32] = {
......@@ -260,7 +260,7 @@ static int eblcr_table[32];
static int voltage_table[32];
static int highest_speed, lowest_speed; /* kHz */
static int longhaul; /* version. */
static struct cpufreq_driver *longhaul_driver;
static struct cpufreq_frequency_table *longhaul_table;
static int longhaul_get_cpu_fsb (void)
......@@ -428,7 +428,7 @@ static void longhaul_setstate (unsigned int clock_ratio_index, unsigned int newf
}
static void __init longhaul_get_ranges (void)
static int __init longhaul_get_ranges (void)
{
unsigned long lo, hi, invalue;
unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0;
......@@ -436,6 +436,9 @@ static void __init longhaul_get_ranges (void)
50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
unsigned int fsb_table[4] = { 133, 100, -1, 66 };
unsigned int fsbcount = 1;
unsigned int i, j, k = 0;
static unsigned int *fsb_search_table;
switch (longhaul) {
case 1:
......@@ -472,6 +475,11 @@ static void __init longhaul_get_ranges (void)
dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n",
minfsb, maxfsb);
fsbcount = 0;
for (i=0;i<4;i++) {
if((fsb_table[i] >= minfsb) && (fsb_table[i] <= maxfsb))
fsbcount++;
}
} else {
minfsb = maxfsb = current_fsb;
}
......@@ -480,11 +488,37 @@ static void __init longhaul_get_ranges (void)
highest_speed = maxmult * maxfsb * 100;
lowest_speed = minmult * minfsb * 100;
dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n",
minmult, maxmult);
dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n",
lowest_speed, highest_speed);
longhaul_table = kmalloc((numscales * fsbcount + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
if(!longhaul_table)
return -ENOMEM;
if (prefer_slow_fsb)
fsb_search_table = perf_fsb_table; // yep, this is right: the last entry is preferred by cpufreq_frequency_table_* ...
else
fsb_search_table = power_fsb_table;
for (i=0; (i<4); i++) {
if ((fsb_search_table[i] > maxfsb) || (fsb_search_table[i] < minfsb) || (fsb_search_table[i] == -1))
continue;
for (j=0; (j<numscales); j++) {
if ((clock_ratio[j] > maxmult) || (clock_ratio[j] < minmult) || (clock_ratio[j] == -1))
continue;
longhaul_table[k].frequency= clock_ratio[j] * fsb_search_table[i] * 100;
longhaul_table[k].index = (j << 8) | (i);
k++;
}
}
longhaul_table[k].frequency = CPUFREQ_TABLE_END;
if (!k)
return -EINVAL;
return 0;
}
......@@ -523,182 +557,43 @@ static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned lon
}
static inline unsigned int longhaul_statecount_fsb(struct cpufreq_policy *policy, unsigned int fsb) {
unsigned int i, count = 0;
for(i=0; i<numscales; i++) {
if ((clock_ratio[i] != -1) &&
((clock_ratio[i] * fsb * 100) <= policy->max) &&
((clock_ratio[i] * fsb * 100) >= policy->min))
count++;
}
return count;
}
static int longhaul_verify(struct cpufreq_policy *policy)
{
unsigned int number_states = 0;
unsigned int i;
unsigned int fsb_index = 0;
unsigned int tmpfreq = 0;
unsigned int newmax = -1;
if (!policy || !longhaul_driver)
return -EINVAL;
policy->cpu = 0;
cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);
if (can_scale_fsb==1) {
for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)
number_states += longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);
} else
number_states = longhaul_statecount_fsb(policy, current_fsb);
if (number_states)
return 0;
/* get frequency closest above current policy->max */
if (can_scale_fsb==1) {
for (fsb_index=0; fsb_search_table[fsb_index] != -1; fsb_index++)
for(i=0; i<numscales; i++) {
if (clock_ratio[i] == -1)
continue;
tmpfreq = clock_ratio[i] * fsb_search_table[fsb_index];
if ((tmpfreq > policy->max) &&
(tmpfreq < newmax))
newmax = tmpfreq;
}
} else {
for(i=0; i<numscales; i++) {
if (clock_ratio[i] == -1)
continue;
tmpfreq = clock_ratio[i] * current_fsb;
if ((tmpfreq > policy->max) &&
(tmpfreq < newmax))
newmax = tmpfreq;
}
}
policy->max = newmax;
cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);
return 0;
}
static int longhaul_get_best_freq_for_fsb(struct cpufreq_policy *policy,
unsigned int min_mult,
unsigned int max_mult,
unsigned int fsb,
unsigned int *new_mult)
{
unsigned int optimal = 0;
unsigned int found_optimal = 0;
unsigned int i;
switch(policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
optimal = max_mult;
break;
case CPUFREQ_POLICY_PERFORMANCE:
optimal = min_mult;
}
for(i=0; i<numscales; i++) {
unsigned int freq = fsb * clock_ratio[i] * 100;
if ((freq > policy->max) ||
(freq < policy->min))
continue;
switch(policy->policy) {
case CPUFREQ_POLICY_POWERSAVE:
if (clock_ratio[i] < clock_ratio[optimal]) {
found_optimal = 1;
optimal = i;
}
break;
case CPUFREQ_POLICY_PERFORMANCE:
if (clock_ratio[i] > clock_ratio[optimal]) {
found_optimal = 1;
optimal = i;
}
break;
}
}
if (found_optimal) {
*new_mult = optimal;
return 1;
}
return 0;
return cpufreq_frequency_table_verify(policy, longhaul_table);
}
static int longhaul_setpolicy (struct cpufreq_policy *policy)
static int longhaul_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int i;
unsigned int fsb_index = 0;
unsigned int table_index = 0;
unsigned int new_fsb = 0;
unsigned int new_clock_ratio = 0;
unsigned int min_mult = 0;
unsigned int max_mult = 0;
if (!longhaul_driver)
if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
return -EINVAL;
if (policy->policy==CPUFREQ_POLICY_PERFORMANCE)
fsb_search_table = perf_fsb_table;
else
fsb_search_table = power_fsb_table;
for(i=0;i<numscales;i++) {
if (clock_ratio[max_mult] < clock_ratio[i])
max_mult = i;
else if (clock_ratio[min_mult] > clock_ratio[i])
min_mult = i;
}
if (can_scale_fsb==1) {
unsigned int found = 0;
for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)
{
if (longhaul_get_best_freq_for_fsb(policy,
min_mult, max_mult,
fsb_search_table[fsb_index],
&new_clock_ratio)) {
new_fsb = fsb_search_table[fsb_index];
break;
}
}
if (!found)
return -EINVAL;
} else {
new_fsb = current_fsb;
if (!longhaul_get_best_freq_for_fsb(policy, min_mult,
max_mult, new_fsb, &new_clock_ratio))
return -EINVAL;
}
new_clock_ratio = longhaul_table[table_index].index & 0xFF;
new_fsb = power_fsb_table[(longhaul_table[table_index].index & 0xFF00) >> 8];
longhaul_setstate(new_clock_ratio, new_fsb);
return 0;
}
static int longhaul_cpu_init (struct cpufreq_policy *policy);
static int __init longhaul_init (void)
static struct cpufreq_driver longhaul_driver = {
.verify = longhaul_verify,
.target = longhaul_target,
.init = longhaul_cpu_init,
.name = "longhaul",
};
static int longhaul_cpu_init (struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned int currentspeed;
static int currentmult;
unsigned long lo, hi;
int ret;
struct cpufreq_driver *driver;
if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )
return -ENODEV;
......@@ -733,21 +628,12 @@ static int __init longhaul_init (void)
memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr));
break;
default:
printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n");
return -ENODEV;
}
printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul);
current_fsb = longhaul_get_cpu_fsb();
currentmult = longhaul_get_cpu_mult();
currentspeed = currentmult * current_fsb * 100;
dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n",
(currentspeed/1000), current_fsb, currentmult/10, currentmult%10);
if (longhaul==2 || longhaul==3) {
unsigned long lo, hi;
rdmsr (MSR_VIA_LONGHAUL, lo, hi);
if ((lo & (1<<0)) && (dont_scale_voltage==0))
longhaul_setup_voltagescaling (lo, hi);
......@@ -756,57 +642,48 @@ static int __init longhaul_init (void)
can_scale_fsb = 1;
}
longhaul_get_ranges();
driver = kmalloc(sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
if (!driver)
if (longhaul_get_ranges())
return -ENOMEM;
memset(driver, 0, sizeof(struct cpufreq_driver) +
NR_CPUS * sizeof(struct cpufreq_policy));
driver->policy = (struct cpufreq_policy *) (driver + 1);
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
#ifdef CONFIG_CPU_FREQ_24_API
driver->cpu_cur_freq[0] = currentspeed;
longhaul_driver.cpu_cur_freq[0] = (unsigned int) (longhaul_get_cpu_fsb() * longhaul_get_cpu_mult() * 100);
#endif
driver->verify = &longhaul_verify;
driver->setpolicy = &longhaul_setpolicy;
strncpy(driver->name, "longhaul", CPUFREQ_NAME_LEN);
return cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
}
driver->policy[0].cpu = 0;
driver->policy[0].min = (unsigned int) lowest_speed;
driver->policy[0].max = (unsigned int) highest_speed;
driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
driver->policy[0].cpuinfo.min_freq = (unsigned int) lowest_speed;
driver->policy[0].cpuinfo.max_freq = (unsigned int) highest_speed;
driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
static int __init longhaul_init (void)
{
struct cpuinfo_x86 *c = cpu_data;
longhaul_driver = driver;
if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )
return -ENODEV;
ret = cpufreq_register(driver);
if (ret) {
longhaul_driver = NULL;
kfree(driver);
switch (c->x86_model) {
case 6 ... 7:
return cpufreq_register_driver(&longhaul_driver);
case 8:
return -ENODEV;
default:
printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n");
}
return ret;
return -ENODEV;
}
static void __exit longhaul_exit (void)
{
if (longhaul_driver) {
cpufreq_unregister();
kfree(longhaul_driver);
}
cpufreq_unregister_driver(&longhaul_driver);
kfree(longhaul_table);
}
MODULE_PARM (dont_scale_fsb, "i");
MODULE_PARM (dont_scale_voltage, "i");
MODULE_PARM (current_fsb, "i");
MODULE_PARM (prefer_slow_fsb, "i");
MODULE_AUTHOR ("Dave Jones <davej@suse.de>");
MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
......
......@@ -350,6 +350,13 @@ static int cpufreq_add_dev (struct device * dev)
&cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
/* 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
if (cpufreq_driver->target)
cpufreq_governor(cpu, CPUFREQ_GOV_START);
......@@ -359,13 +366,6 @@ static int cpufreq_add_dev (struct device * dev)
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 */
cpufreq_driver->policy[cpu].intf.dev = dev;
cpufreq_driver->policy[cpu].intf.intf = &cpufreq_interface;
......
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