2 * Copyright (c) 2020 Takanori Watanabe
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/errno.h>
35 #include <sys/mutex.h>
36 #include <sys/sysctl.h>
37 #include <sys/syslog.h>
40 #include <machine/bus.h>
42 #include <machine/resource.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
46 #define PCHTHERM_REG_TEMP 0
47 #define PCHTHERM_REG_TSC 4
48 #define PCHTHERM_REG_TSS 6
49 #define PCHTHERM_REG_TSEL 8
50 #define PCHTHERM_REG_TSREL 0xa
51 #define PCHTHERM_REG_TSMIC 0xc
52 #define PCHTHERM_REG_CTT 0x10
53 #define PCHTHERM_REG_TAHV 0x14
54 #define PCHTHERM_REG_TALV 0x18
55 #define PCHTHERM_REG_TSPM 0x1c
56 #define PCHTHERM_REG_TL 0x40
57 #define PCHTHERM_REG_TL2 0x50
58 #define PCHTHERM_REG_PHL 0x60
59 #define PCHTHERM_REG_PHLC 0x62
60 #define PCHTHERM_REG_TAS 0x80
61 #define PCHTHERM_REG_TSPIEN 0x82
62 #define PCHTHERM_REG_TSGPEN 0x84
63 #define PCHTHERM_REG_TCFD 0xf0
64 #define PCHTHERM_GEN_LOCKDOWN 0x80
65 #define PCHTHERM_GEN_ENABLE 1
66 #define PCHTHERM_TEMP_FACTOR 5
67 #define PCHTHERM_TEMP_ZERO 2231
68 #define PCHTHERM_TEMP_MASK 0x1ff
69 #define PCHTHERM_TL_T0 0
70 #define PCHTHERM_TL_T1 10
71 #define PCHTHERM_TL_T2 20
72 #define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \
73 PCHTHERM_TEMP_FACTOR + \
79 struct resource *tbar;
86 static const struct pci_device_table pchtherm_devices[] =
88 { PCI_DEV(0x8086, 0x9c24),
89 PCI_DESCR("Haswell Thermal Subsystem")},
90 { PCI_DEV(0x8086, 0x8c24),
91 PCI_DESCR("Haswell Thermal Subsystem")},
92 { PCI_DEV(0x8086, 0x9ca4),
93 PCI_DESCR("Wildcat Point Thermal Subsystem")},
94 { PCI_DEV(0x8086, 0x9d31),
95 PCI_DESCR("Skylake PCH Thermal Subsystem")},
96 { PCI_DEV(0x8086, 0xa131),
97 PCI_DESCR("Skylake PCH 100 Thermal Subsystem")},
98 { PCI_DEV(0x8086, 0x9df9),
99 PCI_DESCR("Cannon Lake PCH Thermal Controller")},
102 static int pchtherm_probe(device_t dev)
104 const struct pci_device_table *tbl;
106 tbl = PCI_MATCH(dev, pchtherm_devices);
109 device_set_desc(dev, tbl->descr);
111 return (BUS_PROBE_DEFAULT);
114 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS)
116 struct pchtherm_softc *sc = oidp->oid_arg1;
117 int regshift = oidp->oid_arg2;
120 temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
122 temp = PCHTHERM_TEMP_TO_IK(temp);
124 return sysctl_handle_int(oidp, &temp, 0, req);
126 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS)
128 struct pchtherm_softc *sc = oidp->oid_arg1;
129 int regoff = oidp->oid_arg2;
132 temp = bus_read_2(sc->tbar, regoff);
133 temp = PCHTHERM_TEMP_TO_IK(temp);
135 return sysctl_handle_int(oidp, &temp, 0, req);
138 #define FLAG_PRINT(dev, str, val) device_printf \
139 (dev, str " %s %sable\n", \
140 ((val) & 0x80)? "Locked" : "", \
141 ((val) & 0x1)? "En" : "Dis")
143 static int pchtherm_attach(device_t dev)
145 struct pchtherm_softc *sc = device_get_softc(dev);
150 sc->tbarrid = PCIR_BAR(0);
151 sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
152 &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE);
153 if (sc->tbar == NULL) {
156 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
157 if (!(sc->enable & PCHTHERM_GEN_ENABLE )) {
158 if (sc->enable & PCHTHERM_GEN_LOCKDOWN) {
159 device_printf(dev, "Sensor not available\n");
162 device_printf(dev, "Enabling Sensor\n");
163 bus_write_1(sc->tbar, PCHTHERM_REG_TSEL,
164 PCHTHERM_GEN_ENABLE);
165 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
166 if (!(sc->enable & PCHTHERM_REG_TSEL)){
167 device_printf(dev, "Sensor enable failed\n");
173 sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
175 FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten);
177 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL);
179 FLAG_PRINT(dev, "SMBus report", val);
181 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
183 FLAG_PRINT(dev, "SMI on alert", val);
185 val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM);
188 device_printf(dev, "TSPM: %b\n",
189 flag, "\20\3Lock\2DTSS0EN\1DSSOC0");
190 device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n",
194 temp = val & PCHTHERM_TEMP_MASK;
195 sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp);
196 sc->pmtime = 1<<((val>>9)&7);
197 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
198 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
199 OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD,
200 sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl,
201 "IK", "Thermal sensor idle temperature");
202 SYSCTL_ADD_U32(device_get_sysctl_ctx(dev),
203 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
204 OID_AUTO, "pmtime", CTLFLAG_RD,
205 &sc->pmtime, 0,"Thermal sensor idle duration");
207 val = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
211 device_printf(dev, "Throttling %b\n",
212 flag, "\20\3Lock\2TT13EN\1TTEN");
215 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
216 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
217 OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD,
218 sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl,
219 "IK", "T0 temperature");
221 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
222 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
223 OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD,
224 sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl,
225 "IK", "T1 temperature");
227 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
228 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
229 OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD,
230 sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl,
231 "IK", "T2 temperature");
233 val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2);
236 device_printf(dev, "TL2 flag %b\n",
237 flag, "\20\1PMCTEN\2Lock");
240 /* If PHL is disable and lockdown, don't export it.*/
241 val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC);
243 val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL);
244 if ((val & 0x10000) != 0x10000) {
245 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
246 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
247 OID_AUTO, "pch_hot_level",
248 CTLTYPE_INT |CTLFLAG_RD,
249 sc, PCHTHERM_REG_PHL,
250 pchtherm_temp_sysctl, "IK",
251 "PCH Hot level Temperature");
254 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
255 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
256 OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD,
257 sc, PCHTHERM_REG_TEMP,
258 pchtherm_temp_sysctl, "IK", "Current temperature");
260 * If sensor enable bit is locked down, there is no way to change
261 * alart values effectively.
263 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
264 bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) {
265 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
266 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
267 OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD,
268 sc, PCHTHERM_REG_TAHV,
269 pchtherm_temp_sysctl, "IK",
270 "Alart High temperature");
273 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
274 bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) {
275 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
276 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
277 OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD,
278 sc, PCHTHERM_REG_TALV,
279 pchtherm_temp_sysctl, "IK",
280 "Alart Low temperature");
282 if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) ||
283 sc->ctten& PCHTHERM_GEN_ENABLE) {
284 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
285 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
287 CTLTYPE_INT |CTLFLAG_RD,
288 sc, PCHTHERM_REG_CTT,
289 pchtherm_temp_sysctl, "IK",
290 "Catastrophic Trip Point");
295 static int pchtherm_detach(device_t dev)
297 struct pchtherm_softc *sc = device_get_softc(dev);
298 bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar);
302 static device_method_t pchtherm_methods[] =
304 DEVMETHOD(device_probe, pchtherm_probe),
305 DEVMETHOD(device_attach, pchtherm_attach),
306 DEVMETHOD(device_detach, pchtherm_detach),
310 static driver_t pchtherm_driver = {
313 sizeof(struct pchtherm_softc)
316 static devclass_t pchtherm_devclass;
317 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, pchtherm_devclass, 0, 0);
318 PCI_PNP_INFO(pchtherm_devices);