diff options
-rw-r--r-- | sys/arch/amd64/amd64/est.c | 232 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/identcpu.c | 59 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 5 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 9 | ||||
-rw-r--r-- | sys/arch/amd64/include/specialreg.h | 15 |
5 files changed, 315 insertions, 5 deletions
diff --git a/sys/arch/amd64/amd64/est.c b/sys/arch/amd64/amd64/est.c new file mode 100644 index 00000000000..60d1ff0be65 --- /dev/null +++ b/sys/arch/amd64/amd64/est.c @@ -0,0 +1,232 @@ +/* $OpenBSD: est.c,v 1.1 2007/05/29 06:31:44 tedu Exp $ */ +/* + * Copyright (c) 2003 Michael Eriksson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * This is a driver for Intel's Enhanced SpeedStep, as implemented in + * Pentium M processors. + * + * Reference documentation: + * + * - IA-32 Intel Architecture Software Developer's Manual, Volume 3: + * System Programming Guide. + * Section 13.14, Enhanced Intel SpeedStep technology. + * Table B-2, MSRs in Pentium M Processors. + * http://www.intel.com/design/pentium4/manuals/245472.htm + * + * - Intel Pentium M Processor Datasheet. + * Table 5, Voltage and Current Specifications. + * http://www.intel.com/design/mobile/datashts/252612.htm + * + * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet + * Table 3-4, Voltage and Current Specifications. + * http://www.intel.com/design/mobile/datashts/302189.htm + * + * - Linux cpufreq patches, speedstep-centrino.c. + * Encoding of MSR_PERF_CTL and MSR_PERF_STATUS. + * http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysctl.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/specialreg.h> + +#define CPUVENDOR_INTEL 0 +#define CPUVENDOR_VIA 8 + + +/* Convert MHz and mV into IDs for passing to the MSR. */ +#define ID16(MHz, mV, bus_clk) \ + ((((MHz * 100 + 50) / bus_clk) << 8) | ((mV ? mV - 700 : 0) >> 4)) + +/* Possible bus speeds (multiplied by 100 for rounding) */ +#define BUS100 10000 +#define BUS133 13333 +#define BUS166 16666 +#define BUS200 20000 + +#define MSR2MHZ(msr, bus) \ + (((((int) (msr) >> 8) & 0xff) * (bus) + 50) / 100) +#define MSR2MV(msr) \ + (((int) (msr) & 0xff) * 16 + 700) + +struct fqlist { + int vendor: 5; + unsigned bus_clk : 1; + unsigned n : 5; + const u_int16_t *table; +}; + +static const struct fqlist *est_fqlist; + +static u_int16_t fake_table[3]; +static struct fqlist fake_fqlist; + +extern int setperf_prio; +extern int perflevel; + +int bus_clock; + +void +est_init(struct cpu_info *ci) +{ + const char *cpu_device = ci->ci_dev->dv_xname; + int vendor = -1; + int i, mhz, mv, low, high, bus; + u_int64_t msr; + u_int16_t idhi, idlo, cur; + u_int8_t crhi, crlo, crcur; + + if (setperf_prio > 3) + return; + msr = rdmsr(MSR_FSB_FREQ); + bus = msr & 0x07; + switch (bus) { + case 5: + bus_clock = 10000; + break; + case 1: + bus_clock = 13333; + break; + case 3: + bus_clock = 16666; + break; + case 0: + bus_clock = 26666; + break; + case 4: + bus_clock = 33333; + break; + default: + printf("unknown bus %d\n", bus); + } + + if (bus_clock == 0) { + printf("%s: EST: unknown system bus clock\n", cpu_device); + return; + } + + msr = rdmsr(MSR_PERF_STATUS); + idhi = (msr >> 32) & 0xffff; + idlo = (msr >> 48) & 0xffff; + cur = msr & 0xffff; + crhi = (idhi >> 8) & 0xff; + crlo = (idlo >> 8) & 0xff; + crcur = (cur >> 8) & 0xff; + if (crlo == 0 || crhi == crlo) { + /* + * Don't complain about these cases, and silently disable EST: + * - A lowest clock ratio of 0, which seems to happen on all + * Pentium 4's that report EST. + * - An equal highest and lowest clock ratio, which happens on + * at least the Core 2 Duo X6800, maybe on newer models too. + */ + return; + } + if (crhi == 0 || crcur == 0 || crlo > crhi || + crcur < crlo || crcur > crhi) { + /* + * Do complain about other weirdness, because we first want to + * know about it, before we decide what to do with it. + */ + printf("%s: EST: strange msr value 0x%016llx\n", + cpu_device, msr); + return; + } + if (est_fqlist == NULL) { + printf("%s: unknown Enhanced SpeedStep CPU, msr 0x%016llx\n", + cpu_device, msr); + + /* + * Generate a fake table with the power states we know. + */ + fake_table[0] = idhi; + if (cur == idhi || cur == idlo) { + printf("%s: using only highest and lowest power " + "states\n", cpu_device); + + fake_table[1] = idlo; + fake_fqlist.n = 2; + } else { + printf("%s: using only highest, current and lowest " + "power states\n", cpu_device); + + fake_table[1] = cur; + fake_table[2] = idlo; + fake_fqlist.n = 3; + } + fake_fqlist.vendor = vendor; + fake_fqlist.table = fake_table; + est_fqlist = &fake_fqlist; + } + + mhz = MSR2MHZ(cur, bus_clock); + mv = MSR2MV(cur); + printf("%s: Enhanced SpeedStep %d MHz (%d mV)", cpu_device, mhz, mv); + + low = MSR2MHZ(est_fqlist->table[est_fqlist->n - 1], bus_clock); + high = MSR2MHZ(est_fqlist->table[0], bus_clock); + perflevel = (mhz - low) * 100 / (high - low); + + /* + * OK, tell the user the available frequencies. + */ + printf(": speeds: "); + for (i = 0; i < est_fqlist->n; i++) + printf("%d%s", MSR2MHZ(est_fqlist->table[i], bus_clock), + i < est_fqlist->n - 1 ? ", " : " MHz\n"); + + cpu_setperf = est_setperf; + setperf_prio = 3; +} + +void +est_setperf(int level) +{ + int i; + uint64_t msr; + + if (est_fqlist == NULL) + return; + + i = ((level * est_fqlist->n) + 1) / 101; + if (i >= est_fqlist->n) + i = est_fqlist->n - 1; + i = est_fqlist->n - 1 - i; + + msr = rdmsr(MSR_PERF_CTL); + msr &= ~0xffffULL; + msr |= est_fqlist->table[i]; + wrmsr(MSR_PERF_CTL, msr); + cpuspeed = MSR2MHZ(est_fqlist->table[i], bus_clock); +} diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index 5d6695e7e2b..0dbf1949607 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.12 2007/05/06 03:37:08 gwk Exp $ */ +/* $OpenBSD: identcpu.c,v 1.13 2007/05/29 06:31:44 tedu Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -109,6 +109,44 @@ cpu_amd64speed(int *freq) return (0); } +#ifndef SMALL_KERNEL +void intelcore_update_sensor(void *args); +/* + * Temperature read on the CPU is relative to the maximum + * temperature supported by the CPU, Tj(Max). + * Poorly documented, refer to: + * http://softwarecommunity.intel.com/isn/Community/ + * en-US/forums/thread/30228638.aspx + * Basically, depending on a bit in one msr, the max is either 85 or 100. + * Then we subtract the temperature portion of thermal status from + * max to get current temperature. + */ +void +intelcore_update_sensor(void *args) +{ + struct cpu_info *ci = (struct cpu_info *) args; + u_int64_t msr; + int max = 100; + + if (rdmsr(MSR_TEMPERATURE_TARGET) & MSR_TEMPERATURE_TARGET_LOW_BIT) + max = 85; + + msr = rdmsr(MSR_THERM_STATUS); + if (msr & MSR_THERM_STATUS_VALID_BIT) { + ci->ci_sensor.value = max - MSR_THERM_STATUS_TEMP(msr); + /* micro degress */ + ci->ci_sensor.value *= 1000000; + /* kelvin */ + ci->ci_sensor.value += 273150000; + ci->ci_sensor.flags &= ~SENSOR_FINVALID; + } else { + ci->ci_sensor.value = 0; + ci->ci_sensor.flags |= SENSOR_FINVALID; + } +} + +#endif + void (*setperf_setup)(struct cpu_info *); void @@ -183,6 +221,7 @@ identifycpu(struct cpu_info *ci) x86_print_cacheinfo(ci); +#ifndef SMALL_KERNEL if (pnfeatset > 0x80000007) { CPUID(0x80000007, dummy, dummy, dummy, pnfeatset); @@ -192,6 +231,24 @@ identifycpu(struct cpu_info *ci) } } + if (!strncmp(cpu_model, "Intel", 5)) { + if (cpu_ecxfeature & CPUIDECX_EST) { + setperf_setup = est_init; + } + CPUID(0x06, val, dummy, dummy, dummy); + if (val & 0x1) { + strlcpy(ci->ci_sensordev.xname, ci->ci_dev->dv_xname, + sizeof(ci->ci_sensordev.xname)); + ci->ci_sensor.type = SENSOR_TEMP; + sensor_task_register(ci, intelcore_update_sensor, 5); + sensor_attach(&ci->ci_sensordev, &ci->ci_sensor); + sensordev_install(&ci->ci_sensordev); + } + } + +#endif + + /* AuthenticAMD: h t u A i t n e */ if (vendor[0] == 0x68747541 && vendor[1] == 0x69746e65 && vendor[2] == 0x444d4163) /* DMAc */ diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index c59f4bad515..626b98299eb 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.29 2007/05/28 02:13:44 krw Exp $ +# $OpenBSD: files.amd64,v 1.30 2007/05/29 06:31:44 tedu Exp $ maxpartitions 16 maxusers 2 16 128 @@ -58,7 +58,8 @@ file arch/amd64/amd64/kgdb_machdep.c kgdb # Basic clock - required file arch/amd64/isa/clock.c -file arch/amd64/amd64/powernow-k8.c +file arch/amd64/amd64/powernow-k8.c !small_kernel +file arch/amd64/amd64/est.c !small_kernel include "dev/mii/files.mii" diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h index ef0bce98095..c99ec07058f 100644 --- a/sys/arch/amd64/include/cpu.h +++ b/sys/arch/amd64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.29 2007/05/10 17:59:24 deraadt Exp $ */ +/* $OpenBSD: cpu.h,v 1.30 2007/05/29 06:31:44 tedu Exp $ */ /* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ /*- @@ -55,6 +55,7 @@ #include <sys/device.h> #include <sys/lock.h> #include <sys/sched.h> +#include <sys/sensors.h> struct cpu_info { struct device *ci_dev; @@ -127,6 +128,9 @@ struct cpu_info { struct x86_64_tss ci_doubleflt_tss; char *ci_doubleflt_stack; + + struct ksensordev ci_sensordev; + struct ksensor ci_sensor; }; #define CPUF_BSP 0x0001 /* CPU is the original BSP */ @@ -308,6 +312,9 @@ void x86_bus_space_mallocok(void); void k8_powernow_init(struct cpu_info *); void k8_powernow_setperf(int); +void est_init(struct cpu_info *); +void est_setperf(int); + #ifdef MULTIPROCESSOR /* mp_setperf.c */ void mp_setperf_init(void); diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index 6b24513bef4..cdc85739ed6 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.8 2007/04/27 01:57:16 dlg Exp $ */ +/* $OpenBSD: specialreg.h,v 1.9 2007/05/29 06:31:44 tedu Exp $ */ /* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ /* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ @@ -173,6 +173,7 @@ #define MSR_BIOS_SIGN 0x08b #define MSR_PERFCTR0 0x0c1 #define MSR_PERFCTR1 0x0c2 +#define MSR_FSB_FREQ 0x0cd /* Core Duo/Solo only */ #define MSR_MTRRcap 0x0fe #define MSR_BBL_CR_ADDR 0x116 /* PII+ only */ #define MSR_BBL_CR_DECC 0x118 /* PII+ only */ @@ -188,6 +189,14 @@ #define MSR_MCG_CTL 0x17b #define MSR_EVNTSEL0 0x186 #define MSR_EVNTSEL1 0x187 +#define MSR_PERF_STATUS 0x198 /* Pentium M */ +#define MSR_PERF_CTL 0x199 /* Pentium M */ +#define MSR_THERM_CONTROL 0x19a +#define MSR_THERM_INTERRUPT 0x19b +#define MSR_THERM_STATUS 0x19c +#define MSR_THERM_STATUS_VALID_BIT 0x80000000 +#define MSR_THERM_STATUS_TEMP(msr) ((msr >> 16) & 0x7f) +#define MSR_THERM2_CTL 0x19d /* Pentium M */ #define MSR_DEBUGCTLMSR 0x1d9 #define MSR_LASTBRANCHFROMIP 0x1db #define MSR_LASTBRANCHTOIP 0x1dc @@ -620,3 +629,7 @@ #define K7_BP1_MATCH 0xdd #define K7_BP2_MATCH 0xde #define K7_BP3_MATCH 0xdf + +/* not documented anywhere, see intelcore_update_sensor() */ +#define MSR_TEMPERATURE_TARGET 0xee +#define MSR_TEMPERATURE_TARGET_LOW_BIT 0x40000000 |