xref: /freebsd/sys/dev/intel/pchtherm.c (revision 2008043f386721d58158e37e0d7e50df8095942d)
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 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/module.h>
31 #include <sys/errno.h>
32 #include <sys/lock.h>
33 #include <sys/mutex.h>
34 #include <sys/sysctl.h>
35 #include <sys/syslog.h>
36 #include <sys/bus.h>
37 
38 #include <machine/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41 #include <dev/pci/pcivar.h>
42 #include <dev/pci/pcireg.h>
43 
44 #define PCHTHERM_REG_TEMP 0
45 #define PCHTHERM_REG_TSC 4
46 #define PCHTHERM_REG_TSS 6
47 #define PCHTHERM_REG_TSEL 8
48 #define PCHTHERM_REG_TSREL 0xa
49 #define PCHTHERM_REG_TSMIC 0xc
50 #define PCHTHERM_REG_CTT 0x10
51 #define PCHTHERM_REG_TAHV 0x14
52 #define PCHTHERM_REG_TALV 0x18
53 #define PCHTHERM_REG_TSPM 0x1c
54 #define PCHTHERM_REG_TL 0x40
55 #define PCHTHERM_REG_TL2 0x50
56 #define PCHTHERM_REG_PHL 0x60
57 #define PCHTHERM_REG_PHLC 0x62
58 #define PCHTHERM_REG_TAS 0x80
59 #define PCHTHERM_REG_TSPIEN 0x82
60 #define PCHTHERM_REG_TSGPEN 0x84
61 #define PCHTHERM_REG_TCFD 0xf0
62 #define PCHTHERM_GEN_LOCKDOWN 0x80
63 #define PCHTHERM_GEN_ENABLE 1
64 #define PCHTHERM_TEMP_FACTOR 5
65 #define PCHTHERM_TEMP_ZERO 2231
66 #define PCHTHERM_TEMP_MASK 0x1ff
67 #define PCHTHERM_TL_T0 0
68 #define PCHTHERM_TL_T1 10
69 #define PCHTHERM_TL_T2 20
70 #define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \
71 				  PCHTHERM_TEMP_FACTOR +       \
72 				  PCHTHERM_TEMP_ZERO)
73 
74 struct pchtherm_softc
75 {
76 	int tbarrid;
77 	struct resource *tbar;
78 	int enable;
79 	int ctten;
80 	int pmtemp;
81 	unsigned int pmtime;
82 };
83 
84 static const struct pci_device_table pchtherm_devices[] =
85 {
86 	{ PCI_DEV(0x8086, 0x9c24),
87 	  PCI_DESCR("Haswell Thermal Subsystem")},
88 	{ PCI_DEV(0x8086, 0x8c24),
89 	  PCI_DESCR("Haswell Thermal Subsystem")},
90 	{ PCI_DEV(0x8086, 0x9ca4),
91 	  PCI_DESCR("Wildcat Point Thermal Subsystem")},
92 	{ PCI_DEV(0x8086, 0x9d31),
93 	  PCI_DESCR("Skylake PCH Thermal Subsystem")},
94 	{ PCI_DEV(0x8086, 0xa131),
95 	  PCI_DESCR("Skylake PCH 100 Thermal Subsystem")},
96 	{ PCI_DEV(0x8086, 0x9df9),
97 	  PCI_DESCR("CannonLake-LP Thermal Subsystem")},
98 	{ PCI_DEV(0x8086, 0xa379),
99 	  PCI_DESCR("CannonLake-H Thermal Subsystem")},
100 	{ PCI_DEV(0x8086, 0x02f9),
101 	  PCI_DESCR("CometLake-LP Thermal Subsystem")},
102 	{ PCI_DEV(0x8086, 0x06f9),
103 	  PCI_DESCR("CometLake-H Thermal Subsystem")},
104 	{ PCI_DEV(0x8086, 0xa1b1),
105 	  PCI_DESCR("Lewisburg Thermal Subsystem")},
106 };
107 
108 static int pchtherm_probe(device_t dev)
109 {
110 	const struct pci_device_table *tbl;
111 
112 	tbl = PCI_MATCH(dev, pchtherm_devices);
113 	if (tbl == NULL)
114 		return (ENXIO);
115 	device_set_desc(dev, tbl->descr);
116 
117 	return (BUS_PROBE_DEFAULT);
118 
119 }
120 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS)
121 {
122 	struct pchtherm_softc *sc = oidp->oid_arg1;
123 	int regshift = oidp->oid_arg2;
124 	int temp;
125 
126 	temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
127 	temp >>= regshift;
128 	temp = PCHTHERM_TEMP_TO_IK(temp);
129 
130 	return sysctl_handle_int(oidp, &temp, 0, req);
131 }
132 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS)
133 {
134 	struct pchtherm_softc *sc = oidp->oid_arg1;
135 	int regoff = oidp->oid_arg2;
136 	int temp;
137 
138 	temp = bus_read_2(sc->tbar, regoff);
139 	temp = PCHTHERM_TEMP_TO_IK(temp);
140 
141 	return sysctl_handle_int(oidp, &temp, 0, req);
142 }
143 
144 #define FLAG_PRINT(dev, str, val) device_printf				\
145 	(dev, str " %s %sable\n",				       	\
146 	 ((val) & 0x80)? "Locked" : "",					\
147 	 ((val) & 0x1)? "En" : "Dis")
148 
149 static int pchtherm_attach(device_t dev)
150 {
151 	struct pchtherm_softc *sc =  device_get_softc(dev);
152 	unsigned int val;
153 	int flag;
154 	int temp;
155 
156 	sc->tbarrid = PCIR_BAR(0);
157 	sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
158 					  &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE);
159 	if (sc->tbar == NULL) {
160 		return (ENOMEM);
161 	}
162 	sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
163 	if (!(sc->enable & PCHTHERM_GEN_ENABLE )) {
164 		if (sc->enable & PCHTHERM_GEN_LOCKDOWN) {
165 			device_printf(dev, "Sensor not available\n");
166 			return 0;
167 		} else {
168 			device_printf(dev, "Enabling Sensor\n");
169 			bus_write_1(sc->tbar, PCHTHERM_REG_TSEL,
170 				    PCHTHERM_GEN_ENABLE);
171 			sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL);
172 			if (!(sc->enable & PCHTHERM_GEN_ENABLE)) {
173 				device_printf(dev, "Sensor enable failed\n");
174 				return 0;
175 			}
176 		}
177 	}
178 
179 	sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC);
180 	if (bootverbose) {
181 		FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten);
182 	}
183 	val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL);
184 	if (bootverbose) {
185 		FLAG_PRINT(dev, "SMBus report", val);
186 	}
187 	val = bus_read_1(sc->tbar, PCHTHERM_REG_TSMIC);
188 	if (bootverbose) {
189 		FLAG_PRINT(dev, "SMI on alert", val);
190 	}
191 	val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM);
192 	flag = val >> 13;
193 	if (bootverbose) {
194 		device_printf(dev, "TSPM: %b\n",
195 			      flag, "\20\3Lock\2DTSS0EN\1DSSOC0");
196 		device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n",
197 			      1<<((val>>9)&7));
198 	}
199 
200 	temp = val & PCHTHERM_TEMP_MASK;
201 	sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp);
202 	sc->pmtime = 1<<((val>>9)&7);
203 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
204 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
205 			OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD,
206 			sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl,
207 			"IK", "Thermal sensor idle temperature");
208 	SYSCTL_ADD_U32(device_get_sysctl_ctx(dev),
209 		       SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
210 		       OID_AUTO, "pmtime", CTLFLAG_RD,
211 		       &sc->pmtime, 0,"Thermal sensor idle duration");
212 
213 	val = bus_read_4(sc->tbar, PCHTHERM_REG_TL);
214 	flag = val>>29;
215 
216 	if (bootverbose) {
217 		device_printf(dev, "Throttling %b\n",
218 			      flag, "\20\3Lock\2TT13EN\1TTEN");
219 	}
220 
221 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
222 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
223 			OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD,
224 			sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl,
225 		        "IK", "T0 temperature");
226 
227 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
228 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
229 			OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD,
230 			sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl,
231 		        "IK", "T1 temperature");
232 
233 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
234 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
235 			OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD,
236 			sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl,
237 			"IK", "T2 temperature");
238 
239 	val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2);
240 	if (bootverbose) {
241 		flag = val >>14;
242 		device_printf(dev, "TL2 flag %b\n",
243 			      flag, "\20\1PMCTEN\2Lock");
244 	}
245 
246 	/* If PHL is disable and lockdown, don't export it.*/
247 	val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC);
248 	val <<= 16;
249 	val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL);
250 	if ((val & 0x10000) != 0x10000) {
251 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
252 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
253 				OID_AUTO, "pch_hot_level",
254 				CTLTYPE_INT |CTLFLAG_RD,
255 				sc, PCHTHERM_REG_PHL,
256 				pchtherm_temp_sysctl, "IK",
257 				"PCH Hot level Temperature");
258 	}
259 
260 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
261 			SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
262 			OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD,
263 			sc, PCHTHERM_REG_TEMP,
264 			pchtherm_temp_sysctl, "IK", "Current temperature");
265 	/*
266 	 * If sensor enable bit is locked down, there is no way to change
267 	 * alart values effectively.
268 	 */
269 	if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
270 	    bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) {
271 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
272 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
273 				OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD,
274 				sc, PCHTHERM_REG_TAHV,
275 				pchtherm_temp_sysctl, "IK",
276 				"Alart High temperature");
277 	}
278 
279 	if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) ||
280 	    bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) {
281 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
282 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
283 				OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD,
284 				sc, PCHTHERM_REG_TALV,
285 				pchtherm_temp_sysctl, "IK",
286 				"Alart Low temperature");
287 	}
288 	if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) ||
289 	    sc->ctten& PCHTHERM_GEN_ENABLE) {
290 		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
291 				SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
292 				OID_AUTO, "ctt",
293 				CTLTYPE_INT |CTLFLAG_RD,
294 				sc, PCHTHERM_REG_CTT,
295 				pchtherm_temp_sysctl, "IK",
296 				"Catastrophic Trip Point");
297 	}
298 
299 	return 0;
300 }
301 static int pchtherm_detach(device_t dev)
302 {
303 	struct pchtherm_softc *sc =  device_get_softc(dev);
304 	bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar);
305 
306 	return 0;
307 }
308 
309 static device_method_t pchtherm_methods[] =
310 {
311 	DEVMETHOD(device_probe, pchtherm_probe),
312 	DEVMETHOD(device_attach, pchtherm_attach),
313 	DEVMETHOD(device_detach, pchtherm_detach),
314 
315 	DEVMETHOD_END
316 };
317 
318 static driver_t pchtherm_driver = {
319 	"pchtherm",
320 	pchtherm_methods,
321 	sizeof(struct pchtherm_softc)
322 };
323 
324 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, 0, 0);
325 PCI_PNP_INFO(pchtherm_devices);
326