Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Jones <davej@tetrachloride.(none)>2003-06-12 22:21:52 +0100
committerDave Jones <davej@tetrachloride.(none)>2003-06-12 22:21:52 +0100
commitda16456fa7d292e5122d0ffa16784e195be5ed94 (patch)
tree539627964c5200785b7e14e910dbb0acb90d9eda
parentd6266c68b61add3d7d207314ffe40a0a24c92d16 (diff)
parentae981631fccf3753549df9e620bba564621b080a (diff)
Merge tetrachloride.(none):/mnt/raid/src/kernel/2.5/bk-linus
into tetrachloride.(none):/mnt/raid/src/kernel/2.5/cpufreq
-rw-r--r--Documentation/cpu-freq/user-guide.txt5
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Kconfig35
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Makefile3
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k7.c8
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c377
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-ich.c (renamed from arch/i386/kernel/cpu/cpufreq/speedstep.c)0
-rw-r--r--include/asm-i386/cpufeature.h1
-rw-r--r--include/asm-i386/msr.h3
8 files changed, 415 insertions, 17 deletions
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index b1820ebc6d8e..dd93fb46bda1 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -53,9 +53,12 @@ The following processors for the x86 architecture are supported by cpufreq:
AMD Elan - SC400, SC410
AMD mobile K6-2+
AMD mobile K6-3+
+AMD mobile Duron
+AMD mobile Athlon
Cyrix Media GXm
Intel mobile PIII [*] and Intel mobile PIII-M on certain chipsets
Intel Pentium 4, Intel Xeon
+Intel Pentium M (Centrino)
National Semiconductors Geode GX
Transmeta Crusoe
VIA Cyrix 3 / C3
@@ -117,7 +120,7 @@ the processor shall run at.
The preferred interface is located in the sysfs filesystem. If you
mounted it at /sys, the cpufreq interface is located in a subdirectory
"cpufreq" within the cpu-device directory
-(e.g. /sys/devices/sys/cpu0/cpufreq/ for the first CPU).
+(e.g. /sys/class/cpu/cpu0/cpufreq/ for the first CPU).
cpuinfo_min_freq : this file shows the minimum operating
frequency the processor can run at(in kHz)
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
index 71f31ab0ed73..013160bc0ae7 100644
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -11,7 +11,7 @@ config CPU_FREQ
fly. This is a nice method to save battery power on notebooks,
because the lower the clock speed, the less power the CPU consumes.
- For more information, take a look at linux/Documentation/cpufreq or
+ For more information, take a look at linux/Documentation/cpu-freq or
at <http://www.brodo.de/cpufreq/>
If in doubt, say N.
@@ -38,7 +38,7 @@ config X86_ACPI_CPUFREQ
This driver adds a CPUFreq driver which utilizes the ACPI
Processor Performance States.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -63,7 +63,7 @@ config ELAN_CPUFREQ
parameter: elanfreq=maxspeed (in kHz) or as module
parameter "max_freq".
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -74,7 +74,7 @@ config X86_POWERNOW_K6
This adds the CPUFreq driver for mobile AMD K6-2+ and mobile
AMD K6-3+ processors.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -84,7 +84,7 @@ config X86_POWERNOW_K7
help
This adds the CPUFreq driver for mobile AMD K7 mobile processors.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -95,22 +95,33 @@ config X86_GX_SUSPMOD
This add the CPUFreq driver for NatSemi Geode processors which
support suspend modulation.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
-config X86_SPEEDSTEP
+config X86_SPEEDSTEP_ICH
tristate "Intel Speedstep"
depends on CPU_FREQ_TABLE
help
This adds the CPUFreq driver for certain mobile Intel Pentium III
- (Coppermine), all mobile Intel Pentium III-M (Tulatin) and all
+ (Coppermine), all mobile Intel Pentium III-M (Tualatin) and all
mobile Intel Pentium 4 P4-Ms.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
+config X86_SPEEDSTEP_CENTRINO
+ tristate "Intel Enhanced SpeedStep"
+ depends on CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for Enhanced SpeedStep enabled
+ mobile CPUs. This means Intel Pentium M (Centrino) CPUs.
+
+ For details, take a look at linux/Documentation/cpu-freq.
+
+ If in doubt, say N.
+
config X86_P4_CLOCKMOD
tristate "Intel Pentium 4 clock modulation"
depends on CPU_FREQ_TABLE
@@ -118,7 +129,7 @@ config X86_P4_CLOCKMOD
This adds the CPUFreq driver for Intel Pentium 4 / XEON
processors.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -129,7 +140,7 @@ config X86_LONGRUN
This adds the CPUFreq driver for Transmeta Crusoe processors which
support LongRun.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -141,7 +152,7 @@ config X86_LONGHAUL
VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T
processors.
- For details, take a look at linux/Documentation/cpufreq.
+ For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile
index 06cfab86c990..89b2a63a7581 100644
--- a/arch/i386/kernel/cpu/cpufreq/Makefile
+++ b/arch/i386/kernel/cpu/cpufreq/Makefile
@@ -1,12 +1,13 @@
obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
-obj-$(CONFIG_X86_SPEEDSTEP) += speedstep.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o
+obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
ifdef CONFIG_X86_ACPI_CPUFREQ
ifdef CONFIG_ACPI_DEBUG
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
index 29f210384f0e..5482dc9523c8 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
@@ -10,7 +10,6 @@
*
* 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.
- * (ADDENDUM: This seems to be needed on more systems, so we do it unconditionally now).
* Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
* - We disable half multipliers if ACPI is used on A0 stepping CPUs.
*/
@@ -260,7 +259,8 @@ static void change_speed (unsigned int index)
/* Now do the magic poking into the MSRs. */
- __asm__("\tcli\n");
+ if (have_a0 == 1) /* A0 errata 5 */
+ __asm__("\tcli\n");
if (freqs.old > freqs.new) {
/* Going down, so change FID first */
@@ -272,7 +272,9 @@ static void change_speed (unsigned int index)
change_FID(vid);
}
- __asm__("\tsti\n");
+
+ if (have_a0 == 1)
+ __asm__("\tsti\n");
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
new file mode 100644
index 000000000000..470ece754595
--- /dev/null
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -0,0 +1,377 @@
+/*
+ * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium
+ * M (part of the Centrino chipset).
+ *
+ * Despite the "SpeedStep" in the name, this is almost entirely unlike
+ * traditional SpeedStep.
+ *
+ * Modelled on speedstep.c
+ *
+ * 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
+ * things or simply crash.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/cpufeature.h>
+
+#define PFX "speedstep-centrino: "
+#define MAINTAINER "Jeremy Fitzhardinge <jeremy@goop.org>"
+
+#define CENTRINO_DEBUG
+
+#ifdef CENTRINO_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0)
+#endif
+
+struct cpu_model
+{
+ const char *model_name;
+ unsigned max_freq; /* max clock in kHz */
+
+ struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
+};
+
+/* Operating points for current CPU */
+static const struct cpu_model *centrino_model;
+
+/* Computes the correct form for IA32_PERF_CTL MSR for a particular
+ frequency/voltage operating point; frequency in MHz, volts in mV.
+ This is stored as "index" in the structure. */
+#define OP(mhz, mv) \
+ { \
+ .frequency = (mhz) * 1000, \
+ .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
+ * M.
+ */
+
+/* Ultra Low Voltage Intel Pentium M processor 900MHz */
+static struct cpufreq_frequency_table op_900[] =
+{
+ OP(600, 844),
+ OP(800, 988),
+ OP(900, 1004),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Low Voltage Intel Pentium M processor 1.10GHz */
+static struct cpufreq_frequency_table op_1100[] =
+{
+ OP( 600, 956),
+ OP( 800, 1020),
+ OP( 900, 1100),
+ OP(1000, 1164),
+ OP(1100, 1180),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+
+/* Low Voltage Intel Pentium M processor 1.20GHz */
+static struct cpufreq_frequency_table op_1200[] =
+{
+ OP( 600, 956),
+ OP( 800, 1004),
+ OP( 900, 1020),
+ OP(1000, 1100),
+ OP(1100, 1164),
+ OP(1200, 1180),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Intel Pentium M processor 1.30GHz */
+static struct cpufreq_frequency_table op_1300[] =
+{
+ OP( 600, 956),
+ OP( 800, 1260),
+ OP(1000, 1292),
+ OP(1200, 1356),
+ OP(1300, 1388),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Intel Pentium M processor 1.40GHz */
+static struct cpufreq_frequency_table op_1400[] =
+{
+ OP( 600, 956),
+ OP( 800, 1180),
+ OP(1000, 1308),
+ OP(1200, 1436),
+ OP(1400, 1484),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Intel Pentium M processor 1.50GHz */
+static struct cpufreq_frequency_table op_1500[] =
+{
+ OP( 600, 956),
+ OP( 800, 1116),
+ OP(1000, 1228),
+ OP(1200, 1356),
+ OP(1400, 1452),
+ OP(1500, 1484),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Intel Pentium M processor 1.60GHz */
+static struct cpufreq_frequency_table op_1600[] =
+{
+ OP( 600, 956),
+ OP( 800, 1036),
+ OP(1000, 1164),
+ OP(1200, 1276),
+ OP(1400, 1420),
+ OP(1600, 1484),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+
+/* Intel Pentium M processor 1.70GHz */
+static struct cpufreq_frequency_table op_1700[] =
+{
+ OP( 600, 956),
+ OP( 800, 1004),
+ OP(1000, 1116),
+ OP(1200, 1228),
+ OP(1400, 1308),
+ OP(1700, 1484),
+ { .frequency = CPUFREQ_TABLE_END }
+};
+#undef OP
+
+#define CPU(max) \
+ { "Intel(R) Pentium(R) M processor " #max "MHz", (max)*1000, op_##max }
+
+/* CPU models, their operating frequency range, and freq/voltage
+ operating points */
+static const struct cpu_model models[] =
+{
+ CPU( 900),
+ CPU(1100),
+ CPU(1200),
+ CPU(1300),
+ CPU(1400),
+ CPU(1500),
+ CPU(1600),
+ CPU(1700),
+ { 0, }
+};
+#undef CPU
+
+/* Extract clock in kHz from PERF_CTL value */
+static unsigned extract_clock(unsigned msr)
+{
+ msr = (msr >> 8) & 0xff;
+ return msr * 100000;
+}
+
+/* Return the current CPU frequency in kHz */
+static unsigned get_cur_freq(void)
+{
+ unsigned l, h;
+
+ rdmsr(MSR_IA32_PERF_STATUS, l, h);
+ return extract_clock(l);
+}
+
+static int centrino_cpu_init(struct cpufreq_policy *policy)
+{
+ unsigned freq;
+
+ if (policy->cpu != 0 || centrino_model == NULL)
+ return -ENODEV;
+
+ freq = get_cur_freq();
+
+ policy->policy = (freq == centrino_model->max_freq) ?
+ CPUFREQ_POLICY_PERFORMANCE :
+ CPUFREQ_POLICY_POWERSAVE;
+ policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */
+ policy->cur = freq;
+
+ dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
+ policy->policy, policy->cur);
+
+ return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
+}
+
+/**
+ * centrino_verify - verifies a new CPUFreq policy
+ * @freq: new policy
+ *
+ * Limit must be within this model's frequency range at least one
+ * border included.
+ */
+static int centrino_verify (struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, centrino_model->op_points);
+}
+
+/**
+ * centrino_setpolicy - set a new CPUFreq policy
+ * @policy: new policy
+ *
+ * Sets a new CPUFreq policy.
+ */
+static int centrino_target (struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int newstate = 0;
+ unsigned int msr, oldmsr, h;
+ struct cpufreq_freqs freqs;
+
+ if (centrino_model == NULL)
+ return -ENODEV;
+
+ if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq,
+ relation, &newstate))
+ return -EINVAL;
+
+ msr = centrino_model->op_points[newstate].index;
+ rdmsr(MSR_IA32_PERF_CTL, oldmsr, h);
+
+ if (msr == (oldmsr & 0xffff))
+ return 0;
+
+ /* Hm, old frequency can either be the last value we put in
+ PERF_CTL, or whatever it is now. The trouble is that TM2
+ can change it behind our back, which means we never get to
+ see the speed change. Reading back the current speed would
+ 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".
+
+ TODO: work out how the TCC interrupts work, and try to
+ catch the CPU changing things under us.
+ */
+ freqs.cpu = 0;
+ 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);
+
+ /* 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;
+}
+
+static struct cpufreq_driver centrino_driver = {
+ .name = "centrino", /* should be speedstep-centrino,
+ but there's a 16 char limit */
+ .init = centrino_cpu_init,
+ .verify = centrino_verify,
+ .target = centrino_target,
+ .owner = THIS_MODULE,
+};
+
+
+/**
+ * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
+ *
+ * Initializes the Enhanced SpeedStep support. Returns -ENODEV on
+ * unsupported devices, -ENOENT if there's no voltage table for this
+ * particular CPU model, -EINVAL on problems during initiatization,
+ * and zero on success.
+ *
+ * This is quite picky. Not only does the CPU have to advertise the
+ * "est" flag in the cpuid capability flags, we look for a specific
+ * CPU model and stepping, and we need to have the exact model name in
+ * our voltage tables. That is, be paranoid about not releasing
+ * someone's valuable magic smoke.
+ */
+static int __init centrino_init(void)
+{
+ struct cpuinfo_x86 *cpu = cpu_data;
+ const struct cpu_model *model;
+ unsigned l, h;
+
+ if (!cpu_has(cpu, X86_FEATURE_EST))
+ return -ENODEV;
+
+ /* Only Intel Pentium M stepping 5 for now - add new CPUs as
+ they appear after making sure they use PERF_CTL in the same
+ way. */
+ if (cpu->x86_vendor != X86_VENDOR_INTEL ||
+ cpu->x86 != 6 ||
+ cpu->x86_model != 9 ||
+ cpu->x86_mask != 5) {
+ printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
+ "send /proc/cpuinfo to " MAINTAINER "\n");
+ return -ENODEV;
+ }
+
+ /* 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))) {
+ printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
+ return -ENODEV;
+ }
+ }
+
+ for(model = models; model->model_name != NULL; model++)
+ if (strcmp(cpu->x86_model_id, model->model_name) == 0)
+ break;
+ if (model->model_name == NULL) {
+ printk(KERN_INFO PFX "no support for CPU model \"%s\": "
+ "send /proc/cpuinfo to " MAINTAINER "\n",
+ cpu->x86_model_id);
+ return -ENOENT;
+ }
+
+ centrino_model = model;
+
+ printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
+ model->model_name, model->max_freq);
+
+ return cpufreq_register_driver(&centrino_driver);
+}
+
+static void __exit centrino_exit(void)
+{
+ cpufreq_unregister_driver(&centrino_driver);
+}
+
+MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
+MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
+MODULE_LICENSE ("GPL");
+
+module_init(centrino_init);
+module_exit(centrino_exit);
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
index 65137016e293..65137016e293 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index 040e1f66ea48..34de8a5a0f22 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -70,6 +70,7 @@
#define X86_FEATURE_P4 (3*32+ 7) /* P4 */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 7c738dc96ae1..b89b597e960c 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -77,6 +77,9 @@
#define MSR_P6_EVNTSEL0 0x186
#define MSR_P6_EVNTSEL1 0x187
+#define MSR_IA32_PERF_STATUS 0x198
+#define MSR_IA32_PERF_CTL 0x199
+
#define MSR_IA32_THERM_CONTROL 0x19a
#define MSR_IA32_THERM_INTERRUPT 0x19b
#define MSR_IA32_THERM_STATUS 0x19c