aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDave Jones <davej@delerium.kernelslacker.org>2005-01-14 06:17:42 -0500
committerDave Jones <davej@delerium.kernelslacker.org>2005-01-14 06:17:42 -0500
commitba420e2869fdcf4b917bb4d53a39ad67b84223e3 (patch)
tree9a3eed09bcf08f0eb3d63d8c39dd35672f6d016e /arch
parent812ab7f31be1ebce3afdd3209c08b596903a9bef (diff)
parentc24a8e84587b96d45ae534546027087e8a62ba1e (diff)
downloadhistory-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.c34
-rw-r--r--arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c11
-rw-r--r--arch/i386/kernel/cpu/cpufreq/gx-suspmod.c2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/p4-clockmod.c2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k7.c19
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.c29
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.h9
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c152
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-est-common.h25
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;
+}
+