aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-08-22 01:18:04 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-08-22 01:18:04 -0700
commit26a9b9cfb717e342e9c6e1877e3c0cbed2922057 (patch)
treefb4df5ce71149da50270abf773430d5d7a1d07a8 /arch
parentf9ee7122964e06b3a50de26b219157efb392de00 (diff)
parenta0dea52bb03981cccc9ea6cb19e51c5587d4c441 (diff)
downloadhistory-26a9b9cfb717e342e9c6e1877e3c0cbed2922057.tar.gz
Merge bk://linux-dj.bkbits.net/cpufreq
into ppc970.osdl.org:/home/torvalds/v2.6/linux
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Kconfig10
-rw-r--r--arch/i386/kernel/cpu/cpufreq/gx-suspmod.c1
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c103
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longrun.c42
-rw-r--r--arch/i386/kernel/cpu/cpufreq/p4-clockmod.c4
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k7.c72
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.c8
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.h2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c250
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-ich.c117
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-smi.c7
-rw-r--r--arch/i386/kernel/smpboot.c2
-rw-r--r--arch/i386/kernel/timers/timer_tsc.c7
-rw-r--r--arch/x86_64/kernel/cpufreq/Kconfig5
14 files changed, 387 insertions, 243 deletions
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
index d285dc1bafcec8..5cd444214f1ea0 100644
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -88,6 +88,11 @@ config X86_POWERNOW_K7
If in doubt, say N.
+config X86_POWERNOW_K7_ACPI
+ bool
+ depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y"))
+ default y
+
config X86_POWERNOW_K8
tristate "AMD Opteron/Athlon64 PowerNow!"
depends on CPU_FREQ && EXPERIMENTAL
@@ -98,6 +103,11 @@ config X86_POWERNOW_K8
If in doubt, say N.
+config X86_POWERNOW_K8_ACPI
+ bool
+ depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+ default y
+
config X86_GX_SUSPMOD
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
depends on CPU_FREQ
diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
index fefaf45a08c142..1f855c54c4a63a 100644
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
@@ -297,6 +297,7 @@ static void gx_set_cpuspeed(unsigned int khz)
case PCI_DEVICE_ID_CYRIX_5520:
case PCI_DEVICE_ID_CYRIX_5510:
suscfg = gx_params->pci_suscfg | SUSMOD;
+ break;
default:
local_irq_restore(flags);
dprintk("fatal: try to set unknown chipset.\n");
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 57c0377b4ec8e2..b3bcde8c0ec5c5 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -5,14 +5,19 @@
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by VIA.
*
- * VIA have currently 2 different versions of Longhaul.
+ * VIA have currently 3 different versions of Longhaul.
* Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
- * It is present only in Samuel 1, Samuel 2 and Ezra.
- * Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a.
- * It is present in Ezra-T, Nehemiah and above.
- * In addition to scaling multiplier, it can also scale voltage.
- * There is provision for scaling FSB too, but this doesn't work
- * too well in practice.
+ * It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.
+ * Version 2 of longhaul is the same as v1, but adds voltage scaling.
+ * Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C)
+ * voltage scaling support has currently been disabled in this driver
+ * until we have code that gets it right.
+ * Version 3 of longhaul got renamed to Powersaver and redesigned
+ * to use the POWERSAVER MSR at 0x110a.
+ * It is present in Ezra-T (C5M), Nehemiah (C5X) and above.
+ * It's pretty much the same feature wise to longhaul v2, though
+ * there is provision for scaling FSB too, but this doesn't work
+ * too well in practice so we don't even try to use this.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/
@@ -95,6 +100,27 @@ static int longhaul_get_cpu_mult(void)
}
+static void do_powersaver(union msr_longhaul *longhaul,
+ unsigned int clock_ratio_index, int version)
+{
+ rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
+ longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+ longhaul->bits.EnableSoftBusRatio = 1;
+ longhaul->bits.RevisionKey = 0;
+ local_irq_disable();
+ wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ local_irq_enable();
+ __hlt();
+
+ rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ longhaul->bits.EnableSoftBusRatio = 0;
+ longhaul->bits.RevisionKey = version;
+ local_irq_disable();
+ wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ local_irq_enable();
+}
+
/**
* longhaul_set_cpu_frequency()
* @clock_ratio_index : bitpattern of the new multiplier.
@@ -126,61 +152,54 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10);
switch (longhaul_version) {
+
+ /*
+ * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
+ * Software controlled multipliers only.
+ *
+ * *NB* Until we get voltage scaling working v1 & v2 are the same code.
+ * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C]
+ */
case 1:
rdmsrl (MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
bcr2.bits.ESOFTBF = 1;
bcr2.bits.CLOCKMUL = clock_ratio_index;
+ local_irq_disable();
wrmsrl (MSR_VIA_BCR2, bcr2.val);
+ local_irq_enable();
__hlt();
/* Disable software clock multiplier */
rdmsrl (MSR_VIA_BCR2, bcr2.val);
bcr2.bits.ESOFTBF = 0;
+ local_irq_disable();
wrmsrl (MSR_VIA_BCR2, bcr2.val);
+ local_irq_enable();
break;
/*
- * Powersaver. (Ezra-T [C5M], Nehemiah [C5N])
+ * Longhaul v3 (aka Powersaver). (Ezra-T [C5M])
* We can scale voltage with this too, but that's currently
* disabled until we come up with a decent 'match freq to voltage'
* algorithm.
- * We also need to do the voltage/freq setting in order depending
- * on the direction of scaling (like we do in powernow-k7.c)
- * Ezra-T was alleged to do FSB scaling too, but it never worked in practice.
+ * When we add voltage scaling, we will also need to do the
+ * voltage/freq setting in order depending on the direction
+ * of scaling (like we do in powernow-k7.c)
*/
case 2:
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
- longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
- longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
- longhaul.bits.EnableSoftBusRatio = 1;
- /* We must program the revision key only with values we
- * know about, not blindly copy it from 0:3 */
- longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */
- wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- __hlt();
-
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
- longhaul.bits.EnableSoftBusRatio = 0;
- longhaul.bits.RevisionKey = 3;
- wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+ do_powersaver(&longhaul, clock_ratio_index, 3);
break;
- case 3:
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
- longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
- longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
- longhaul.bits.EnableSoftBusRatio = 1;
-
- longhaul.bits.RevisionKey = 0x0;
- wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- __hlt();
-
- rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
- longhaul.bits.EnableSoftBusRatio = 0;
- longhaul.bits.RevisionKey = 0xf;
- wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
+ /*
+ * Powersaver. (Nehemiah [C5N])
+ * As for Ezra-T, we don't do voltage yet.
+ * This can do FSB scaling too, but it has never been proven
+ * to work in practice.
+ */
+ case 3:
+ do_powersaver(&longhaul, clock_ratio_index, 0xf);
break;
}
@@ -289,7 +308,11 @@ static int __init longhaul_get_ranges(void)
minmult=50;
maxmult=longhaul_get_cpu_mult();
- fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
+ /* Starting with the 1.2GHz parts, theres a 200MHz bus. */
+ if ((cpu_khz/1000) > 1200)
+ fsb = 200;
+ else
+ fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
break;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c
index c04c99bba8c97a..ab3cfc3cdee949 100644
--- a/arch/i386/kernel/cpu/cpufreq/longrun.c
+++ b/arch/i386/kernel/cpu/cpufreq/longrun.c
@@ -7,7 +7,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
@@ -19,7 +19,7 @@
static struct cpufreq_driver longrun_driver;
/**
- * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
+ * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
* values into per cent values. In TMTA microcode, the following is valid:
* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
*/
@@ -42,18 +42,18 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
else
policy->policy = CPUFREQ_POLICY_POWERSAVE;
-
+
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F;
-
+
if ( longrun_high_freq <= longrun_low_freq ) {
/* Assume degenerate Longrun table */
policy->min = policy->max = longrun_high_freq;
} else {
- policy->min = longrun_low_freq + msr_lo *
+ policy->min = longrun_low_freq + msr_lo *
((longrun_high_freq - longrun_low_freq) / 100);
- policy->max = longrun_low_freq + msr_hi *
+ policy->max = longrun_low_freq + msr_hi *
((longrun_high_freq - longrun_low_freq) / 100);
}
policy->cpu = 0;
@@ -79,9 +79,9 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
/* Assume degenerate Longrun table */
pctg_lo = pctg_hi = 100;
} else {
- pctg_lo = (policy->min - longrun_low_freq) /
+ pctg_lo = (policy->min - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
- pctg_hi = (policy->max - longrun_low_freq) /
+ pctg_hi = (policy->max - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
}
@@ -118,7 +118,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
* longrun_verify_poliy - verifies a new CPUFreq policy
* @policy: the policy to verify
*
- * Validates a new CPUFreq policy. This function has to be called with
+ * Validates a new CPUFreq policy. This function has to be called with
* cpufreq_driver locked.
*/
static int longrun_verify_policy(struct cpufreq_policy *policy)
@@ -127,8 +127,8 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
return -EINVAL;
policy->cpu = 0;
- cpufreq_verify_within_limits(policy,
- policy->cpuinfo.min_freq,
+ cpufreq_verify_within_limits(policy,
+ policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
@@ -160,7 +160,7 @@ static unsigned int longrun_get(unsigned int cpu)
* TMTA rules:
* performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
*/
-static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
+static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
unsigned int *high_freq)
{
u32 msr_lo, msr_hi;
@@ -174,9 +174,9 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
if (cpu_has(c, X86_FEATURE_LRTI)) {
/* if the LongRun Table Interface is present, the
- * detection is a bit easier:
+ * detection is a bit easier:
* For minimum frequency, read out the maximum
- * level (msr_hi), write that into "currently
+ * level (msr_hi), write that into "currently
* selected level", and read out the frequency.
* For maximum frequency, read out level zero.
*/
@@ -223,7 +223,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
/* restore values */
- wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
+ wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
}
/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
@@ -237,7 +237,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
if ((ecx > 95) || (ecx == 0) || (eax < ebx))
return -EIO;
- edx = (eax - ebx) / (100 - ecx);
+ edx = (eax - ebx) / (100 - ecx);
*low_freq = edx * 1000; /* back to kHz */
if (*low_freq > *high_freq)
@@ -249,7 +249,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
static int __init longrun_cpu_init(struct cpufreq_policy *policy)
{
- int result = 0;
+ int result = 0;
/* capability check */
if (policy->cpu != 0)
@@ -265,15 +265,15 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = longrun_high_freq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
longrun_get_policy(policy);
-
+
return 0;
}
static struct cpufreq_driver longrun_driver = {
.flags = CPUFREQ_CONST_LOOPS,
- .verify = longrun_verify_policy,
- .setpolicy = longrun_set_policy,
+ .verify = longrun_verify_policy,
+ .setpolicy = longrun_set_policy,
.get = longrun_get,
.init = longrun_cpu_init,
.name = "longrun",
@@ -290,7 +290,7 @@ static int __init longrun_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
- if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
+ if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
!cpu_has(c, X86_FEATURE_LONGRUN))
return -ENODEV;
diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
index fa01a95bbaa313..ef139496401f82 100644
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
@@ -184,7 +184,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
"The speedstep_centrino module offers voltage scaling"
" in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
- /* on P-4s, the TSC runs with constant frequency independent wether
+ /* on P-4s, the TSC runs with constant frequency independent whether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
@@ -195,7 +195,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
return 0;
}
- /* on P-4s, the TSC runs with constant frequency independent wether
+ /* on P-4s, the TSC runs with constant frequency independent whether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
index 18d30ab9a43eba..8e05d601c011ec 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
@@ -6,8 +6,6 @@
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by AMD.
*
- * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
- *
* Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
* - We cli/sti on stepping A0 CPUs around the FID/VID transition.
* Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
@@ -29,21 +27,13 @@
#include <asm/io.h>
#include <asm/system.h>
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
#include "powernow-k7.h"
-#define DEBUG
-
-#ifdef DEBUG
-#define dprintk(msg...) printk(msg)
-#else
-#define dprintk(msg...) do { } while(0)
-#endif
-
#define PFX "powernow: "
@@ -64,7 +54,7 @@ struct pst_s {
u8 numpstates;
};
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
union powernow_acpi_control_t {
struct {
unsigned long fid:5,
@@ -97,6 +87,7 @@ static int fid_codes[32] = {
*/
static int acpi_force;
+static int debug;
static struct cpufreq_frequency_table *powernow_table;
@@ -109,6 +100,21 @@ static unsigned int fsb;
static unsigned int latency;
static char have_a0;
+static void dprintk(const char *fmt, ...)
+{
+ char s[256];
+ va_list args;
+
+ if (debug==0)
+ return;
+
+ va_start(args,fmt);
+ vsprintf(s, fmt, args);
+ printk(s);
+ va_end(args);
+}
+
+
static int check_fsb(unsigned int fsbspeed)
{
int delta;
@@ -190,13 +196,13 @@ static int get_ranges (unsigned char *pst)
speed = powernow_table[j].frequency;
if ((fid_codes[fid] % 10)==5) {
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (have_a0 == 1)
powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
#endif
}
- dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid,
+ dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid,
fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
if (speed < minimum_speed)
@@ -285,7 +291,7 @@ static void change_speed (unsigned int index)
change_VID(vid);
change_FID(fid);
}
-
+
if (have_a0 == 1)
local_irq_enable();
@@ -294,7 +300,7 @@ static void change_speed (unsigned int index)
}
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
struct acpi_processor_performance *acpi_processor_perf;
@@ -377,7 +383,7 @@ static int powernow_acpi_init(void)
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
- dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid,
+ dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid,
fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000,
mobile_vid_table[vid]%1000);
@@ -467,9 +473,9 @@ static int powernow_decode_bios (int maxfid, int startvid)
(maxfid==pst->maxfid) && (startvid==pst->startvid))
{
dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst);
- dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid);
- dprintk ("fsb: %d\t", pst->fsbspeed);
- dprintk ("maxFID: 0x%x\t", pst->maxfid);
+ dprintk (KERN_INFO PFX " cpuid: 0x%x ", pst->cpuid);
+ dprintk ("fsb: %d ", pst->fsbspeed);
+ dprintk ("maxFID: 0x%x ", pst->maxfid);
dprintk ("startvid: 0x%x\n", pst->startvid);
ret = get_ranges ((char *) pst + sizeof (struct pst_s));
@@ -591,14 +597,14 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
/* A K7 with powernow technology is set to max frequency by BIOS */
- fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
+ fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID];
if (!fsb) {
printk(KERN_WARNING PFX "can not determine bus frequency\n");
return -EINVAL;
}
dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000);
- if (dmi_check_system(powernow_dmi_table) || acpi_force) {
+ if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n");
result = powernow_acpi_init();
} else {
@@ -648,14 +654,14 @@ static struct freq_attr* powernow_table_attr[] = {
};
static struct cpufreq_driver powernow_driver = {
- .verify = powernow_verify,
- .target = powernow_target,
- .get = powernow_get,
- .init = powernow_cpu_init,
- .exit = powernow_cpu_exit,
- .name = "powernow-k7",
- .owner = THIS_MODULE,
- .attr = powernow_table_attr,
+ .verify = powernow_verify,
+ .target = powernow_target,
+ .get = powernow_get,
+ .init = powernow_cpu_init,
+ .exit = powernow_cpu_exit,
+ .name = "powernow-k7",
+ .owner = THIS_MODULE,
+ .attr = powernow_table_attr,
};
static int __init powernow_init (void)
@@ -668,7 +674,7 @@ static int __init powernow_init (void)
static void __exit powernow_exit (void)
{
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
kfree(acpi_processor_perf);
@@ -679,8 +685,10 @@ static void __exit powernow_exit (void)
kfree(powernow_table);
}
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "enable debug output.");
module_param(acpi_force, int, 0444);
-MODULE_PARM_DESC(acpi_force, "Force ACPI to be used");
+MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index 05ed9025e97006..7113c2e6e5f144 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <asm/delay.h>
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
@@ -664,7 +664,7 @@ static int find_psb_table(struct powernow_k8_data *data)
return -ENODEV;
}
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
{
if (!data->acpi_data.state_count)
@@ -1024,7 +1024,7 @@ err_out:
return -ENODEV;
}
-static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
+static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
{
struct powernow_k8_data *data = powernow_data[pol->cpu];
@@ -1076,7 +1076,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.verify = powernowk8_verify,
.target = powernowk8_target,
.init = powernowk8_cpu_init,
- .exit = powernowk8_cpu_exit,
+ .exit = __devexit_p(powernowk8_cpu_exit),
.get = powernowk8_get,
.name = "powernow-k8",
.owner = THIS_MODULE,
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index 500f28d277944a..a95db64a9b194c 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -29,7 +29,7 @@ struct powernow_k8_data {
* frequency is in kHz */
struct cpufreq_frequency_table *powernow_table;
-#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
/* the acpi table needs to be kept. it's only available if ACPI was
* used to determine valid frequency/vid/fid states */
struct acpi_processor_performance acpi_data;
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index ea917381299cbc..56aafbde6377be 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -10,7 +10,7 @@
* Copyright (C) 2003 Jeremy Fitzhardinge <jeremy@goop.org>
*
* WARNING WARNING WARNING
- *
+ *
* This driver manipulates the PERF_CTL MSR, which is only somewhat
* documented. While it seems to work on my laptop, it has not been
* tested anywhere else, and it may not work for you, do strange
@@ -23,6 +23,11 @@
#include <linux/cpufreq.h>
#include <linux/config.h>
+#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
+#include <linux/acpi.h>
+#include <acpi/processor.h>
+#endif
+
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
@@ -41,24 +46,24 @@
struct cpu_id
{
__u8 x86; /* CPU family */
- __u8 x86_vendor; /* CPU vendor */
__u8 x86_model; /* model */
__u8 x86_mask; /* stepping */
};
-static const struct cpu_id cpu_id_banias = {
- .x86_vendor = X86_VENDOR_INTEL,
- .x86 = 6,
- .x86_model = 9,
- .x86_mask = 5,
+enum {
+ CPU_BANIAS,
+ CPU_DOTHAN_A1,
+ CPU_DOTHAN_A2,
+ CPU_DOTHAN_B0,
};
-static const struct cpu_id cpu_id_dothan_a1 = {
- .x86_vendor = X86_VENDOR_INTEL,
- .x86 = 6,
- .x86_model = 13,
- .x86_mask = 1,
+static const struct cpu_id cpu_ids[] = {
+ [CPU_BANIAS] = { 6, 9, 5 },
+ [CPU_DOTHAN_A1] = { 6, 13, 1 },
+ [CPU_DOTHAN_A2] = { 6, 13, 2 },
+ [CPU_DOTHAN_B0] = { 6, 13, 6 },
};
+#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0]))
struct cpu_model
{
@@ -68,10 +73,11 @@ struct cpu_model
struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
};
-static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x);
+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 int centrino_cpu;
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
@@ -84,7 +90,7 @@ static struct cpu_model *centrino_model;
.index = (((mhz)/100) << 8) | ((mv - 700) / 16) \
}
-/*
+/*
* These voltage tables were derived from the Intel Pentium M
* datasheet, document 25261202.pdf, Table 5. I have verified they
* are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium
@@ -103,9 +109,9 @@ static struct cpufreq_frequency_table banias_900[] =
/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */
static struct cpufreq_frequency_table banias_1000[] =
{
- OP(600, 844),
- OP(800, 972),
- OP(900, 988),
+ OP(600, 844),
+ OP(800, 972),
+ OP(900, 988),
OP(1000, 1004),
{ .frequency = CPUFREQ_TABLE_END }
};
@@ -135,7 +141,7 @@ static struct cpufreq_frequency_table banias_1200[] =
};
/* Intel Pentium M processor 1.30GHz (Banias) */
-static struct cpufreq_frequency_table banias_1300[] =
+static struct cpufreq_frequency_table banias_1300[] =
{
OP( 600, 956),
OP( 800, 1260),
@@ -146,7 +152,7 @@ static struct cpufreq_frequency_table banias_1300[] =
};
/* Intel Pentium M processor 1.40GHz (Banias) */
-static struct cpufreq_frequency_table banias_1400[] =
+static struct cpufreq_frequency_table banias_1400[] =
{
OP( 600, 956),
OP( 800, 1180),
@@ -157,7 +163,7 @@ static struct cpufreq_frequency_table banias_1400[] =
};
/* Intel Pentium M processor 1.50GHz (Banias) */
-static struct cpufreq_frequency_table banias_1500[] =
+static struct cpufreq_frequency_table banias_1500[] =
{
OP( 600, 956),
OP( 800, 1116),
@@ -169,7 +175,7 @@ static struct cpufreq_frequency_table banias_1500[] =
};
/* Intel Pentium M processor 1.60GHz (Banias) */
-static struct cpufreq_frequency_table banias_1600[] =
+static struct cpufreq_frequency_table banias_1600[] =
{
OP( 600, 956),
OP( 800, 1036),
@@ -199,13 +205,13 @@ static struct cpufreq_frequency_table banias_1700[] =
.max_freq = (max)*1000, \
.op_points = banias_##max, \
}
-#define BANIAS(max) _BANIAS(&cpu_id_banias, max, #max)
+#define BANIAS(max) _BANIAS(&cpu_ids[CPU_BANIAS], max, #max)
/* CPU models, their operating frequency range, and freq/voltage
operating points */
-static struct cpu_model models[] =
+static struct cpu_model models[] =
{
- _BANIAS(&cpu_id_banias, 900, " 900"),
+ _BANIAS(&cpu_ids[CPU_BANIAS], 900, " 900"),
BANIAS(1000),
BANIAS(1100),
BANIAS(1200),
@@ -214,6 +220,12 @@ static struct cpu_model models[] =
BANIAS(1500),
BANIAS(1600),
BANIAS(1700),
+
+ /* NULL model_name is a wildcard */
+ { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL },
+ { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL },
+ { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL },
+
{ NULL, }
};
#undef _BANIAS
@@ -224,19 +236,30 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
struct cpu_model *model;
- for(model = models; model->model_name != NULL; model++)
- if ((strcmp(cpu->x86_model_id, model->model_name) == 0) &&
- (!centrino_verify_cpu_id(cpu, model->cpu_id)))
+ for(model = models; model->cpu_id != NULL; model++)
+ if (centrino_verify_cpu_id(cpu, model->cpu_id) &&
+ (model->model_name == NULL ||
+ strcmp(cpu->x86_model_id, model->model_name) == 0))
break;
- if (model->model_name == NULL) {
+
+ if (model->cpu_id == NULL) {
+ /* No match at all */
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
}
+ if (model->op_points == NULL) {
+ /* Matched a non-match */
+ printk(KERN_INFO PFX "no table support for CPU model \"%s\": \n",
+ cpu->x86_model_id);
+ printk(KERN_INFO PFX "try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n");
+ return -ENOENT;
+ }
+
centrino_model = model;
-
+
printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
@@ -247,31 +270,54 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
-static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x)
+static int centrino_verify_cpu_id(const struct cpuinfo_x86 *c, const struct cpu_id *x)
{
if ((c->x86 == x->x86) &&
- (c->x86_vendor == x->x86_vendor) &&
(c->x86_model == x->x86_model) &&
(c->x86_mask == x->x86_mask))
- return 0;
- return -ENODEV;
+ return 1;
+ return 0;
}
-/* Extract clock in kHz from PERF_CTL value */
+/* To be called only after centrino_model is initialized */
static unsigned extract_clock(unsigned msr)
{
- msr = (msr >> 8) & 0xff;
- return msr * 100000;
+ int i;
+
+ /*
+ * Extract clock in kHz from PERF_CTL value
+ * for centrino, as some DSDTs are buggy.
+ * Ideally, this can be done using the acpi_data structure.
+ */
+ if (centrino_cpu) {
+ msr = (msr >> 8) & 0xff;
+ return msr * 100000;
+ }
+
+ if ((!centrino_model) || (!centrino_model->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;
+ }
+ return 0;
}
/* Return the current CPU frequency in kHz */
static unsigned int get_cur_freq(unsigned int cpu)
{
unsigned l, h;
- if (cpu)
+ cpumask_t saved_mask;
+
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (smp_processor_id() != cpu)
return 0;
rdmsr(MSR_IA32_PERF_STATUS, l, h);
+ set_cpus_allowed(current, saved_mask);
return extract_clock(l);
}
@@ -280,13 +326,8 @@ static unsigned int get_cur_freq(unsigned int cpu)
static struct acpi_processor_performance p;
-#include <linux/acpi.h>
-#include <acpi/processor.h>
-
-#define ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP 0x1
-
/*
- * centrino_cpu_init_acpi - register with ACPI P-States library
+ * centrino_cpu_init_acpi - register with ACPI P-States library
*
* Register with the ACPI P-States library (part of drivers/acpi/processor.c)
* in order to determine correct frequency and voltage pairings by reading
@@ -296,7 +337,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
{
union acpi_object arg0 = {ACPI_TYPE_BUFFER};
u32 arg0_buf[3];
- struct acpi_object_list arg_list = {1, &arg0};
+ struct acpi_object_list arg_list = {1, &arg0};
unsigned long cur_freq;
int result = 0, i;
@@ -305,12 +346,12 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
arg0.buffer.pointer = (u8 *) arg0_buf;
arg0_buf[0] = ACPI_PDC_REVISION_ID;
arg0_buf[1] = 1;
- arg0_buf[2] = ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP;
+ arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_MSR;
p.pdc = &arg_list;
/* register with ACPI core */
- if (acpi_processor_register_performance(&p, 0))
+ if (acpi_processor_register_performance(&p, policy->cpu))
return -EIO;
/* verify the acpi_data */
@@ -318,7 +359,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
printk(KERN_DEBUG "No P-States\n");
result = -ENODEV;
goto err_unreg;
- }
+ }
if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
@@ -340,11 +381,10 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
goto err_unreg;
}
- if (extract_clock(p.states[i].control) !=
- (p.states[i].core_frequency * 1000)) {
- printk(KERN_DEBUG "Invalid encoded frequency\n");
- result = -EINVAL;
- goto err_unreg;
+ if (p.states[i].core_frequency > p.states[0].core_frequency) {
+ printk(KERN_DEBUG "P%u has larger frequency than P0, skipping\n", i);
+ p.states[i].core_frequency = 0;
+ continue;
}
}
@@ -357,29 +397,43 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
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->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
(p.state_count + 1), GFP_KERNEL);
if (!centrino_model->op_points) {
result = -ENOMEM;
goto err_kfree;
}
- cur_freq = get_cur_freq(0);
-
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->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
+
+ cur_freq = get_cur_freq(policy->cpu);
+
+ for (i=0; i<p.state_count; i++) {
+ if (extract_clock(centrino_model->op_points[i].index) !=
+ (centrino_model->op_points[i].frequency)) {
+ printk(KERN_DEBUG "Invalid encoded frequency\n");
+ result = -EINVAL;
+ goto err_kfree_all;
+ }
+
if (cur_freq == centrino_model->op_points[i].frequency)
p.state = i;
+ if (!p.states[i].core_frequency)
+ centrino_model->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
}
- centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
return 0;
+ err_kfree_all:
+ kfree(centrino_model->op_points);
err_kfree:
kfree(centrino_model);
err_unreg:
- acpi_processor_unregister_performance(&p, 0);
+ acpi_processor_unregister_performance(&p, policy->cpu);
return (result);
}
#else
@@ -392,21 +446,30 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
unsigned freq;
unsigned l, h;
int ret;
+ int i;
- if (policy->cpu != 0)
+ /* Only Intel makes Enhanced Speedstep-capable CPUs */
+ if (cpu->x86_vendor != X86_VENDOR_INTEL || !cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
- if (!cpu_has(cpu, X86_FEATURE_EST))
- return -ENODEV;
+ for (i = 0; i < N_IDS; i++)
+ if (centrino_verify_cpu_id(cpu, &cpu_ids[i]))
+ break;
- if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) &&
- (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) {
- printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
- "send /proc/cpuinfo to " MAINTAINER "\n");
- return -ENODEV;
- }
+ if (i != N_IDS)
+ centrino_cpu = 1;
if (centrino_cpu_init_acpi(policy)) {
+ if (policy->cpu != 0)
+ return -ENODEV;
+
+ if (!centrino_cpu) {
+ printk(KERN_INFO PFX "found unsupported CPU with "
+ "Enhanced SpeedStep: send /proc/cpuinfo to "
+ MAINTAINER "\n");
+ return -ENODEV;
+ }
+
if (centrino_cpu_init_table(policy)) {
return -ENODEV;
}
@@ -415,11 +478,11 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
/* Check to see if Enhanced SpeedStep is enabled, and try to
enable it if not. */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-
+
if (!(l & (1<<16))) {
l |= (1<<16);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
-
+
/* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
@@ -428,7 +491,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
}
}
- freq = get_cur_freq(0);
+ freq = get_cur_freq(policy->cpu);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
@@ -436,7 +499,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
policy->policy, policy->cur);
-
+
ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
if (ret)
return (ret);
@@ -455,7 +518,7 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
if (!centrino_model->model_name) {
- acpi_processor_unregister_performance(&p, 0);
+ acpi_processor_unregister_performance(&p, policy->cpu);
kfree(centrino_model->op_points);
kfree(centrino_model);
}
@@ -493,19 +556,35 @@ static int centrino_target (struct cpufreq_policy *policy,
unsigned int newstate = 0;
unsigned int msr, oldmsr, h;
struct cpufreq_freqs freqs;
+ cpumask_t saved_mask;
+ int retval;
if (centrino_model == NULL)
return -ENODEV;
+ /*
+ * Support for SMP systems.
+ * Make sure we are running on the CPU that wants to change frequency
+ */
+ saved_mask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(policy->cpu));
+ if (smp_processor_id() != policy->cpu) {
+ return(-EAGAIN);
+ }
+
if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq,
- relation, &newstate))
- return -EINVAL;
+ relation, &newstate)) {
+ retval = -EINVAL;
+ goto migrate_end;
+ }
msr = centrino_model->op_points[newstate].index;
rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
- if (msr == (oldmsr & 0xffff))
- return 0;
+ if (msr == (oldmsr & 0xffff)) {
+ retval = 0;
+ goto migrate_end;
+ }
/* Hm, old frequency can either be the last value we put in
PERF_CTL, or whatever it is now. The trouble is that TM2
@@ -514,31 +593,34 @@ static int centrino_target (struct cpufreq_policy *policy,
tell us something happened, but it may leave the things on
the notifier chain confused; we therefore stick to using
the last programmed speed rather than the current speed for
- "old".
+ "old".
TODO: work out how the TCC interrupts work, and try to
catch the CPU changing things under us.
*/
- freqs.cpu = 0;
+ freqs.cpu = policy->cpu;
freqs.old = extract_clock(oldmsr);
freqs.new = extract_clock(msr);
-
+
dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n",
target_freq, freqs.old, freqs.new, msr);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* all but 16 LSB are "reserved", so treat them with
care */
oldmsr &= ~0xffff;
msr &= 0xffff;
oldmsr |= msr;
-
+
wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- return 0;
+ retval = 0;
+migrate_end:
+ set_cpus_allowed(current, saved_mask);
+ return (retval);
}
static struct freq_attr* centrino_attr[] = {
@@ -547,12 +629,12 @@ static struct freq_attr* centrino_attr[] = {
};
static struct cpufreq_driver centrino_driver = {
- .name = "centrino", /* should be speedstep-centrino,
+ .name = "centrino", /* should be speedstep-centrino,
but there's a 16 char limit */
.init = centrino_cpu_init,
.exit = centrino_cpu_exit,
- .verify = centrino_verify,
- .target = centrino_target,
+ .verify = centrino_verify,
+ .target = centrino_target,
.get = get_cur_freq,
.attr = centrino_attr,
.owner = THIS_MODULE,
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
index 93b70f0dc53b2a..5f94c4fa24e77f 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
@@ -7,7 +7,7 @@
* for chipsets ICH2-M and ICH3-M.
*
* Many thanks to Ducrot Bruno for finding and fixing the last
- * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
+ * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
* for extensive testing.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
@@ -19,7 +19,7 @@
*********************************************************************/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
@@ -29,24 +29,24 @@
/* speedstep_chipset:
- * It is necessary to know which chipset is used. As accesses to
- * this device occur at various places in this module, we need a
+ * It is necessary to know which chipset is used. As accesses to
+ * this device occur at various places in this module, we need a
* static struct pci_dev * pointing to that device.
*/
-static struct pci_dev *speedstep_chipset_dev;
+static struct pci_dev *speedstep_chipset_dev;
/* speedstep_processor
*/
-static unsigned int speedstep_processor = 0;
+static unsigned int speedstep_processor = 0;
-/*
+/*
* There are only two frequency states for each processor. Values
* are in kHz for the time being.
*/
static struct cpufreq_frequency_table speedstep_freqs[] = {
- {SPEEDSTEP_HIGH, 0},
+ {SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_LOW, 0},
{0, CPUFREQ_TABLE_END},
};
@@ -68,22 +68,21 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
*
- * Tries to change the SpeedStep state.
+ * Tries to change the SpeedStep state.
*/
static void speedstep_set_state (unsigned int state)
{
- u32 pmbase;
- u8 pm2_blk;
- u8 value;
- unsigned long flags;
+ u32 pmbase;
+ u8 pm2_blk;
+ u8 value;
+ unsigned long flags;
if (!speedstep_chipset_dev || (state > 0x1))
return;
/* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
- if (!(pmbase & 0x01))
- {
+ if (!(pmbase & 0x01)) {
printk(KERN_ERR "cpufreq: could not find speedstep register\n");
return;
}
@@ -146,18 +145,16 @@ static void speedstep_set_state (unsigned int state)
*/
static int speedstep_activate (void)
{
- u16 value = 0;
+ u16 value = 0;
if (!speedstep_chipset_dev)
return -EINVAL;
- pci_read_config_word(speedstep_chipset_dev,
- 0x00A0, &value);
+ pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
if (!(value & 0x08)) {
value |= 0x08;
dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n");
- pci_write_config_word(speedstep_chipset_dev,
- 0x00A0, value);
+ pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
}
return 0;
@@ -167,15 +164,15 @@ static int speedstep_activate (void)
/**
* speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
*
- * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
- * the LPC bridge / PM module which contains all power-management
+ * Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
+ * the LPC bridge / PM module which contains all power-management
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
* chipset, or zero on failure.
*/
static unsigned int speedstep_detect_chipset (void)
{
speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82801DB_12,
+ PCI_DEVICE_ID_INTEL_82801DB_12,
PCI_ANY_ID,
PCI_ANY_ID,
NULL);
@@ -183,7 +180,7 @@ static unsigned int speedstep_detect_chipset (void)
return 4; /* 4-M */
speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82801CA_12,
+ PCI_DEVICE_ID_INTEL_82801CA_12,
PCI_ANY_ID,
PCI_ANY_ID,
NULL);
@@ -198,11 +195,11 @@ static unsigned int speedstep_detect_chipset (void)
NULL);
if (speedstep_chipset_dev) {
/* speedstep.c causes lockups on Dell Inspirons 8000 and
- * 8100 which use a pretty old revision of the 82815
+ * 8100 which use a pretty old revision of the 82815
* host brige. Abort on these systems.
*/
- static struct pci_dev *hostbridge;
- u8 rev = 0;
+ static struct pci_dev *hostbridge;
+ u8 rev = 0;
hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_MC,
@@ -212,7 +209,7 @@ static unsigned int speedstep_detect_chipset (void)
if (!hostbridge)
return 2; /* 2-M */
-
+
pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
if (rev < 5) {
dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n");
@@ -226,6 +223,23 @@ static unsigned int speedstep_detect_chipset (void)
return 0;
}
+static unsigned int speedstep_get(unsigned int cpu)
+{
+ unsigned int speed;
+ cpumask_t cpus_allowed,affected_cpu_map;
+
+ /* only run on CPU to be set, or on its sibling */
+ cpus_allowed = current->cpus_allowed;
+#ifdef CONFIG_SMP
+ affected_cpu_map = cpu_sibling_map[cpu];
+#else
+ affected_cpu_map = cpumask_of_cpu(cpu);
+#endif
+ set_cpus_allowed(current, affected_cpu_map);
+ speed=speedstep_get_processor_frequency(speedstep_processor);
+ set_cpus_allowed(current, cpus_allowed);
+ return speed;
+}
/**
* speedstep_target - set a new CPUFreq policy
@@ -239,7 +253,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- unsigned int newstate = 0;
+ unsigned int newstate = 0;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
int i;
@@ -247,14 +261,14 @@ static int speedstep_target (struct cpufreq_policy *policy,
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
return -EINVAL;
+ freqs.old = speedstep_get(policy->cpu);
+ freqs.new = speedstep_freqs[newstate].frequency;
+ freqs.cpu = policy->cpu;
+
/* no transition necessary */
if (freqs.old == freqs.new)
return 0;
- freqs.old = speedstep_get_processor_frequency(speedstep_processor);
- freqs.new = speedstep_freqs[newstate].frequency;
- freqs.cpu = policy->cpu;
-
cpus_allowed = current->cpus_allowed;
/* only run on CPU to be set, or on its sibling */
@@ -301,9 +315,9 @@ static int speedstep_verify (struct cpufreq_policy *policy)
static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
- int result = 0;
- unsigned int speed;
- cpumask_t cpus_allowed,affected_cpu_map;
+ int result = 0;
+ unsigned int speed;
+ cpumask_t cpus_allowed,affected_cpu_map;
/* capability check */
@@ -324,18 +338,16 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
&speedstep_set_state);
- if (result) {
- set_cpus_allowed(current, cpus_allowed);
+ set_cpus_allowed(current, cpus_allowed);
+ if (result)
return result;
- }
/* get current speed setting */
- speed = speedstep_get_processor_frequency(speedstep_processor);
- set_cpus_allowed(current, cpus_allowed);
+ speed = speedstep_get(policy->cpu);
if (!speed)
return -EIO;
- dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n",
+ dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
(speed / 1000));
@@ -360,11 +372,6 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
-static unsigned int speedstep_get(unsigned int cpu)
-{
- return speedstep_get_processor_frequency(speedstep_processor);
-}
-
static struct freq_attr* speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
@@ -372,14 +379,14 @@ static struct freq_attr* speedstep_attr[] = {
static struct cpufreq_driver speedstep_driver = {
- .name = "speedstep-ich",
- .verify = speedstep_verify,
- .target = speedstep_target,
- .init = speedstep_cpu_init,
- .exit = speedstep_cpu_exit,
- .get = speedstep_get,
- .owner = THIS_MODULE,
- .attr = speedstep_attr,
+ .name = "speedstep-ich",
+ .verify = speedstep_verify,
+ .target = speedstep_target,
+ .init = speedstep_cpu_init,
+ .exit = speedstep_cpu_exit,
+ .get = speedstep_get,
+ .owner = THIS_MODULE,
+ .attr = speedstep_attr,
};
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
index 6aa31cd5a3af89..5d176b19acfb78 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
@@ -115,6 +115,11 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi)
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
);
+
+ /* abort if results are obviously incorrect... */
+ if ((high_mhz + low_mhz) < 600)
+ return -EINVAL;
+
*high = high_mhz * 1000;
*low = low_mhz * 1000;
@@ -180,7 +185,7 @@ static void speedstep_set_state (unsigned int state)
local_irq_restore(flags);
if (new_state == state) {
- dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (freqs.new / 1000), retry, result);
+ dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result);
} else {
printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result);
}
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index d973f934b45929..de91beb190ed7c 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -17,7 +17,7 @@
* Fixes
* Felix Koop : NR_CPUS used properly
* Jose Renau : Handle single CPU case.
- * Alan Cox : By repeated request 8) - Total BogoMIP report.
+ * Alan Cox : By repeated request 8) - Total BogoMIPS report.
* Greg Wright : Fix for kernel stacks panic.
* Erich Boleyn : MP v1.4 and additional changes.
* Matthias Sattler : Changes for 2.1 kernel map.
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
index a1e3f6f966987a..34e9b8eba1d2d9 100644
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -265,7 +265,8 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
{
struct cpufreq_freqs *freq = data;
- write_seqlock_irq(&xtime_lock);
+ if (val != CPUFREQ_RESUMECHANGE)
+ write_seqlock_irq(&xtime_lock);
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
@@ -291,7 +292,9 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
}
#endif
}
- write_sequnlock_irq(&xtime_lock);
+
+ if (val != CPUFREQ_RESUMECHANGE)
+ write_sequnlock_irq(&xtime_lock);
return 0;
}
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index 1b3aefc8d9f923..284023945a3b60 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -41,4 +41,9 @@ config X86_POWERNOW_K8
If in doubt, say N.
+config X86_POWERNOW_K8_ACPI
+ bool
+ depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
+ default y
+
endmenu