diff options
| author | Dominik Brodowski <linux@brodo.de> | 2003-02-28 16:54:06 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-02-28 16:54:06 -0800 |
| commit | 3537d16121f55c115b59d4ecb312463eb92acef3 (patch) | |
| tree | a89f067ceb3e949e715d7e7770d562988c46abd1 | |
| parent | 5787e471fbd9dec35c927e2c360c336a0293440d (diff) | |
[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.
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/Kconfig | 12 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi.c | 285 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/cpufreq/longhaul.c | 291 | ||||
| -rw-r--r-- | kernel/cpufreq.c | 14 |
4 files changed, 272 insertions, 330 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig index bf61dd5a9c56..aa0f51b69d10 100644 --- a/arch/i386/kernel/cpu/cpufreq/Kconfig +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig @@ -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 diff --git a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c index 1d84b053fc0e..b5fef75c62f8 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c @@ -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 @@ end: 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 @@ end: 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); diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 79fa2499719b..9b87bf9bd582 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -1,5 +1,5 @@ /* - * $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 @@ bad_voltage: } -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); + minmult, maxmult); dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n", - lowest_speed, highest_speed); + 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 new_fsb = 0; - unsigned int new_clock_ratio = 0; - unsigned int min_mult = 0; - unsigned int max_mult = 0; + unsigned int table_index = 0; + unsigned int new_fsb = 0; + unsigned int new_clock_ratio = 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."); diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c index 17d2845accfd..de4b015ec9aa 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -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; |
