diff options
author | Dave Jones <davej@delerium.kernelslacker.org> | 2005-01-14 06:17:42 -0500 |
---|---|---|
committer | Dave Jones <davej@delerium.kernelslacker.org> | 2005-01-14 06:17:42 -0500 |
commit | ba420e2869fdcf4b917bb4d53a39ad67b84223e3 (patch) | |
tree | 9a3eed09bcf08f0eb3d63d8c39dd35672f6d016e /arch | |
parent | 812ab7f31be1ebce3afdd3209c08b596903a9bef (diff) | |
parent | c24a8e84587b96d45ae534546027087e8a62ba1e (diff) | |
download | history-ba420e2869fdcf4b917bb4d53a39ad67b84223e3.tar.gz |
Merge delerium.kernelslacker.org:/mnt/data/src/bk/bk-linus
into delerium.kernelslacker.org:/mnt/data/src/bk/cpufreq
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c | 34 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c | 11 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/gx-suspmod.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/p4-clockmod.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 19 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 29 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/powernow-k8.h | 9 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 152 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/cpufreq/speedstep-est-common.h | 25 |
9 files changed, 183 insertions, 100 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index 1e11401ef0fc4b..963e17aa205d60 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -38,6 +38,8 @@ #include <linux/acpi.h> #include <acpi/processor.h> +#include "speedstep-est-common.h" + #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); @@ -48,10 +50,12 @@ MODULE_LICENSE("GPL"); struct cpufreq_acpi_io { struct acpi_processor_performance acpi_data; struct cpufreq_frequency_table *freq_table; + unsigned int resume; }; static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; +static struct cpufreq_driver acpi_cpufreq_driver; static int acpi_processor_write_port( @@ -119,9 +123,14 @@ acpi_processor_set_performance ( } if (state == data->acpi_data.state) { - dprintk("Already at target state (P%d)\n", state); - retval = 0; - goto migrate_end; + if (unlikely(data->resume)) { + dprintk("Called after resume, resetting to P%d\n", state); + data->resume = 0; + } else { + dprintk("Already at target state (P%d)\n", state); + retval = 0; + goto migrate_end; + } } dprintk("Transitioning from P%d to P%d\n", @@ -368,6 +377,10 @@ acpi_cpufreq_cpu_init ( if (result) goto err_free; + if (is_const_loops_cpu(cpu)) { + acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; + } + /* capability check */ if (data->acpi_data.state_count <= 1) { dprintk("No P-States\n"); @@ -462,6 +475,20 @@ acpi_cpufreq_cpu_exit ( return (0); } +static int +acpi_cpufreq_resume ( + struct cpufreq_policy *policy) +{ + struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; + + + dprintk("acpi_cpufreq_resume\n"); + + data->resume = 1; + + return (0); +} + static struct freq_attr* acpi_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, @@ -473,6 +500,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = { .target = acpi_cpufreq_target, .init = acpi_cpufreq_cpu_init, .exit = acpi_cpufreq_cpu_exit, + .resume = acpi_cpufreq_resume, .name = "acpi-cpufreq", .owner = THIS_MODULE, .attr = acpi_cpufreq_attr, diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c index e654e7b674f0c0..04a40534520342 100644 --- a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c +++ b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c @@ -55,16 +55,7 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); MODULE_PARM_DESC(min_fsb, "Minimum FSB to use, if not defined: current FSB - 50"); -/* DEBUG - * Define it if you want verbose debug output, e.g. for bug reporting - */ -//#define NFORCE2_DEBUG - -#ifdef NFORCE2_DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg) /* * nforce2_calc_fsb - calculate FSB diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c index 3faa0ddb608cdd..1a49adb1f4a68c 100644 --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c @@ -209,7 +209,7 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu) if ((gx_params->pci_suscfg & SUSMOD) == 0) return stock_freq; - return (stock_freq * gx_params->on_duration) + return (stock_freq * gx_params->off_duration) / (gx_params->on_duration + gx_params->off_duration); } diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 18596a15b115a7..aa622d52c6e538 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -171,7 +171,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); } - if ((c->x86 == 0x06) && (c->x86_model == 0x13)) { + if ((c->x86 == 0x06) && (c->x86_model == 0x0D)) { /* Pentium M (Dothan) */ printk(KERN_WARNING PFX "Warning: Pentium M detected. " "The speedstep_centrino module offers voltage scaling" diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index f8822776061250..e8276905cc516f 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -635,6 +635,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) static int powernow_cpu_exit (struct cpufreq_policy *policy) { cpufreq_frequency_table_put_attr(policy->cpu); + +#ifdef CONFIG_X86_POWERNOW_K7_ACPI + if (acpi_processor_perf) { + acpi_processor_unregister_performance(acpi_processor_perf, 0); + kfree(acpi_processor_perf); + } +#endif + + if (powernow_table) + kfree(powernow_table); + return 0; } @@ -664,15 +675,7 @@ static int __init powernow_init (void) static void __exit powernow_exit (void) { -#ifdef CONFIG_X86_POWERNOW_K7_ACPI - if (acpi_processor_perf) { - acpi_processor_unregister_performance(acpi_processor_perf, 0); - kfree(acpi_processor_perf); - } -#endif cpufreq_unregister_driver(&powernow_driver); - if (powernow_table) - kfree(powernow_table); } module_param(acpi_force, int, 0444); diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 9b6ec758c7c3ab..a65ff7e32e5d09 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -18,6 +18,9 @@ * Processor information obtained from Chapter 9 (Power and Thermal Management) * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * Opteron Processors" available for download from www.amd.com + * + * Tables for specific CPUs can be infrerred from + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf */ #include <linux/kernel.h> @@ -65,7 +68,12 @@ static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid) return 1550-vid*25; } -/* Return the vco fid for an input fid */ +/* Return the vco fid for an input fid + * + * Each "low" fid has corresponding "high" fid, and you can get to "low" fids + * only from corresponding high fids. This returns "high" fid corresponding to + * "low" one. + */ static u32 convert_fid_to_vco_fid(u32 fid) { if (fid < HI_FID_TABLE_BOTTOM) { @@ -278,7 +286,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid return 1; } - while (rvosteps > 0) { + while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) { if (data->currvid == 0) { rvosteps = 0; } else { @@ -307,10 +315,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid /* Phase 2 - core frequency transition */ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) { - u32 vcoreqfid; - u32 vcocurrfid; - u32 vcofiddiff; - u32 savevid = data->currvid; + u32 vcoreqfid, vcocurrfid, vcofiddiff, savevid = data->currvid; if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n", @@ -498,7 +503,7 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 || (pst[j].fid & 1) || (j && (pst[j].fid < HI_FID_TABLE_BOTTOM))) { /* Only first fid is allowed to be in "low" range */ - printk(KERN_ERR PFX "fid %d invalid : 0x%x\n", j, pst[j].fid); + printk(KERN_ERR PFX "two low fids - %d : 0x%x\n", j, pst[j].fid); return -EINVAL; } if (pst[j].fid < lastfid) @@ -618,7 +623,7 @@ static int find_psb_table(struct powernow_k8_data *data) return -ENODEV; } - data->vstable = psb->voltagestabilizationtime; + data->vstable = psb->vstable; dprintk("voltage stabilization time: %d(*20us)\n", data->vstable); dprintk("flags2: 0x%x\n", psb->flags2); @@ -632,8 +637,8 @@ static int find_psb_table(struct powernow_k8_data *data) dprintk("isochronous relief time: %d\n", data->irt); dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs); - dprintk("numpst: 0x%x\n", psb->numpst); - cpst = psb->numpst; + dprintk("numpst: 0x%x\n", psb->num_tables); + cpst = psb->num_tables; if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){ thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) { @@ -651,7 +656,7 @@ static int find_psb_table(struct powernow_k8_data *data) dprintk("maxvid: 0x%x\n", psb->maxvid); maxvid = psb->maxvid; - data->numps = psb->numpstates; + data->numps = psb->numps; dprintk("numpstates: 0x%x\n", data->numps); return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); } @@ -1010,6 +1015,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) /* min/max the cpu is capable of */ if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) { printk(KERN_ERR PFX "invalid powernow_table\n"); + powernow_k8_cpu_exit_acpi(data); kfree(data->powernow_table); kfree(data); return -EINVAL; @@ -1027,6 +1033,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) err_out: set_cpus_allowed(current, oldmask); schedule(); + powernow_k8_cpu_exit_acpi(data); kfree(data); return -ENODEV; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h index 72fdcbf1f411fc..63ebc8470f5249 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h @@ -21,8 +21,7 @@ struct powernow_k8_data { u32 plllock; /* pll lock time, units 1 us */ /* keep track of the current fid / vid */ - u32 currvid; - u32 currfid; + u32 currvid, currfid; /* the powernow_table includes all frequency and vid/fid pairings: * fid are the lower 8 bits of the index, vid are the upper 8 bits. @@ -152,14 +151,14 @@ struct psb_s { u8 signature[10]; u8 tableversion; u8 flags1; - u16 voltagestabilizationtime; + u16 vstable; u8 flags2; - u8 numpst; + u8 num_tables; u32 cpuid; u8 plllocktime; u8 maxfid; u8 maxvid; - u8 numpstates; + u8 numps; }; /* Pairs of fid/vid values are appended to the version 1.4 PSB table. */ diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 497bf9446564fb..07d5612dc00f4f 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -22,6 +22,8 @@ #include <linux/init.h> #include <linux/cpufreq.h> #include <linux/config.h> +#include <linux/delay.h> +#include <linux/compiler.h> #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI #include <linux/acpi.h> @@ -32,6 +34,8 @@ #include <asm/processor.h> #include <asm/cpufeature.h> +#include "speedstep-est-common.h" + #define PFX "speedstep-centrino: " #define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>" @@ -71,8 +75,10 @@ struct cpu_model static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x); /* Operating points for current CPU */ -static struct cpu_model *centrino_model; -static const struct cpu_id *centrino_cpu; +static struct cpu_model *centrino_model[NR_CPUS]; +static const struct cpu_id *centrino_cpu[NR_CPUS]; + +static struct cpufreq_driver centrino_driver; #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE @@ -239,7 +245,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->cpu_id == NULL) { /* No match at all */ - printk(KERN_INFO PFX "no support for CPU model \"%s\": " + dprintk(KERN_INFO PFX "no support for CPU model \"%s\": " "send /proc/cpuinfo to " MAINTAINER "\n", cpu->x86_model_id); return -ENOENT; @@ -247,15 +253,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) if (model->op_points == NULL) { /* Matched a non-match */ - printk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", + dprintk(KERN_INFO PFX "no table support for CPU model \"%s\": \n", cpu->x86_model_id); #ifndef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI - printk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); + dprintk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n"); #endif return -ENOENT; } - centrino_model = model; + centrino_model[policy->cpu] = model; dprintk("found \"%s\": max frequency: %dkHz\n", model->model_name, model->max_freq); @@ -277,7 +283,7 @@ static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_ } /* To be called only after centrino_model is initialized */ -static unsigned extract_clock(unsigned msr) +static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe) { int i; @@ -286,28 +292,32 @@ static unsigned extract_clock(unsigned msr) * for centrino, as some DSDTs are buggy. * Ideally, this can be done using the acpi_data structure. */ - if ((centrino_cpu == &cpu_ids[CPU_BANIAS]) || - (centrino_cpu == &cpu_ids[CPU_DOTHAN_A1]) || - (centrino_cpu == &cpu_ids[CPU_DOTHAN_B0])) { + if ((centrino_cpu[cpu] == &cpu_ids[CPU_BANIAS]) || + (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_A1]) || + (centrino_cpu[cpu] == &cpu_ids[CPU_DOTHAN_B0])) { msr = (msr >> 8) & 0xff; return msr * 100000; } - if ((!centrino_model) || (!centrino_model->op_points)) + if ((!centrino_model[cpu]) || (!centrino_model[cpu]->op_points)) return 0; msr &= 0xffff; - for (i=0;centrino_model->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { - if (msr == centrino_model->op_points[i].index) - return centrino_model->op_points[i].frequency; + for (i=0;centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++) { + if (msr == centrino_model[cpu]->op_points[i].index) + return centrino_model[cpu]->op_points[i].frequency; } - return 0; + if (failsafe) + return centrino_model[cpu]->op_points[i-1].frequency; + else + return 0; } /* Return the current CPU frequency in kHz */ static unsigned int get_cur_freq(unsigned int cpu) { unsigned l, h; + unsigned clock_freq; cpumask_t saved_mask; saved_mask = current->cpus_allowed; @@ -316,8 +326,21 @@ static unsigned int get_cur_freq(unsigned int cpu) return 0; rdmsr(MSR_IA32_PERF_STATUS, l, h); + clock_freq = extract_clock(l, cpu, 0); + + if (unlikely(clock_freq == 0)) { + /* + * On some CPUs, we can see transient MSR values (which are + * not present in _PSS), while CPU is doing some automatic + * P-state transition (like TM2). Get the last freq set + * in PERF_CTL. + */ + rdmsr(MSR_IA32_PERF_CTL, l, h); + clock_freq = extract_clock(l, cpu, 1); + } + set_cpus_allowed(current, saved_mask); - return extract_clock(l); + return clock_freq; } @@ -339,6 +362,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) struct acpi_object_list arg_list = {1, &arg0}; unsigned long cur_freq; int result = 0, i; + unsigned int cpu = policy->cpu; /* _PDC settings */ arg0.buffer.length = 12; @@ -350,8 +374,8 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) p.pdc = &arg_list; /* register with ACPI core */ - if (acpi_processor_register_performance(&p, policy->cpu)) { - printk(KERN_INFO PFX "obtaining ACPI data failed\n"); + if (acpi_processor_register_performance(&p, cpu)) { + dprintk(KERN_INFO PFX "obtaining ACPI data failed\n"); return -EIO; } @@ -392,49 +416,49 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) } } - centrino_model = kmalloc(sizeof(struct cpu_model), GFP_KERNEL); - if (!centrino_model) { + centrino_model[cpu] = kmalloc(sizeof(struct cpu_model), GFP_KERNEL); + if (!centrino_model[cpu]) { result = -ENOMEM; goto err_unreg; } - memset(centrino_model, 0, sizeof(struct cpu_model)); + memset(centrino_model[cpu], 0, sizeof(struct cpu_model)); - centrino_model->model_name=NULL; - centrino_model->max_freq = p.states[0].core_frequency * 1000; - centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * + centrino_model[cpu]->model_name=NULL; + centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000; + centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) * (p.state_count + 1), GFP_KERNEL); - if (!centrino_model->op_points) { + if (!centrino_model[cpu]->op_points) { result = -ENOMEM; goto err_kfree; } for (i=0; i<p.state_count; i++) { - centrino_model->op_points[i].index = p.states[i].control; - centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000; + centrino_model[cpu]->op_points[i].index = p.states[i].control; + centrino_model[cpu]->op_points[i].frequency = p.states[i].core_frequency * 1000; dprintk("adding state %i with frequency %u and control value %04x\n", - i, centrino_model->op_points[i].frequency, centrino_model->op_points[i].index); + i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index); } - centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; + centrino_model[cpu]->op_points[p.state_count].frequency = CPUFREQ_TABLE_END; - cur_freq = get_cur_freq(policy->cpu); + cur_freq = get_cur_freq(cpu); for (i=0; i<p.state_count; i++) { if (!p.states[i].core_frequency) { dprintk("skipping state %u\n", i); - centrino_model->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; + centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID; continue; } - if (extract_clock(centrino_model->op_points[i].index) != - (centrino_model->op_points[i].frequency)) { + if (extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0) != + (centrino_model[cpu]->op_points[i].frequency)) { dprintk("Invalid encoded frequency (%u vs. %u)\n", - extract_clock(centrino_model->op_points[i].index), - centrino_model->op_points[i].frequency); + extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0), + centrino_model[cpu]->op_points[i].frequency); result = -EINVAL; goto err_kfree_all; } - if (cur_freq == centrino_model->op_points[i].frequency) + if (cur_freq == centrino_model[cpu]->op_points[i].frequency) p.state = i; } @@ -444,12 +468,12 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) return 0; err_kfree_all: - kfree(centrino_model->op_points); + kfree(centrino_model[cpu]->op_points); err_kfree: - kfree(centrino_model); + kfree(centrino_model[cpu]); err_unreg: - acpi_processor_unregister_performance(&p, policy->cpu); - printk(KERN_INFO PFX "invalid ACPI data\n"); + acpi_processor_unregister_performance(&p, cpu); + dprintk(KERN_INFO PFX "invalid ACPI data\n"); return (result); } #else @@ -473,14 +497,18 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) break; if (i != N_IDS) - centrino_cpu = &cpu_ids[i]; + centrino_cpu[policy->cpu] = &cpu_ids[i]; + + if (is_const_loops_cpu(policy->cpu)) { + centrino_driver.flags |= CPUFREQ_CONST_LOOPS; + } if (centrino_cpu_init_acpi(policy)) { if (policy->cpu != 0) return -ENODEV; - if (!centrino_cpu) { - printk(KERN_INFO PFX "found unsupported CPU with " + if (!centrino_cpu[policy->cpu]) { + dprintk(KERN_INFO PFX "found unsupported CPU with " "Enhanced SpeedStep: send /proc/cpuinfo to " MAINTAINER "\n"); return -ENODEV; @@ -516,32 +544,34 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur); - ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); + ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model[policy->cpu]->op_points); if (ret) return (ret); - cpufreq_frequency_table_get_attr(centrino_model->op_points, policy->cpu); + cpufreq_frequency_table_get_attr(centrino_model[policy->cpu]->op_points, policy->cpu); return 0; } static int centrino_cpu_exit(struct cpufreq_policy *policy) { - if (!centrino_model) + unsigned int cpu = policy->cpu; + + if (!centrino_model[cpu]) return -ENODEV; - cpufreq_frequency_table_put_attr(policy->cpu); + cpufreq_frequency_table_put_attr(cpu); #ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI - if (!centrino_model->model_name) { + if (!centrino_model[cpu]->model_name) { dprintk("unregistering and freeing ACPI data\n"); - acpi_processor_unregister_performance(&p, policy->cpu); - kfree(centrino_model->op_points); - kfree(centrino_model); + acpi_processor_unregister_performance(&p, cpu); + kfree(centrino_model[cpu]->op_points); + kfree(centrino_model[cpu]); } #endif - centrino_model = NULL; + centrino_model[cpu] = NULL; return 0; } @@ -555,7 +585,7 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) */ static int centrino_verify (struct cpufreq_policy *policy) { - return cpufreq_frequency_table_verify(policy, centrino_model->op_points); + return cpufreq_frequency_table_verify(policy, centrino_model[policy->cpu]->op_points); } /** @@ -571,12 +601,12 @@ static int centrino_target (struct cpufreq_policy *policy, unsigned int relation) { unsigned int newstate = 0; - unsigned int msr, oldmsr, h; + unsigned int msr, oldmsr, h, cpu = policy->cpu; struct cpufreq_freqs freqs; cpumask_t saved_mask; int retval; - if (centrino_model == NULL) + if (centrino_model[cpu] == NULL) return -ENODEV; /* @@ -585,18 +615,18 @@ static int centrino_target (struct cpufreq_policy *policy, */ saved_mask = current->cpus_allowed; set_cpus_allowed(current, policy->cpus); - if (smp_processor_id() != policy->cpu) { + if (!cpu_isset(smp_processor_id(), policy->cpus)) { dprintk("couldn't limit to CPUs in this domain\n"); return(-EAGAIN); } - if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq, + if (cpufreq_frequency_table_target(policy, centrino_model[cpu]->op_points, target_freq, relation, &newstate)) { retval = -EINVAL; goto migrate_end; } - msr = centrino_model->op_points[newstate].index; + msr = centrino_model[cpu]->op_points[newstate].index; rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); if (msr == (oldmsr & 0xffff)) { @@ -605,9 +635,9 @@ static int centrino_target (struct cpufreq_policy *policy, goto migrate_end; } - freqs.cpu = policy->cpu; - freqs.old = extract_clock(oldmsr); - freqs.new = extract_clock(msr); + freqs.cpu = cpu; + freqs.old = extract_clock(oldmsr, cpu, 0); + freqs.new = extract_clock(msr, cpu, 0); dprintk("target=%dkHz old=%d new=%d msr=%04x\n", target_freq, freqs.old, freqs.new, msr); diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-est-common.h b/arch/i386/kernel/cpu/cpufreq/speedstep-est-common.h new file mode 100644 index 00000000000000..5ce995c9d866c1 --- /dev/null +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-est-common.h @@ -0,0 +1,25 @@ +/* + * Routines common for drivers handling Enhanced Speedstep Technology + * Copyright (C) 2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + * + * Licensed under the terms of the GNU GPL License version 2 -- see + * COPYING for details. + */ + +static inline int is_const_loops_cpu(unsigned int cpu) +{ + struct cpuinfo_x86 *c = cpu_data + cpu; + + if (c->x86_vendor != X86_VENDOR_INTEL || !cpu_has(c, X86_FEATURE_EST)) + return 0; + + /* + * on P-4s, the TSC runs with constant frequency independent of cpu freq + * when we use EST + */ + if (c->x86 == 0xf) + return 1; + + return 0; +} + |