Index: head/share/man/man4/Makefile =================================================================== --- head/share/man/man4/Makefile +++ head/share/man/man4/Makefile @@ -404,6 +404,7 @@ pccard.4 \ pccbb.4 \ pcf.4 \ + ${_pchtherm.4} \ pci.4 \ pcib.4 \ pcic.4 \ @@ -815,6 +816,7 @@ _nvme.4= nvme.4 _nvram.4= nvram.4 _padlock.4= padlock.4 +_pchtherm.4= pchtherm.4 _rr232x.4= rr232x.4 _speaker.4= speaker.4 _spkr.4= spkr.4 Index: head/share/man/man4/pchtherm.4 =================================================================== --- head/share/man/man4/pchtherm.4 +++ head/share/man/man4/pchtherm.4 @@ -0,0 +1,117 @@ +.\" +.\" Copyright (c) 2020 Takanori Watanabe +.\" +.\" 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$ +.\" +.Dd March 15, 2020 +.Dt pchtherm 4 +.Os +.Sh NAME +.Nm pchtherm +.Nd Intel PCH thermal subsystem +.Sh SYNOPSIS +.Cd "device pci" +.Cd "device pchtherm" +.Sh DESCRIPTION +The +.Nm +driver provides access to sensor data and configuration +installed in Intel PCH chipset. +.Nm +configuration register. +.Pp +The access to +.Nm +data is made via the +.Xr sysctl 8 +interface: +.Bd -literal +dev.pchtherm.0.ctt: 115.0C +dev.pchtherm.0.temperature: 28.5C +dev.pchtherm.0.t2temp: 91.0C +dev.pchtherm.0.t1temp: 86.0C +dev.pchtherm.0.t0temp: 81.0C +dev.pchtherm.0.tahv: 83.0C +dev.pchtherm.0.talv: 30.0C +dev.pchtherm.0.pmtime: 32 +dev.pchtherm.0.pmtemp: 50.0C +dev.pchtherm.0.%parent: pci0 +dev.pchtherm.0.%pnpinfo: vendor=0x8086 device=0x9d31 subvendor=0x17aa subdevice=0x2256 class=0x118000 +dev.pchtherm.0.%location: slot=20 function=2 dbsf=pci0:0:20:2 +dev.pchtherm.0.%driver: pchtherm +dev.pchtherm.0.%desc: Skylake PCH Thermal Subsystem +dev.pchtherm.%parent: +.Ed +.Bl -tag -width ".Va dev.pchtherm.%d.pch_hot_level" +.It Va dev.pchtherm.%d.temperature +Is the read-only value of the current temperature read by the sensor. +.It Va dev.pchtherm.%d.ctt +When the system reaches this temperature, it will shut down. +This will not appear when this feature is disabled and locked down. +.It Va dev.pchtherm.%d.t0temp +When temperature is under this value, system will be in T0 state. +.It Va dev.pchtherm.%d.t1temp +When temperature is over +.Va t0temp +and under this value, system will be in T1 state. +.It Va dev.pchtherm.%d.t2temp +When temperature is over +.Va t1temp +and under this value, system will be in T2 state. +Over this value, system will be in T3 state. +.It Va dev.pchtherm.%d.talv +Lower alart value. +This will not appear when sensor enable bit is locked down and the value is zero(which will show -50.0C). +.It Va dev.pchtherm.%d.tahv +High alart value. +This will not appear when sensor enable bit is locked down and the value is zero(which will show -50.0C). +.It Va dev.pchtherm.%d.pmtemp +Sensor Power management temperature. +Under this temperature, sensor will idle during +.Va pmtime +second. +.It Va dev.pchtherm.%d.pmtime +Sensor idle duration when low temperature. +.It Va dev.pchtherm.%d.pch_hot_level +When temperature is higher than this value, PCHHOT# pin will assert. +This value is not appear when this feature is disabled and locked down. +.El +.Pp +Please check the PCH datasheets for more details. +.Pp +.Sh CAVEAT +All values are read-only. +And it do not support event interrupt for now. +.Sh SEE ALSO +.Xr sysctl 8 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 13.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver and this manual page were written by +.An Takanori Watanabe Aq Mt takawata@FreeBSD.org . Index: head/sys/dev/intel/pchtherm.c =================================================================== --- head/sys/dev/intel/pchtherm.c +++ head/sys/dev/intel/pchtherm.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2020 Takanori Watanabe + * + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define PCHTHERM_REG_TEMP 0 +#define PCHTHERM_REG_TSC 4 +#define PCHTHERM_REG_TSS 6 +#define PCHTHERM_REG_TSEL 8 +#define PCHTHERM_REG_TSREL 0xa +#define PCHTHERM_REG_TSMIC 0xc +#define PCHTHERM_REG_CTT 0x10 +#define PCHTHERM_REG_TAHV 0x14 +#define PCHTHERM_REG_TALV 0x18 +#define PCHTHERM_REG_TSPM 0x1c +#define PCHTHERM_REG_TL 0x40 +#define PCHTHERM_REG_TL2 0x50 +#define PCHTHERM_REG_PHL 0x60 +#define PCHTHERM_REG_PHLC 0x62 +#define PCHTHERM_REG_TAS 0x80 +#define PCHTHERM_REG_TSPIEN 0x82 +#define PCHTHERM_REG_TSGPEN 0x84 +#define PCHTHERM_REG_TCFD 0xf0 +#define PCHTHERM_GEN_LOCKDOWN 0x80 +#define PCHTHERM_GEN_ENABLE 1 +#define PCHTHERM_TEMP_FACTOR 5 +#define PCHTHERM_TEMP_ZERO 2231 +#define PCHTHERM_TEMP_MASK 0x1ff +#define PCHTHERM_TL_T0 0 +#define PCHTHERM_TL_T1 10 +#define PCHTHERM_TL_T2 20 +#define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \ + PCHTHERM_TEMP_FACTOR + \ + PCHTHERM_TEMP_ZERO) + +struct pchtherm_softc +{ + int tbarrid; + struct resource *tbar; + int enable; + int ctten; + int pmtemp; + unsigned int pmtime; +}; + +static const struct pci_device_table pchtherm_devices[] = +{ + { PCI_DEV(0x8086, 0x9c24), + PCI_DESCR("Haswell Thermal Subsystem")}, + { PCI_DEV(0x8086, 0x8c24), + PCI_DESCR("Haswell Thermal Subsystem")}, + { PCI_DEV(0x8086, 0x9ca4), + PCI_DESCR("Wildcat Point Thermal Subsystem")}, + { PCI_DEV(0x8086, 0x9d31), + PCI_DESCR("Skylake PCH Thermal Subsystem")}, + { PCI_DEV(0x8086, 0xa131), + PCI_DESCR("Skylake PCH 100 Thermal Subsystem")}, +}; + +static int pchtherm_probe(device_t dev) +{ + const struct pci_device_table *tbl; + + tbl = PCI_MATCH(dev, pchtherm_devices); + if (tbl == NULL) + return (ENXIO); + device_set_desc(dev, tbl->descr); + + return (BUS_PROBE_DEFAULT); + +} +static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct pchtherm_softc *sc = oidp->oid_arg1; + int regshift = oidp->oid_arg2; + int temp; + + temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL); + temp >>= regshift; + temp = PCHTHERM_TEMP_TO_IK(temp); + + return sysctl_handle_int(oidp, &temp, 0, req); +} +static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct pchtherm_softc *sc = oidp->oid_arg1; + int regoff = oidp->oid_arg2; + int temp; + + temp = bus_read_2(sc->tbar, regoff); + temp = PCHTHERM_TEMP_TO_IK(temp); + + return sysctl_handle_int(oidp, &temp, 0, req); +} + +#define FLAG_PRINT(dev, str, val) device_printf \ + (dev, str " %s %sable\n", \ + ((val) & 0x80)? "Locked" : "", \ + ((val) & 0x1)? "En" : "Dis") + +static int pchtherm_attach(device_t dev) +{ + struct pchtherm_softc *sc = device_get_softc(dev); + unsigned int val; + int flag; + int temp; + + sc->tbarrid = PCIR_BAR(0); + sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE); + if (sc->tbar == NULL) { + return (ENOMEM); + } + sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); + if (!(sc->enable & PCHTHERM_GEN_ENABLE )) { + if (sc->enable & PCHTHERM_GEN_LOCKDOWN) { + device_printf(dev, "Sensor not available\n"); + return 0; + } else { + device_printf(dev, "Enabling Sensor\n"); + bus_write_1(sc->tbar, PCHTHERM_REG_TSEL, + PCHTHERM_GEN_ENABLE); + sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); + if (!(sc->enable & PCHTHERM_REG_TSEL)){ + device_printf(dev, "Sensor enable failed\n"); + return 0; + } + } + } + + sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); + if (bootverbose) { + FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten); + } + val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL); + if (bootverbose) { + FLAG_PRINT(dev, "SMBus report", val); + } + val = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); + if (bootverbose) { + FLAG_PRINT(dev, "SMI on alert", val); + } + val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM); + flag = val >> 13; + if (bootverbose) { + device_printf(dev, "TSPM: %b\n", + flag, "\20\3Lock\2DTSS0EN\1DSSOC0"); + device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n", + 1<<((val>>9)&7)); + } + + temp = val & PCHTHERM_TEMP_MASK; + sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp); + sc->pmtime = 1<<((val>>9)&7); + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD, + sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl, + "IK", "Thermal sensor idle temperature"); + SYSCTL_ADD_U32(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "pmtime", CTLFLAG_RD, + &sc->pmtime, 0,"Thermal sensor idle duration"); + + val = bus_read_4(sc->tbar, PCHTHERM_REG_TL); + flag = val>>29; + + if (bootverbose) { + device_printf(dev, "Throttling %b\n", + flag, "\20\3Lock\2TT13EN\1TTEN"); + } + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl, + "IK", "T0 temperature"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl, + "IK", "T1 temperature"); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl, + "IK", "T2 temperature"); + + val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2); + if (bootverbose) { + flag = val >>14; + device_printf(dev, "TL2 flag %b\n", + flag, "\20\1PMCTEN\2Lock"); + } + + /* If PHL is disable and lockdown, don't export it.*/ + val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC); + val <<= 16; + val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL); + if ((val & 0x10000) != 0x10000) { + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "pch_hot_level", + CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_REG_PHL, + pchtherm_temp_sysctl, "IK", + "PCH Hot level Temperature"); + } + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_REG_TEMP, + pchtherm_temp_sysctl, "IK", "Current temperature"); + /* + * If sensor enable bit is locked down, there is no way to change + * alart values effectively. + */ + if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || + bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) { + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_REG_TAHV, + pchtherm_temp_sysctl, "IK", + "Alart High temperature"); + } + + if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || + bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) { + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_REG_TALV, + pchtherm_temp_sysctl, "IK", + "Alart Low temperature"); + } + if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) || + sc->ctten& PCHTHERM_GEN_ENABLE) { + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "ctt", + CTLTYPE_INT |CTLFLAG_RD, + sc, PCHTHERM_REG_CTT, + pchtherm_temp_sysctl, "IK", + "Catastrophic Trip Point"); + } + + return 0; +} +static int pchtherm_detach(device_t dev) +{ + struct pchtherm_softc *sc = device_get_softc(dev); + bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar); + + return 0; +} +static device_method_t pchtherm_methods[] = +{ + DEVMETHOD(device_probe, pchtherm_probe), + DEVMETHOD(device_attach, pchtherm_attach), + DEVMETHOD(device_detach, pchtherm_detach), + + DEVMETHOD_END +}; +static driver_t pchtherm_driver = { + "pchtherm", + pchtherm_methods, + sizeof(struct pchtherm_softc) +}; + +static devclass_t pchtherm_devclass; +DRIVER_MODULE(pchtherm, pci, pchtherm_driver, pchtherm_devclass, 0, 0); +PCI_PNP_INFO(pchtherm_devices); Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -278,6 +278,7 @@ ${_padlock} \ ${_padlock_rng} \ ${_pccard} \ + ${_pchtherm} \ ${_pcfclock} \ ${_pf} \ ${_pflog} \ @@ -676,6 +677,7 @@ _padlock_rng= padlock_rng _rdrand_rng= rdrand_rng .endif +_pchtherm = pchtherm _s3= s3 _sdhci_acpi= sdhci_acpi _superio= superio Index: head/sys/modules/pchtherm/Makefile =================================================================== --- head/sys/modules/pchtherm/Makefile +++ head/sys/modules/pchtherm/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/intel +KMOD= pchtherm +SRCS= pchtherm.c +SRCS+= device_if.h bus_if.h pci_if.h opt_platform.h + +.include