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