From: Hasso Tepper Date: Tue, 2 Oct 2007 13:16:42 +0000 (+0000) Subject: Coretemp(4) driver for Intel Core on-die digital thermal sensor with patch X-Git-Tag: v2.0.1~2095 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/3a514b87b9eaeb16e4d17f9960d1600cef20c16d Coretemp(4) driver for Intel Core on-die digital thermal sensor with patch from Constantine A. Murenin to make it use hw.sensors framework. Obtained-from: FreeBSD with modifications from Constantine A. Murenin --- diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index b0427ac10a..33cd77fe2b 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,6 +1,6 @@ # @(#)Makefile 8.1 (Berkeley) 6/18/93 # $FreeBSD: src/share/man/man4/Makefile,v 1.83.2.66 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/share/man/man4/Makefile,v 1.67 2007/09/16 18:26:18 swildner Exp $ +# $DragonFly: src/share/man/man4/Makefile,v 1.68 2007/10/02 13:16:42 hasso Exp $ MAN= aac.4 \ acpi.4 \ @@ -41,6 +41,7 @@ MAN= aac.4 \ cd.4 \ ch.4 \ ciss.4 \ + coretemp.4 \ crypto.4 \ csa.4 \ cue.4 \ diff --git a/share/man/man4/coretemp.4 b/share/man/man4/coretemp.4 new file mode 100644 index 0000000000..be9c8f43bd --- /dev/null +++ b/share/man/man4/coretemp.4 @@ -0,0 +1,82 @@ +.\"- +.\" Copyright (c) 2007 Dag-Erling Coïdan Smørgrav +.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: src/share/man/man4/coretemp.4,v 1.1 2007/08/23 20:05:09 des Exp $ +.\" $DragonFly: src/share/man/man4/coretemp.4,v 1.1 2007/10/02 13:16:42 hasso Exp $ +.\" +.Dd September 13, 2007 +.Dt CORETEMP 4 +.Os +.Sh NAME +.Nm coretemp +.Nd device driver for Intel Core on-die digital thermal sensor +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device coretemp" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +coretemp_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for the on-die digital thermal sensor present +in Intel Core and newer CPUs. +The values are exposed through the +.Va HW_SENSORS +.Xr sysctl 3 +tree. +For example: +.Bd -literal -offset indent +%sysctl hw.sensors +hw.sensors.cpu0.temp0: 28.00 degC +hw.sensors.cpu1.temp0: 29.00 degC +.Ed +.Sh SEE ALSO +.Xr systat 1 , +.Xr sysctl 3 , +.Xr sensorsd 8 , +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 7.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Rui Paulo Aq rpaulo@FreeBSD.org +as part of a Google Summer of Code project. +This manual page was written by +.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . diff --git a/sys/conf/files b/sys/conf/files index 9054252554..01c7d1635b 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,5 +1,5 @@ # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $ -# $DragonFly: src/sys/conf/files,v 1.182 2007/10/02 12:57:00 hasso Exp $ +# $DragonFly: src/sys/conf/files,v 1.183 2007/10/02 13:16:42 hasso Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -251,6 +251,7 @@ dev/atm/hfa/fore_vcm.c optional hfa dev/netif/ie/if_ie.c optional ie isa dev/powermng/ichsmb/ichsmb.c optional ichsmb dev/powermng/ichsmb/ichsmb_pci.c optional ichsmb pci +dev/powermng/coretemp/coretemp.c optional coretemp dev/raid/ida/ida.c optional ida dev/raid/ida/ida_disk.c optional ida dev/raid/ida/ida_eisa.c optional ida eisa diff --git a/sys/config/LINT b/sys/config/LINT index a839da1a18..d167921438 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -3,7 +3,7 @@ # as much of the source tree as it can. # # $FreeBSD: src/sys/i386/conf/LINT,v 1.749.2.144 2003/06/04 17:56:59 sam Exp $ -# $DragonFly: src/sys/config/LINT,v 1.131 2007/09/02 13:27:23 sephe Exp $ +# $DragonFly: src/sys/config/LINT,v 1.132 2007/10/02 13:16:42 hasso Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -2068,6 +2068,9 @@ device iicsmb # smb over i2c bridge device pcf0 at isa? port 0x320 irq 5 +# Intel Core and newer CPUs on-die digital thermal sensor support +device coretemp + #--------------------------------------------------------------------------- # ISDN4BSD # diff --git a/sys/cpu/i386/include/specialreg.h b/sys/cpu/i386/include/specialreg.h index 059058ac02..e0207ec5f4 100644 --- a/sys/cpu/i386/include/specialreg.h +++ b/sys/cpu/i386/include/specialreg.h @@ -32,7 +32,7 @@ * * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91 * $FreeBSD: src/sys/i386/include/specialreg.h,v 1.19.2.3 2003/01/22 17:24:28 jhb Exp $ - * $DragonFly: src/sys/cpu/i386/include/specialreg.h,v 1.8 2007/01/12 23:12:59 tgen Exp $ + * $DragonFly: src/sys/cpu/i386/include/specialreg.h,v 1.9 2007/10/02 13:16:42 hasso Exp $ */ #ifndef _CPU_SPECIALREG_H_ @@ -142,6 +142,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_MCG_CAP 0x179 #define MSR_MCG_STATUS 0x17a diff --git a/sys/dev/powermng/Makefile b/sys/dev/powermng/Makefile index a6f73b47b6..05746ce9c3 100644 --- a/sys/dev/powermng/Makefile +++ b/sys/dev/powermng/Makefile @@ -1,6 +1,6 @@ -# $DragonFly: src/sys/dev/powermng/Makefile,v 1.1 2003/08/15 08:32:31 dillon Exp $ +# $DragonFly: src/sys/dev/powermng/Makefile,v 1.2 2007/10/02 13:16:42 hasso Exp $ # -SUBDIR= +SUBDIR= coretemp .include diff --git a/sys/dev/powermng/coretemp/Makefile b/sys/dev/powermng/coretemp/Makefile new file mode 100644 index 0000000000..a72c216557 --- /dev/null +++ b/sys/dev/powermng/coretemp/Makefile @@ -0,0 +1,6 @@ +# $DragonFly: src/sys/dev/powermng/coretemp/Makefile,v 1.1 2007/10/02 13:16:42 hasso Exp $ + +KMOD= coretemp +SRCS= coretemp.c bus_if.h device_if.h + +.include diff --git a/sys/dev/powermng/coretemp/coretemp.c b/sys/dev/powermng/coretemp/coretemp.c new file mode 100644 index 0000000000..c9de4cedce --- /dev/null +++ b/sys/dev/powermng/coretemp/coretemp.c @@ -0,0 +1,291 @@ +/* + * 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: src/sys/dev/coretemp/coretemp.c,v 1.2 2007/08/23 10:53:03 des Exp $ + * $DragonFly: src/sys/dev/powermng/coretemp/coretemp.c,v 1.1 2007/10/02 13:16:42 hasso Exp $ + */ + +/* + * Device driver for Intel's On Die thermal sensor via MSR. + * First introduced in Intel's Core line of processors. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for curthread */ +#include + +#include +#include +#include + +static struct spinlock coretemp_lock; + +struct coretemp_softc { + struct ksensordev sc_sensordev; + struct ksensor sc_sensor; + device_t sc_dev; + int sc_tjmax; +}; + +/* + * 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 void coretemp_refresh(void *arg); + +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; + + sc->sc_dev = dev; + 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, "not supported (Intel errata " + "AE18), try updating your BIOS\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. + */ + sc->sc_tjmax = 100; + if ((cpu_model == 0xf && cpu_mask >= 2) || cpu_model == 0xe) { + msr = rdmsr(MSR_IA32_EXT_CONFIG); + if (msr & (1 << 30)) + sc->sc_tjmax = 85; + } + + /* + * Add hw.sensors.cpuN.temp0 MIB. + */ + strlcpy(sc->sc_sensordev.xname, device_get_nameunit(pdev), + sizeof(sc->sc_sensordev.xname)); + sc->sc_sensor.type = SENSOR_TEMP; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); + if (sensor_task_register(sc, coretemp_refresh, 2)) { + device_printf(dev, "unable to register update task\n"); + return (ENXIO); + } + sensordev_install(&sc->sc_sensordev); + spin_init(&coretemp_lock); + + return (0); +} + +static int +coretemp_detach(device_t dev) +{ + struct coretemp_softc *sc = device_get_softc(dev); + + spin_lock_wr(&coretemp_lock); + sensordev_deinstall(&sc->sc_sensordev); + sensor_task_unregister(sc); + spin_unlock_wr(&coretemp_lock); + spin_uninit(&coretemp_lock); + + return (0); +} + + +static int +coretemp_get_temp(device_t dev) +{ + uint64_t msr; + int temp; + int cpu = device_get_unit(dev); + struct coretemp_softc *sc = device_get_softc(dev); + char stemp[16]; + + /* + * Bind to specific CPU to read the correct temperature. + * If not all CPUs are initialised, then only read from + * cpu0, returning -1 on all other CPUs. + */ + if (ncpus > 1) { + spin_lock_rd(&coretemp_lock); + msr = rdmsr(MSR_THERM_STATUS); + spin_unlock_rd(&coretemp_lock); + } else if (cpu != 0) + return (-1); + else + msr = rdmsr(MSR_THERM_STATUS); + + /* + * Check for Thermal Status and Thermal Status Log. + */ + if ((msr & 0x3) == 0x3) + device_printf(dev, "PROCHOT asserted\n"); + + /* + * Bit 31 contains "Reading valid" + */ + if (((msr >> 31) & 0x1) == 1) { + /* + * Starting on bit 16 and ending on bit 22. + */ + temp = sc->sc_tjmax - ((msr >> 16) & 0x7f); + } else + temp = -1; + + /* + * Check for Critical Temperature Status and Critical + * Temperature Log. + * It doesn't really matter if the current temperature is + * invalid because the "Critical Temperature Log" bit will + * tell us if the Critical Temperature has been reached in + * past. It's not directly related to the current temperature. + * + * If we reach a critical level, allow devctl(4) to catch this + * and shutdown the system. + */ + if (((msr >> 4) & 0x3) == 0x3) { + device_printf(dev, "critical temperature detected, " + "suggest system shutdown\n"); + ksnprintf(stemp, sizeof(stemp), "%d", temp); +#if 0 + devctl_notify("coretemp", "Thermal", stemp, "notify=0xcc"); +#endif + } + + return (temp); +} + +static void +coretemp_refresh(void *arg) +{ + struct coretemp_softc *sc = arg; + device_t dev = sc->sc_dev; + struct ksensor *s = &sc->sc_sensor; + int temp; + + temp = coretemp_get_temp(dev); + + if (temp == -1) { + s->flags |= SENSOR_FINVALID; + s->value = 0; + } else { + s->flags &= ~SENSOR_FINVALID; + s->value = temp * 1000000 + 273150000; + } +}