Convert coretemp(4) to the hardware sensors framework and

make sure to never call sched_bind() for uninitialised CPUs.

Submitted by:	Constantine A. Murenin <cnst@FreeBSD.org>
Sponsored by:	Google Summer of Code 2007 (GSoC2007/cnst-sensors)
Mentored by:	syrinx
Tested by:	many
OKed by:	kensmith
This commit is contained in:
Alexander Leidinger 2007-10-14 10:59:44 +00:00
parent 989500bf1a
commit 5c6b7871e9
2 changed files with 59 additions and 40 deletions

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd August 23, 2007
.Dd September 13, 2007
.Dt CORETEMP 4
.Os
.Sh NAME
@ -51,12 +51,20 @@ The
driver provides support for the on-die digital thermal sensor present
in Intel Core and newer CPUs.
.Pp
The
.Nm
driver reports each core's temperature through a sysctl node in the
corresponding CPU device's sysctl tree, named
.Va dev.cpu.%d.temperature .
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

View File

@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/sensors.h>
#include <sys/proc.h> /* for curthread */
#include <sys/sched.h>
@ -50,10 +50,13 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/md_var.h>
extern int smp_cpus;
struct coretemp_softc {
device_t sc_dev;
int sc_tjmax;
struct sysctl_oid *sc_oid;
struct ksensordev sc_sensordev;
struct ksensor sc_sensor;
device_t sc_dev;
int sc_tjmax;
};
/*
@ -65,7 +68,7 @@ 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 void coretemp_refresh(void *arg);
static device_method_t coretemp_methods[] = {
/* Device interface */
@ -174,14 +177,17 @@ coretemp_attach(device_t dev)
}
/*
* Add the "temperature" MIB to dev.cpu.N.
* Add hw.sensors.cpuN.temp0 MIB.
*/
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");
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);
return (0);
}
@ -191,7 +197,8 @@ coretemp_detach(device_t dev)
{
struct coretemp_softc *sc = device_get_softc(dev);
sysctl_remove_oid(sc->sc_oid, 1, 0);
sensordev_deinstall(&sc->sc_sensordev);
sensor_task_unregister(sc);
return (0);
}
@ -206,25 +213,21 @@ coretemp_get_temp(device_t dev)
struct coretemp_softc *sc = device_get_softc(dev);
char stemp[16];
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).
* 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.
*/
msr = rdmsr(MSR_THERM_STATUS);
thread_lock(curthread);
sched_unbind(curthread);
thread_unlock(curthread);
if (smp_cpus > 1) {
thread_lock(curthread);
sched_bind(curthread, cpu);
msr = rdmsr(MSR_THERM_STATUS);
sched_unbind(curthread);
thread_unlock(curthread);
} else if (cpu != 0)
return (-1);
else
msr = rdmsr(MSR_THERM_STATUS);
/*
* Check for Thermal Status and Thermal Status Log.
@ -264,13 +267,21 @@ coretemp_get_temp(device_t dev)
return (temp);
}
static int
coretemp_get_temp_sysctl(SYSCTL_HANDLER_ARGS)
static void
coretemp_refresh(void *arg)
{
device_t dev = (device_t) arg1;
struct coretemp_softc *sc = arg;
device_t dev = sc->sc_dev;
struct ksensor *s = &sc->sc_sensor;
int temp;
temp = coretemp_get_temp(dev);
return (sysctl_handle_int(oidp, &temp, 0, req));
if (temp == -1) {
s->flags |= SENSOR_FINVALID;
s->value = 0;
} else {
s->flags &= ~SENSOR_FINVALID;
s->value = temp * 1000000 + 273150000;
}
}