mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-30 16:51:41 +00:00
Add a driver for the on-die digital thermal sensor found on Intel Core
and newer CPUs (including Core 2 and Core / Core 2 based Xeons). The driver attaches to each cpu device and creates a sysctl node in that device's sysctl context (dev.cpu.N.temperature). When invoked, the handler binds to the appropriate CPU to ensure a correct reading. Submitted by: Rui Paulo <rpaulo@fnop.net> Sponsored by: Google Summer of Code 2007 Tested by: des, marcus, Constantine A. Murenin, Ian FREISLICH Approved by: re (kensmith) MFC after: 3 weeks
This commit is contained in:
parent
2b33e8c7ed
commit
83d18f2283
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171854
@ -446,6 +446,13 @@ device xrpu
|
||||
#
|
||||
device ichwd
|
||||
|
||||
#
|
||||
# Temperature sensors:
|
||||
#
|
||||
# coretemp: on-die sensor on Intel Core and newer CPUs
|
||||
#
|
||||
device coretemp
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# ISDN4BSD
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
268
sys/dev/coretemp/coretemp.c
Normal file
268
sys/dev/coretemp/coretemp.c
Normal file
@ -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));
|
||||
}
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
8
sys/modules/coretemp/Makefile
Normal file
8
sys/modules/coretemp/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../dev/coretemp
|
||||
|
||||
KMOD= coretemp
|
||||
SRCS= coretemp.c bus_if.h device_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user