summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/amd64/amd64/est.c232
-rw-r--r--sys/arch/amd64/amd64/identcpu.c59
-rw-r--r--sys/arch/amd64/conf/files.amd645
-rw-r--r--sys/arch/amd64/include/cpu.h9
-rw-r--r--sys/arch/amd64/include/specialreg.h15
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