summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/conf/NOTES7
-rw-r--r--sys/amd64/include/specialreg.h1
-rw-r--r--sys/conf/files.amd641
-rw-r--r--sys/conf/files.i3861
-rw-r--r--sys/dev/coretemp/coretemp.c268
-rw-r--r--sys/i386/conf/NOTES7
-rw-r--r--sys/i386/include/specialreg.h1
-rw-r--r--sys/modules/Makefile3
-rw-r--r--sys/modules/coretemp/Makefile8
9 files changed, 297 insertions, 0 deletions
diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index 5304bf9..f0208d9 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -446,6 +446,13 @@ device xrpu
#
device ichwd
+#
+# Temperature sensors:
+#
+# coretemp: on-die sensor on Intel Core and newer CPUs
+#
+device coretemp
+
#---------------------------------------------------------------------------
# ISDN4BSD
#
diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h
index 143026b..76297be3 100644
--- a/sys/amd64/include/specialreg.h
+++ b/sys/amd64/include/specialreg.h
@@ -179,6 +179,7 @@
#define MSR_BIOS_SIGN 0x08b
#define MSR_PERFCTR0 0x0c1
#define MSR_PERFCTR1 0x0c2
+#define MSR_IA32_EXT_CONFIG 0x0ee /* Undocumented. Core Solo/Duo only */
#define MSR_MTRRcap 0x0fe
#define MSR_BBL_CR_ADDR 0x116
#define MSR_BBL_CR_DECC 0x118
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 164c960..2a9a60a 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -145,6 +145,7 @@ dev/atkbdc/atkbdc.c optional atkbdc
dev/atkbdc/atkbdc_isa.c optional atkbdc isa
dev/atkbdc/atkbdc_subr.c optional atkbdc
dev/atkbdc/psm.c optional psm atkbdc
+dev/coretemp/coretemp.c optional coretemp
# There are no systems with isa slots, so all ed isa entries should go..
dev/ed/if_ed_3c503.c optional ed isa ed_3c503
dev/ed/if_ed_isa.c optional ed isa
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index 5653c10..fc47798 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -158,6 +158,7 @@ dev/ce/ceddk.c optional ce
dev/ce/if_ce.c optional ce
dev/ce/tau32-ddk.c optional ce
dev/cm/if_cm_isa.c optional cm isa
+dev/coretemp/coretemp.c optional coretemp
dev/cp/cpddk.c optional cp
dev/cp/if_cp.c optional cp
dev/ctau/ctau.c optional ctau
diff --git a/sys/dev/coretemp/coretemp.c b/sys/dev/coretemp/coretemp.c
new file mode 100644
index 0000000..e5b80ed
--- /dev/null
+++ b/sys/dev/coretemp/coretemp.c
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 2007 Rui Paulo <rpaulo@FreeBSD.org>
+ * 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.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Device driver for Intel's On Die thermal sensor via MSR.
+ * First introduced in Intel's Core line of processors.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h> /* for curthread */
+#include <sys/sched.h>
+
+#include <machine/specialreg.h>
+#include <machine/cpufunc.h>
+#include <machine/md_var.h>
+
+struct coretemp_softc {
+ device_t sc_dev;
+ int sc_tjmax;
+ struct sysctl_oid *sc_oid;
+};
+
+/*
+ * Device methods.
+ */
+static void coretemp_identify(driver_t *driver, device_t parent);
+static int coretemp_probe(device_t dev);
+static int coretemp_attach(device_t dev);
+static int coretemp_detach(device_t dev);
+
+static int coretemp_get_temp(device_t dev);
+static int coretemp_get_temp_sysctl(SYSCTL_HANDLER_ARGS);
+
+static device_method_t coretemp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, coretemp_identify),
+ DEVMETHOD(device_probe, coretemp_probe),
+ DEVMETHOD(device_attach, coretemp_attach),
+ DEVMETHOD(device_detach, coretemp_detach),
+
+ {0, 0}
+};
+
+static driver_t coretemp_driver = {
+ "coretemp",
+ coretemp_methods,
+ sizeof(struct coretemp_softc),
+};
+
+static devclass_t coretemp_devclass;
+DRIVER_MODULE(coretemp, cpu, coretemp_driver, coretemp_devclass, NULL, NULL);
+
+static void
+coretemp_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+ u_int regs[4];
+
+ /* Make sure we're not being doubly invoked. */
+ if (device_find_child(parent, "coretemp", -1) != NULL)
+ return;
+
+ /* Check that CPUID is supported and the vendor is Intel.*/
+ if (cpu_high == 0 || strcmp(cpu_vendor, "GenuineIntel"))
+ return;
+ /*
+ * CPUID 0x06 returns 1 if the processor has on-die thermal
+ * sensors. EBX[0:3] contains the number of sensors.
+ */
+ do_cpuid(0x06, regs);
+ if ((regs[0] & 0x1) != 1)
+ return;
+
+ /*
+ * We add a child for each CPU since settings must be performed
+ * on each CPU in the SMP case.
+ */
+ child = device_add_child(parent, "coretemp", -1);
+ if (child == NULL)
+ device_printf(parent, "add coretemp child failed\n");
+}
+
+static int
+coretemp_probe(device_t dev)
+{
+ if (resource_disabled("coretemp", 0))
+ return (ENXIO);
+
+ device_set_desc(dev, "CPU On-Die Thermal Sensors");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+coretemp_attach(device_t dev)
+{
+ struct coretemp_softc *sc = device_get_softc(dev);
+ device_t pdev;
+ uint64_t msr;
+ int cpu_model;
+ int cpu_mask;
+
+ pdev = device_get_parent(dev);
+
+ cpu_model = (cpu_id >> 4) & 15;
+ /* extended model */
+ cpu_model += ((cpu_id >> 16) & 0xf) << 4;
+ cpu_mask = cpu_id & 15;
+
+ /*
+ * Check for errata AE18.
+ * "Processor Digital Thermal Sensor (DTS) Readout stops
+ * updating upon returning from C3/C4 state."
+ *
+ * Adapted from the Linux coretemp driver.
+ */
+ if (cpu_model == 0xe && cpu_mask < 0xc) {
+ msr = rdmsr(MSR_BIOS_SIGN);
+ msr = msr >> 32;
+ if (msr < 0x39) {
+ device_printf(dev, "This processor behaves "
+ "erronously regarding to Intel errata "
+ "AE18.\nPlease update your BIOS or the "
+ "CPU microcode.\n");
+ return (ENXIO);
+ }
+ }
+ /*
+ * On some Core 2 CPUs, there's an undocumented MSR that
+ * can tell us if Tj(max) is 100 or 85.
+ *
+ * The if-clause for CPUs having the MSR_IA32_EXT_CONFIG was adapted
+ * from the Linux coretemp driver.
+ */
+ if ((cpu_model == 0xf && cpu_mask > 3) || cpu_model == 0xe) {
+ msr = rdmsr(MSR_IA32_EXT_CONFIG);
+ if ((msr >> 30) & 0x1)
+ sc->sc_tjmax = 85;
+ } else
+ sc->sc_tjmax = 100;
+
+ /*
+ * Add the "temperature" MIB to dev.cpu.N.
+ */
+ sc->sc_oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(pdev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)),
+ OID_AUTO, "temperature",
+ CTLTYPE_INT | CTLFLAG_RD,
+ dev, 0, coretemp_get_temp_sysctl, "I",
+ "Current temperature in degC");
+
+ return (0);
+}
+
+static int
+coretemp_detach(device_t dev)
+{
+ struct coretemp_softc *sc = device_get_softc(dev);
+
+ sysctl_remove_oid(sc->sc_oid, 1, 0);
+
+ return (0);
+}
+
+
+static int
+coretemp_get_temp(device_t dev)
+{
+ uint64_t temp;
+ int cpu = device_get_unit(dev);
+ struct coretemp_softc *sc = device_get_softc(dev);
+
+ thread_lock(curthread);
+ sched_bind(curthread, cpu);
+ thread_unlock(curthread);
+
+ /*
+ * The digital temperature reading is located at bit 16
+ * of MSR_THERM_STATUS.
+ *
+ * There is a bit on that MSR that indicates whether the
+ * temperature is valid or not.
+ *
+ * The temperature is computed by subtracting the temperature
+ * reading by Tj(max).
+ */
+ temp = rdmsr(MSR_THERM_STATUS);
+
+ /*
+ * Check for Thermal Status and Thermal Status Log.
+ */
+ if ((temp & 0x3) == 0x3)
+ device_printf(dev, "PROCHOT asserted\n");
+
+ /*
+ * Check for Critical Temperature Status and Critical
+ * Temperature Log.
+ *
+ * If we reach a critical level, allow devctl(4) to catch this
+ * and shutdown the system.
+ */
+ if (((temp >> 4) & 0x3) == 0x3) {
+ device_printf(dev, "Critical Temperature detected.\n"
+ "Advising system shutdown.\n");
+ devctl_notify("CPU", "coretemp", "temperature",
+ "notify=0x1");
+ }
+
+ /*
+ * Bit 31 contains "Reading valid"
+ */
+ if (((temp >> 31) & 0x1) == 1) {
+ /*
+ * Starting on bit 16 and ending on bit 22.
+ */
+ temp = sc->sc_tjmax - ((temp >> 16) & 0x7f);
+ return ((int) temp);
+ }
+
+ return (-1);
+}
+
+static int
+coretemp_get_temp_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ device_t dev = (device_t) arg1;
+ int temp;
+
+ temp = coretemp_get_temp(dev);
+
+ return (sysctl_handle_int(oidp, &temp, 0, req));
+}
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index bbbea1a..10c99f3 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -853,6 +853,13 @@ hint.pcf.0.irq="5"
#
device ichwd
+#
+# Temperature sensors:
+#
+# coretemp: on-die sensor on Intel Core and newer CPUs
+#
+device coretemp
+
#---------------------------------------------------------------------------
# ISDN4BSD
#
diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h
index a210bc4..24b686b 100644
--- a/sys/i386/include/specialreg.h
+++ b/sys/i386/include/specialreg.h
@@ -176,6 +176,7 @@
#define MSR_BIOS_SIGN 0x08b
#define MSR_PERFCTR0 0x0c1
#define MSR_PERFCTR1 0x0c2
+#define MSR_IA32_EXT_CONFIG 0x0ee /* Undocumented. Core Solo/Duo only */
#define MSR_MTRRcap 0x0fe
#define MSR_BBL_CR_ADDR 0x116
#define MSR_BBL_CR_DECC 0x118
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 9ca5073..79aacc3 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -54,6 +54,7 @@ SUBDIR= ${_3dfx} \
coda \
coda5 \
${_coff} \
+ ${_coretemp} \
${_cp} \
${_cpufreq} \
${_crypto} \
@@ -370,6 +371,7 @@ _cardbus= cardbus
_cbb= cbb
_ce= ce
_coff= coff
+_coretemp= coretemp
_cp= cp
_cpufreq= cpufreq
_cs= cs
@@ -489,6 +491,7 @@ _ath_rate_sample=ath_rate_sample
_cardbus= cardbus
_cbb= cbb
_ciss= ciss
+_coretemp= coretemp
_cpufreq= cpufreq
_digi= digi
_drm= drm
diff --git a/sys/modules/coretemp/Makefile b/sys/modules/coretemp/Makefile
new file mode 100644
index 0000000..dd540ba
--- /dev/null
+++ b/sys/modules/coretemp/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/coretemp
+
+KMOD= coretemp
+SRCS= coretemp.c bus_if.h device_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud