Index: amd64/include/specialreg.h =================================================================== RCS file: /home/ncvs/src/sys/amd64/include/specialreg.h,v retrieving revision 1.39 diff -u -r1.39 specialreg.h --- amd64/include/specialreg.h 31 May 2007 11:26:44 -0000 1.39 +++ amd64/include/specialreg.h 12 Aug 2007 09:53:56 -0000 @@ -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 Index: conf/files.amd64 =================================================================== RCS file: /home/ncvs/src/sys/conf/files.amd64,v retrieving revision 1.106 diff -u -r1.106 files.amd64 --- conf/files.amd64 5 Jul 2007 06:12:40 -0000 1.106 +++ conf/files.amd64 9 Aug 2007 20:56:09 -0000 @@ -145,6 +145,7 @@ 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 Index: conf/files.i386 =================================================================== RCS file: /home/ncvs/src/sys/conf/files.i386,v retrieving revision 1.579 diff -u -r1.579 files.i386 --- conf/files.i386 5 Jul 2007 06:12:40 -0000 1.579 +++ conf/files.i386 9 Aug 2007 20:55:56 -0000 @@ -158,6 +158,7 @@ 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 Index: dev/coretemp/coretemp.c =================================================================== RCS file: dev/coretemp/coretemp.c diff -N dev/coretemp/coretemp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/coretemp/coretemp.c 12 Aug 2007 09:51:25 -0000 @@ -0,0 +1,268 @@ +/*- + * Copyright (c) 2007 Rui Paulo + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for curthread */ +#include + +#include +#include +#include + +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)); +} Index: i386/include/specialreg.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/specialreg.h,v retrieving revision 1.41 diff -u -r1.41 specialreg.h --- i386/include/specialreg.h 31 May 2007 11:26:45 -0000 1.41 +++ i386/include/specialreg.h 12 Aug 2007 09:53:56 -0000 @@ -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 Index: modules/Makefile =================================================================== RCS file: /home/ncvs/src/sys/modules/Makefile,v retrieving revision 1.538 diff -u -r1.538 Makefile --- modules/Makefile 24 Jul 2007 16:58:18 -0000 1.538 +++ modules/Makefile 9 Aug 2007 22:48:03 -0000 @@ -54,6 +54,7 @@ coda \ coda5 \ ${_coff} \ + ${_coretemp} \ ${_cp} \ ${_cpufreq} \ ${_crypto} \ @@ -370,6 +371,7 @@ _cbb= cbb _ce= ce _coff= coff +_coretemp= coretemp _cp= cp _cpufreq= cpufreq _cs= cs @@ -489,6 +491,7 @@ _cardbus= cardbus _cbb= cbb _ciss= ciss +_coretemp= coretemp _cpufreq= cpufreq _digi= digi _drm= drm Index: modules/coretemp/Makefile =================================================================== RCS file: modules/coretemp/Makefile diff -N modules/coretemp/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/coretemp/Makefile 12 Aug 2007 09:51:51 -0000 @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/coretemp + +KMOD= coretemp +SRCS= coretemp.c bus_if.h device_if.h + +.include