summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile4
-rw-r--r--share/man/man4/itherm.468
-rw-r--r--sys/arch/amd64/conf/GENERIC3
-rw-r--r--sys/arch/i386/conf/GENERIC3
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/itherm.c387
6 files changed, 467 insertions, 5 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 9888f9a4d37..1344f4c5894 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.508 2010/06/03 16:15:00 naddy Exp $
+# $OpenBSD: Makefile,v 1.509 2010/07/03 01:02:25 mlarkin Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
@@ -27,7 +27,7 @@ MAN= aac.4 ac97.4 acphy.4 \
ichiic.4 ichwdt.4 icmp.4 icmp6.4 icsphy.4 ifmedia.4 \
iha.4 iic.4 inet.4 inet6.4 inphy.4 iop.4 iophy.4 ioprbs.4 \
iopsp.4 ip.4 ip6.4 ipcomp.4 ipgphy.4 ipmi.4 ips.4 ipsec.4 ipw.4 \
- isa.4 isagpio.4 isapnp.4 isp.4 it.4 iwi.4 iwn.4 ix.4 ixgb.4 \
+ isa.4 isagpio.4 isapnp.4 isp.4 it.4 itherm.4 iwi.4 iwn.4 ix.4 ixgb.4 \
jmb.4 jme.4 jmphy.4 \
kate.4 km.4 ksyms.4 kue.4 lc.4 lge.4 lii.4 lisa.4 lkm.4 lm.4 \
lmc.4 lmenv.4 lmn.4 lmtemp.4 lo.4 lofn.4 lpt.4 lxtphy.4 luphy.4 \
diff --git a/share/man/man4/itherm.4 b/share/man/man4/itherm.4
new file mode 100644
index 00000000000..c7f7b65545f
--- /dev/null
+++ b/share/man/man4/itherm.4
@@ -0,0 +1,68 @@
+.\"
+.\" Copyright (c) 2010 Mike Larkin <mlarkin@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 3 2010 $
+.Dt ITHERM 4
+.Os
+.Sh NAME
+.Nm itherm
+.Nd Intel 3400 Thermal Sensor
+.Sh SYNOPSIS
+.Cd "itherm* at pci?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for several sensors found in Intel 3400 and 5 series
+chipsets.
+.Pp
+The sensors currently exposed via the
+.Xr sysctl 8
+interface are:
+.Bl -column "Sensor " "Units" "Typical" -offset indent
+.It Sy "Sensor" Ta Sy "Units" Ta Sy "Typical Use"
+.It Li "Thermometer" Ta "degC" Ta "Temperature"
+.It Li "Core 1" Ta "degC" Ta "Temperature"
+.It Li "Core 2" Ta "degC" Ta "Temperature"
+.It Li "CPU power cons." Ta "Watts" Ta "Power usage"
+.It Li "CPU/GPU Max" Ta "degC" Ta "Temperature"
+.It Li "DIMM 1" Ta "degC" Ta "Temperature"
+.It Li "DIMM 2" Ta "degC" Ta "Temperature"
+.It Li "DIMM 3" Ta "degC" Ta "Temperature"
+.It Li "DIMM 4" Ta "degC" Ta "Temperature"
+.It Li "GPU abs." Ta "degC" Ta "Temperature"
+.It Li "PCH abs." Ta "degC" Ta "Temperature"
+.El
+.Sh SEE ALSO
+.Xr pci 4 ,
+.Xr sensorsd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 4.8 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Mike Larkin Aq mlarkin@openbsd.org .
+.Sh CAVEATS
+Not all sensors are wired on every machine, so the list of
+sensors shown in
+.Xr sysctl 8
+may not show all the sensors listed above.
+Further, the
+.Nm
+driver will flag sensors as invalid if they report bogus data.
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index f9853c899f8..c6b26ccd4bc 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.290 2010/06/27 21:00:22 kettenis Exp $
+# $OpenBSD: GENERIC,v 1.291 2010/07/03 01:02:25 mlarkin Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -113,6 +113,7 @@ iic* at nviic?
amdpm* at pci? # AMD-7xx/8111 and NForce SMBus controller
iic* at amdpm?
+itherm* at pci? # Intel 3400 Thermal Sensor
adc* at iic? # Analog Devices AD7416/AD7417/7418
adl* at iic? # Andigilog aSC7621
admtemp* at iic? # Analog Devices ADM1021
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC
index 7babe24783f..a280478ecfb 100644
--- a/sys/arch/i386/conf/GENERIC
+++ b/sys/arch/i386/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.685 2010/07/01 17:30:25 tedu Exp $
+# $OpenBSD: GENERIC,v 1.686 2010/07/03 01:02:25 mlarkin Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -152,6 +152,7 @@ fins0 at isa? port 0x4e # Fintek F71805 Super I/O
aps0 at isa? port 0x1600 # ThinkPad Active Protection System
+itherm* at pci? # Intel 3400 Thermal Sensor
adc* at iic? # Analog Devices AD7416/AD7417/7418
andl* at iic? # Andigilog aSC7611
adl* at iic? # Andigilog aSC7621
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 2d7b76f24e2..a713c49394d 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.272 2010/06/27 01:47:36 dlg Exp $
+# $OpenBSD: files.pci,v 1.273 2010/07/03 01:02:25 mlarkin Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -806,3 +806,8 @@ device auglx: audio, ac97
attach auglx at pci
file dev/pci/auglx.c auglx
+# Intel 3400 Thermal
+device itherm
+attach itherm at pci
+file dev/pci/itherm.c itherm
+
diff --git a/sys/dev/pci/itherm.c b/sys/dev/pci/itherm.c
new file mode 100644
index 00000000000..839668e3431
--- /dev/null
+++ b/sys/dev/pci/itherm.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2010 Mike Larkin <mlarkin@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Intel 3400 thermal sensor controller driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/sensors.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#define ITHERM_NUM_SENSORS 12
+#define ITHERM_SENSOR_THERMOMETER 0
+#define ITHERM_SENSOR_CORETEMP1 1
+#define ITHERM_SENSOR_CORETEMP2 2
+#define ITHERM_SENSOR_COREENERGY 3
+#define ITHERM_SENSOR_GPUTEMP 4
+#define ITHERM_SENSOR_MAXPROCTEMP 5
+#define ITHERM_SENSOR_DIMMTEMP1 6
+#define ITHERM_SENSOR_DIMMTEMP2 7
+#define ITHERM_SENSOR_DIMMTEMP3 8
+#define ITHERM_SENSOR_DIMMTEMP4 9
+#define ITHERM_SENSOR_GPUTEMP_ABSOLUTE 10
+#define ITHERM_SENSOR_PCHTEMP_ABSOLUTE 11
+
+/* Intel 3400 Thermal Sensor Data */
+#define ITHERM_TSE 0x1
+#define ITHERM_TSTR 0x3
+#define ITHERM_TRC 0x1A
+#define ITHERM_CTV1 0x30
+#define ITHERM_CTV2 0x32
+#define ITHERM_CEV1 0x34
+#define ITHERM_MGTV 0x58
+#define ITHERM_PTV 0x60
+#define ITHERM_DTV 0xAC
+#define ITHERM_ITV 0xD8
+
+#define ITHERM_TEMP_READ_ENABLE 0xFF
+#define ITHERM_TDR_ENABLE 0x1000
+#define ITHERM_SECOND_CORE_ENABLE 0x8000
+
+#define ITHERM_TSE_ENABLE 0xB8
+
+#define ITHERM_CTV_INVALID 0x8000
+#define ITHERM_CTV_INT_MASK 0x1FE0
+#define ITHERM_CTV_FRAC_MASK 0x001F
+
+#define ITHERM_REFRESH_INTERVAL 5
+
+struct itherm_softc {
+ struct device sc_dev;
+
+ bus_addr_t sc_addr;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ bus_size_t size;
+
+ int64_t energy_prev;
+
+ struct ksensor sensors[ITHERM_NUM_SENSORS];
+ struct ksensordev sensordev;
+ void (*refresh_sensor_data)(struct itherm_softc *);
+};
+
+#define IREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
+#define IREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
+#define IREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
+#define IWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
+#define IWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
+
+int itherm_probe(struct device *, void *, void *);
+void itherm_attach(struct device *, struct device *, void *);
+void itherm_refresh(void *);
+void itherm_enable(struct itherm_softc *);
+void itherm_refresh_sensor_data(struct itherm_softc *);
+int itherm_activate(struct device *, int);
+void itherm_bias_temperature_sensor(struct ksensor *);
+
+const struct pci_matchid itherm_devices[] = {
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_THERMAL }
+};
+
+struct cfdriver itherm_cd = {
+ NULL, "itherm", DV_DULL
+};
+
+struct cfattach itherm_ca = {
+ sizeof(struct itherm_softc), itherm_probe, itherm_attach, NULL,
+ itherm_activate
+};
+
+int
+itherm_probe(struct device *parent, void *match, void *aux)
+{
+ return (pci_matchbyid((struct pci_attach_args *)aux, itherm_devices,
+ sizeof(itherm_devices)/sizeof(itherm_devices[0])));
+}
+
+void
+itherm_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct itherm_softc *sc = (struct itherm_softc *)self;
+ struct pci_attach_args *pa = aux;
+ int i;
+ pcireg_t v;
+
+ v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
+ v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
+ if (pci_mapreg_map(pa, PCI_MAPREG_START,
+ v, 0, &sc->iot, &sc->ioh, NULL, &sc->size, 0)) {
+ printf(": can't map mem space\n");
+ return;
+ }
+
+ sc->sensors[ITHERM_SENSOR_THERMOMETER].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_COREENERGY].type = SENSOR_WATTS;
+ sc->sensors[ITHERM_SENSOR_GPUTEMP].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP1].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP2].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP3].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP4].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].type = SENSOR_TEMP;
+ sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].type = SENSOR_TEMP;
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc,
+ "Thermometer",
+ sizeof(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc,
+ "Core 1",
+ sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc,
+ "Core 2",
+ sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_COREENERGY].desc,
+ "CPU power consumption",
+ sizeof(sc->sensors[ITHERM_SENSOR_COREENERGY].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc,
+ "GPU/Memory Controller Temp",
+ sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc,
+ "CPU/GPU Max temp",
+ sizeof(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc,
+ "DIMM 1",
+ sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc,
+ "DIMM 2",
+ sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc,
+ "DIMM 3",
+ sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc,
+ "DIMM 4",
+ sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc,
+ "GPU/Memory controller abs.",
+ sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc));
+
+ strlcpy(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc,
+ "PCH abs.",
+ sizeof(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc));
+
+ strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->sensordev.xname));
+
+ itherm_enable(sc);
+
+ for (i=0; i < ITHERM_NUM_SENSORS; i++)
+ sensor_attach(&sc->sensordev, &sc->sensors[i]);
+
+ sensordev_install(&sc->sensordev);
+ sensor_task_register(sc, itherm_refresh, ITHERM_REFRESH_INTERVAL);
+
+ printf("\n");
+
+ return;
+}
+
+void
+itherm_enable(struct itherm_softc *sc)
+{
+ sc->energy_prev = 0;
+
+ /* Enable thermal sensor */
+ IWRITE1(sc, ITHERM_TSE, ITHERM_TSE_ENABLE);
+
+ /* Enable thermal reporting */
+ IWRITE2(sc, ITHERM_TRC, (ITHERM_TEMP_READ_ENABLE |
+ ITHERM_TDR_ENABLE | ITHERM_SECOND_CORE_ENABLE));
+}
+
+int
+itherm_activate(struct device *self, int act)
+{
+ struct itherm_softc *sc = (struct itherm_softc *)self;
+
+ switch(act) {
+ case DVACT_RESUME:
+ itherm_enable(sc);
+ }
+
+ return (0);
+}
+
+void
+itherm_refresh_sensor_data(struct itherm_softc *sc)
+{
+ u_int16_t data;
+ int64_t energy;
+ u_int32_t i;
+
+ /* Thermometer sensor */
+ sc->sensors[ITHERM_SENSOR_THERMOMETER].value =
+ IREAD1(sc, ITHERM_TSTR);
+
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_THERMOMETER]);
+
+ /*
+ * The Intel 3400 Thermal Sensor has separate sensors for each
+ * core, reported as a 16 bit value. Bits 13:6 are the integer
+ * part of the temperature in C and bits 5:0 are the fractional
+ * part of the temperature, in 1/64 degree C intervals.
+ * Bit 15 is used to indicate an invalid temperature
+ */
+
+ /* Core 1 temperature */
+ data = IREAD2(sc, ITHERM_CTV1);
+ if (data & ITHERM_CTV_INVALID)
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].flags |=
+ SENSOR_FINVALID;
+ else {
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].flags &=
+ ~SENSOR_FINVALID;
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].value =
+ (data & ITHERM_CTV_INT_MASK) >> 6;
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].value *=
+ 1000000;
+ data &= ITHERM_CTV_FRAC_MASK;
+ data *= 1000000 / 64;
+ sc->sensors[ITHERM_SENSOR_CORETEMP1].value +=
+ data;
+ }
+
+ /* Core 2 temperature */
+ data = IREAD2(sc, ITHERM_CTV2);
+ if (data & ITHERM_CTV_INVALID)
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].flags |=
+ SENSOR_FINVALID;
+ else {
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].flags &=
+ ~SENSOR_FINVALID;
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].value =
+ (data & ITHERM_CTV_INT_MASK) >> 6;
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].value *=
+ 1000000;
+ data &= ITHERM_CTV_FRAC_MASK;
+ data *= 1000000 / 64;
+ sc->sensors[ITHERM_SENSOR_CORETEMP2].value +=
+ data;
+ }
+
+ /*
+ * The core energy sensor reports the number of Joules
+ * of energy consumed by the processor since powerup.
+ * This number is scaled by 65535 and is continually
+ * increasing, so we save the old value and compute
+ * the difference for the Watt sensor value.
+ */
+
+ i = IREAD4(sc, ITHERM_CEV1);
+ /* Convert to Joules per interval */
+ energy = (i / 65535);
+ energy = energy - sc->energy_prev;
+ sc->energy_prev = (i / 65535);
+ /* Convert to Joules per second */
+ energy = energy / ITHERM_REFRESH_INTERVAL;
+ /* Convert to micro Joules per second (micro Watts) */
+ energy = energy * 1000 * 1000;
+
+ sc->sensors[ITHERM_SENSOR_COREENERGY].value = energy;
+
+ /*
+ * XXX - the GPU temp is reported as a 64 bit value with no
+ * documented structure. Disabled for now
+ */
+ sc->sensors[ITHERM_SENSOR_GPUTEMP].flags |= SENSOR_FINVALID;
+#if 0
+ bus_space_read_multi_4(sc->iot, sc->ioh, ITHERM_MGTV,
+ (u_int32_t *)&sc->sensors[ITHERM_SENSOR_GPUTEMP].value, 2);
+ sc->sensors[ITHERM_SENSOR_GPUTEMP].value *= 1000000;
+ sc->sensors[ITHERM_SENSOR_GPUTEMP].value += 273150000;
+#endif
+
+ /* Max processor temperature */
+ sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].value =
+ IREAD1(sc, ITHERM_PTV) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_MAXPROCTEMP]);
+
+ /* DIMM 1 */
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP1].value =
+ IREAD1(sc, ITHERM_DTV) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_DIMMTEMP1]);
+
+ /* DIMM 2 */
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP2].value =
+ IREAD1(sc, ITHERM_DTV+1) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_DIMMTEMP2]);
+
+ /* DIMM 3 */
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP3].value =
+ IREAD1(sc, ITHERM_DTV+2) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_DIMMTEMP3]);
+
+ /* DIMM 4 */
+ sc->sensors[ITHERM_SENSOR_DIMMTEMP4].value =
+ IREAD1(sc, ITHERM_DTV+3) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_DIMMTEMP4]);
+
+ /* GPU Temperature */
+ sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].value =
+ IREAD1(sc, ITHERM_ITV+1) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE]);
+
+ /* PCH Temperature */
+ sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].value =
+ IREAD1(sc, ITHERM_ITV) * 1000000;
+ itherm_bias_temperature_sensor(
+ &sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE]);
+}
+
+void
+itherm_bias_temperature_sensor(struct ksensor *sensor)
+{
+ if (sensor->value == 0 || sensor->value == 0xff)
+ sensor->flags |= SENSOR_FINVALID;
+ else
+ sensor->flags &= ~SENSOR_FINVALID;
+
+ /* Bias anyway from degC to degK, even if invalid */
+ sensor->value += 273150000;
+}
+
+void
+itherm_refresh(void *arg)
+{
+ struct itherm_softc *sc = (struct itherm_softc *)arg;
+
+ itherm_refresh_sensor_data(sc);
+}