xref: /freebsd/sys/dev/intel/pchtherm.c (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1 /*
2  * Copyright (c) 2020 Takanori Watanabe
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
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>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/sysctl.h>
37 #include <sys/syslog.h>
38 #include <sys/bus.h>
39 
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 #include <machine/resource.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 
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 +       \
74 				  PCHTHERM_TEMP_ZERO)
75 
76 struct pchtherm_softc
77 {
78 	int tbarrid;
79 	struct resource *tbar;
80 	int enable;
81 	int ctten;
82 	int pmtemp;
83 	unsigned int pmtime;
84 };
85 
86 static const struct pci_device_table pchtherm_devices[] =
87 {
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 };
99 
100 static int pchtherm_probe(device_t dev)
101 {
102 	const struct pci_device_table *tbl;
103 
104 	tbl = PCI_MATCH(dev, pchtherm_devices);
105 	if (tbl == NULL)
106 		return (ENXIO);
107 	device_set_desc(dev, tbl->descr);
108 
109 	return (BUS_PROBE_DEFAULT);
110 
111 }
112 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS)
113 {
114 	struct pchtherm_softc *sc = oidp->oid_arg1;
115 	int regshift = oidp->oid_arg2;
116 	int temp;
117 
118 	temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
119 	temp >>= regshift;
120 	temp = PCHTHERM_TEMP_TO_IK(temp);
121 
122 	return sysctl_handle_int(oidp, &temp, 0, req);
123 }
124 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS)
125 {
126 	struct pchtherm_softc *sc = oidp->oid_arg1;
127 	int regoff = oidp->oid_arg2;
128 	int temp;
129 
130 	temp = bus_read_2(sc->tbar, regoff);
131 	temp = PCHTHERM_TEMP_TO_IK(temp);
132 
133 	return sysctl_handle_int(oidp, &temp, 0, req);
134 }
135 
136 #define FLAG_PRINT(dev, str, val) device_printf				\
137 	(dev, str " %s %sable\n",				       	\
138 	 ((val) & 0x80)? "Locked" : "",					\
139 	 ((val) & 0x1)? "En" : "Dis")
140 
141 static int pchtherm_attach(device_t dev)
142 {
143 	struct pchtherm_softc *sc =  device_get_softc(dev);
144 	unsigned int val;
145 	int flag;
146 	int temp;
147 
148 	sc->tbarrid = PCIR_BAR(0);
149 	sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
150 					  &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE);
151 	if (sc->tbar == NULL) {
152 		return (ENOMEM);
153 	}
154 	sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
155 	if (!(sc->enable & PCHTHERM_GEN_ENABLE )) {
156 		if (sc->enable & PCHTHERM_GEN_LOCKDOWN) {
157 			device_printf(dev, "Sensor not available\n");
158 			return 0;
159 		} else {
160 			device_printf(dev, "Enabling Sensor\n");
161 			bus_write_1(sc->tbar, PCHTHERM_REG_TSEL,
162 				    PCHTHERM_GEN_ENABLE);
163 			sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
164 			if (!(sc->enable & PCHTHERM_REG_TSEL)){
165 				device_printf(dev, "Sensor enable failed\n");
166 				return 0;
167 			}
168 		}
169 	}
170 
171 	sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
172 	if (bootverbose) {
173 		FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten);
174 	}
175 	val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL);
176 	if (bootverbose) {
177 		FLAG_PRINT(dev, "SMBus report", val);
178 	}
179 	val = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
180 	if (bootverbose) {
181 		FLAG_PRINT(dev, "SMI on alert", val);
182 	}
183 	val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM);
184 	flag = val >> 13;
185 	if (bootverbose) {
186 		device_printf(dev, "TSPM: %b\n",
187 			      flag, "\20\3Lock\2DTSS0EN\1DSSOC0");
188 		device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n",
189 			      1<<((val>>9)&7));
190 	}
191 
192 	temp = val & PCHTHERM_TEMP_MASK;
193 	sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp);
194 	sc->pmtime = 1<<((val>>9)&7);
195 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
196 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
197 			OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD,
198 			sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl,
199 			"IK", "Thermal sensor idle temperature");
200 	SYSCTL_ADD_U32(device_get_sysctl_ctx(dev),
201 		       SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
202 		       OID_AUTO, "pmtime", CTLFLAG_RD,
203 		       &sc->pmtime, 0,"Thermal sensor idle duration");
204 
205 	val = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
206 	flag = val>>29;
207 
208 	if (bootverbose) {
209 		device_printf(dev, "Throttling %b\n",
210 			      flag, "\20\3Lock\2TT13EN\1TTEN");
211 	}
212 
213 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
214 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
215 			OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD,
216 			sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl,
217 		        "IK", "T0 temperature");
218 
219 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
220 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
221 			OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD,
222 			sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl,
223 		        "IK", "T1 temperature");
224 
225 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
226 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
227 			OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD,
228 			sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl,
229 			"IK", "T2 temperature");
230 
231 	val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2);
232 	if (bootverbose) {
233 		flag = val >>14;
234 		device_printf(dev, "TL2 flag %b\n",
235 			      flag, "\20\1PMCTEN\2Lock");
236 	}
237 
238 	/* If PHL is disable and lockdown, don't export it.*/
239 	val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC);
240 	val <<= 16;
241 	val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL);
242 	if ((val & 0x10000) != 0x10000) {
243 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
244 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
245 				OID_AUTO, "pch_hot_level",
246 				CTLTYPE_INT |CTLFLAG_RD,
247 				sc, PCHTHERM_REG_PHL,
248 				pchtherm_temp_sysctl, "IK",
249 				"PCH Hot level Temperature");
250 	}
251 
252 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
253 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
254 			OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD,
255 			sc, PCHTHERM_REG_TEMP,
256 			pchtherm_temp_sysctl, "IK", "Current temperature");
257 	/*
258 	 * If sensor enable bit is locked down, there is no way to change
259 	 * alart values effectively.
260 	 */
261 	if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
262 	    bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) {
263 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
264 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
265 				OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD,
266 				sc, PCHTHERM_REG_TAHV,
267 				pchtherm_temp_sysctl, "IK",
268 				"Alart High temperature");
269 	}
270 
271 	if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
272 	    bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) {
273 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
274 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
275 				OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD,
276 				sc, PCHTHERM_REG_TALV,
277 				pchtherm_temp_sysctl, "IK",
278 				"Alart Low temperature");
279 	}
280 	if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) ||
281 	    sc->ctten& PCHTHERM_GEN_ENABLE) {
282 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
283 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
284 				OID_AUTO, "ctt",
285 				CTLTYPE_INT |CTLFLAG_RD,
286 				sc, PCHTHERM_REG_CTT,
287 				pchtherm_temp_sysctl, "IK",
288 				"Catastrophic Trip Point");
289 	}
290 
291 	return 0;
292 }
293 static int pchtherm_detach(device_t dev)
294 {
295 	struct pchtherm_softc *sc =  device_get_softc(dev);
296 	bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar);
297 
298 	return 0;
299 }
300 static device_method_t pchtherm_methods[] =
301 {
302 	DEVMETHOD(device_probe, pchtherm_probe),
303 	DEVMETHOD(device_attach, pchtherm_attach),
304 	DEVMETHOD(device_detach, pchtherm_detach),
305 
306 	DEVMETHOD_END
307 };
308 static driver_t pchtherm_driver = {
309 	"pchtherm",
310 	pchtherm_methods,
311 	sizeof(struct pchtherm_softc)
312 };
313 
314 static devclass_t pchtherm_devclass;
315 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, pchtherm_devclass, 0, 0);
316 PCI_PNP_INFO(pchtherm_devices);
317