xref: /openbsd-src/sys/dev/pci/itherm.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*
2  * Copyright (c) 2010 Mike Larkin <mlarkin@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * Intel 3400 thermal sensor controller driver
19  */
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/device.h>
24 #include <sys/sensors.h>
25 
26 #include <dev/pci/pcireg.h>
27 #include <dev/pci/pcivar.h>
28 #include <dev/pci/pcidevs.h>
29 
30 #define ITHERM_NUM_SENSORS 12
31 #define ITHERM_SENSOR_THERMOMETER 0
32 #define ITHERM_SENSOR_CORETEMP1 1
33 #define ITHERM_SENSOR_CORETEMP2 2
34 #define ITHERM_SENSOR_COREENERGY 3
35 #define ITHERM_SENSOR_GPUTEMP 4
36 #define ITHERM_SENSOR_MAXPROCTEMP 5
37 #define ITHERM_SENSOR_DIMMTEMP1 6
38 #define ITHERM_SENSOR_DIMMTEMP2 7
39 #define ITHERM_SENSOR_DIMMTEMP3 8
40 #define ITHERM_SENSOR_DIMMTEMP4 9
41 #define ITHERM_SENSOR_GPUTEMP_ABSOLUTE 10
42 #define ITHERM_SENSOR_PCHTEMP_ABSOLUTE 11
43 
44 /* Intel 3400 Thermal Sensor Data */
45 #define ITHERM_TSE	0x1
46 #define ITHERM_TSTR	0x3
47 #define ITHERM_TRC	0x1A
48 #define ITHERM_CTV1	0x30
49 #define ITHERM_CTV2	0x32
50 #define ITHERM_CEV1	0x34
51 #define ITHERM_MGTV	0x58
52 #define ITHERM_PTV	0x60
53 #define ITHERM_DTV	0xAC
54 #define ITHERM_ITV	0xD8
55 
56 #define ITHERM_TEMP_READ_ENABLE	0xFF
57 #define ITHERM_TDR_ENABLE 0x1000
58 #define ITHERM_SECOND_CORE_ENABLE 0x8000
59 
60 #define ITHERM_TSE_ENABLE 0xB8
61 
62 #define ITHERM_CTV_INVALID	0x8000
63 #define ITHERM_CTV_INT_MASK	0x3FC0
64 #define ITHERM_CTV_FRAC_MASK	0x003F
65 
66 #define ITHERM_REFRESH_INTERVAL 5
67 
68 struct itherm_softc {
69 	struct device		sc_dev;
70 
71 	bus_addr_t		sc_addr;
72 	bus_space_tag_t		iot;
73 	bus_space_handle_t	ioh;
74 	bus_size_t		size;
75 
76 	int64_t			energy_prev;
77 
78 	struct ksensor sensors[ITHERM_NUM_SENSORS];
79 	struct ksensordev sensordev;
80 	void (*refresh_sensor_data)(struct itherm_softc *);
81 };
82 
83 #define IREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
84 #define IREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
85 #define IREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
86 #define IWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
87 #define IWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
88 
89 int  itherm_probe(struct device *, void *, void *);
90 void itherm_attach(struct device *, struct device *, void *);
91 void itherm_refresh(void *);
92 void itherm_enable(struct itherm_softc *);
93 void itherm_refresh_sensor_data(struct itherm_softc *);
94 int  itherm_activate(struct device *, int);
95 void itherm_bias_temperature_sensor(struct ksensor *);
96 
97 const struct pci_matchid itherm_devices[] = {
98 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_THERMAL }
99 };
100 
101 struct cfdriver itherm_cd = {
102 	NULL, "itherm", DV_DULL
103 };
104 
105 struct cfattach itherm_ca = {
106 	sizeof(struct itherm_softc), itherm_probe, itherm_attach, NULL,
107 	itherm_activate
108 };
109 
110 int
111 itherm_probe(struct device *parent, void *match, void *aux)
112 {
113 	return (pci_matchbyid((struct pci_attach_args *)aux, itherm_devices,
114 	    sizeof(itherm_devices)/sizeof(itherm_devices[0])));
115 }
116 
117 void
118 itherm_attach(struct device *parent, struct device *self, void *aux)
119 {
120 	struct itherm_softc *sc = (struct itherm_softc *)self;
121 	struct pci_attach_args *pa = aux;
122 	int i;
123 	pcireg_t v;
124 
125 	v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
126 	v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
127 	if (pci_mapreg_map(pa, PCI_MAPREG_START,
128 	    v, 0, &sc->iot, &sc->ioh, NULL, &sc->size, 0)) {
129 		printf(": can't map mem space\n");
130 		return;
131 	}
132 
133 	sc->sensors[ITHERM_SENSOR_THERMOMETER].type = SENSOR_TEMP;
134 	sc->sensors[ITHERM_SENSOR_CORETEMP1].type = SENSOR_TEMP;
135 	sc->sensors[ITHERM_SENSOR_CORETEMP2].type = SENSOR_TEMP;
136 	sc->sensors[ITHERM_SENSOR_COREENERGY].type = SENSOR_WATTS;
137 	sc->sensors[ITHERM_SENSOR_GPUTEMP].type = SENSOR_TEMP;
138 	sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].type = SENSOR_TEMP;
139 	sc->sensors[ITHERM_SENSOR_DIMMTEMP1].type = SENSOR_TEMP;
140 	sc->sensors[ITHERM_SENSOR_DIMMTEMP2].type = SENSOR_TEMP;
141 	sc->sensors[ITHERM_SENSOR_DIMMTEMP3].type = SENSOR_TEMP;
142 	sc->sensors[ITHERM_SENSOR_DIMMTEMP4].type = SENSOR_TEMP;
143 	sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].type = SENSOR_TEMP;
144 	sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].type = SENSOR_TEMP;
145 
146 	strlcpy(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc,
147 	    "Thermometer",
148 	    sizeof(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc));
149 
150 	strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc,
151 	    "Core 1",
152 	    sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc));
153 
154 	strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc,
155 	    "Core 2",
156 	    sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc));
157 
158 	strlcpy(sc->sensors[ITHERM_SENSOR_COREENERGY].desc,
159 	    "CPU power consumption",
160 	    sizeof(sc->sensors[ITHERM_SENSOR_COREENERGY].desc));
161 
162 	strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc,
163 	    "GPU/Memory Controller Temp",
164 	    sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc));
165 
166 	strlcpy(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc,
167 	    "CPU/GPU Max temp",
168 	    sizeof(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc));
169 
170 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc,
171 	    "DIMM 1",
172 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc));
173 
174 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc,
175 	    "DIMM 2",
176 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc));
177 
178 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc,
179 	    "DIMM 3",
180 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc));
181 
182 	strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc,
183 	    "DIMM 4",
184 	    sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc));
185 
186 	strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc,
187 	    "GPU/Memory controller abs.",
188 	    sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc));
189 
190 	strlcpy(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc,
191 	    "PCH abs.",
192 	    sizeof(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc));
193 
194 	strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
195 	    sizeof(sc->sensordev.xname));
196 
197 	itherm_enable(sc);
198 
199 	for (i=0; i < ITHERM_NUM_SENSORS; i++)
200 		sensor_attach(&sc->sensordev, &sc->sensors[i]);
201 
202 	sensordev_install(&sc->sensordev);
203 	sensor_task_register(sc, itherm_refresh, ITHERM_REFRESH_INTERVAL);
204 
205 	printf("\n");
206 
207 	return;
208 }
209 
210 void
211 itherm_enable(struct itherm_softc *sc)
212 {
213 	sc->energy_prev = 0;
214 
215 	/* Enable thermal sensor */
216 	IWRITE1(sc, ITHERM_TSE, ITHERM_TSE_ENABLE);
217 
218 	/* Enable thermal reporting */
219 	IWRITE2(sc, ITHERM_TRC, (ITHERM_TEMP_READ_ENABLE |
220 	    ITHERM_TDR_ENABLE | ITHERM_SECOND_CORE_ENABLE));
221 }
222 
223 int
224 itherm_activate(struct device *self, int act)
225 {
226 	struct itherm_softc *sc = (struct itherm_softc *)self;
227 
228 	switch (act) {
229 	case DVACT_RESUME:
230 		itherm_enable(sc);
231 	}
232 
233 	return (0);
234 }
235 
236 void
237 itherm_refresh_sensor_data(struct itherm_softc *sc)
238 {
239 	u_int16_t data;
240 	int64_t energy;
241 	u_int32_t i;
242 
243 	/* Thermometer sensor */
244 	sc->sensors[ITHERM_SENSOR_THERMOMETER].value =
245 	    IREAD1(sc, ITHERM_TSTR);
246 
247 	itherm_bias_temperature_sensor(
248 	    &sc->sensors[ITHERM_SENSOR_THERMOMETER]);
249 
250 	/*
251 	 * The Intel 3400 Thermal Sensor has separate sensors for each
252 	 * core, reported as a 16 bit value. Bits 13:6 are the integer
253 	 * part of the temperature in C and bits 5:0 are the fractional
254 	 * part of the temperature, in 1/64 degree C intervals.
255 	 * Bit 15 is used to indicate an invalid temperature
256 	 */
257 
258 	/* Core 1 temperature */
259     	data = IREAD2(sc, ITHERM_CTV1);
260 	if (data & ITHERM_CTV_INVALID)
261 		sc->sensors[ITHERM_SENSOR_CORETEMP1].flags |=
262 		   SENSOR_FINVALID;
263 	else {
264 		sc->sensors[ITHERM_SENSOR_CORETEMP1].flags &=
265 		    ~SENSOR_FINVALID;
266 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value =
267 		    (data & ITHERM_CTV_INT_MASK) >> 6;
268 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value *=
269 		    1000000;
270 		data &= ITHERM_CTV_FRAC_MASK;
271 		data *= 1000000 / 64;
272 		sc->sensors[ITHERM_SENSOR_CORETEMP1].value +=
273 		    data;
274 		itherm_bias_temperature_sensor(
275 		    &sc->sensors[ITHERM_SENSOR_CORETEMP1]);
276 	}
277 
278 	/* Core 2 temperature */
279     	data = IREAD2(sc, ITHERM_CTV2);
280 	if (data & ITHERM_CTV_INVALID)
281 		sc->sensors[ITHERM_SENSOR_CORETEMP2].flags |=
282 		   SENSOR_FINVALID;
283 	else {
284 		sc->sensors[ITHERM_SENSOR_CORETEMP2].flags &=
285 		    ~SENSOR_FINVALID;
286 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value =
287 		    (data & ITHERM_CTV_INT_MASK) >> 6;
288 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value *=
289 		    1000000;
290 		data &= ITHERM_CTV_FRAC_MASK;
291 		data *= 1000000 / 64;
292 		sc->sensors[ITHERM_SENSOR_CORETEMP2].value +=
293 		    data;
294 		itherm_bias_temperature_sensor(
295 		    &sc->sensors[ITHERM_SENSOR_CORETEMP2]);
296 	}
297 
298 	/*
299 	 * The core energy sensor reports the number of Joules
300 	 * of energy consumed by the processor since powerup.
301 	 * This number is scaled by 65535 and is continually
302 	 * increasing, so we save the old value and compute
303 	 * the difference for the Watt sensor value.
304 	 */
305 
306 	i = IREAD4(sc, ITHERM_CEV1);
307 	/* Convert to Joules per interval */
308 	energy = (i / 65535);
309 	energy = energy - sc->energy_prev;
310 	sc->energy_prev = (i / 65535);
311 	/* Convert to Joules per second */
312 	energy = energy / ITHERM_REFRESH_INTERVAL;
313 	/* Convert to micro Joules per second (micro Watts) */
314 	energy = energy * 1000 * 1000;
315 
316 	sc->sensors[ITHERM_SENSOR_COREENERGY].value = energy;
317 
318 	/*
319 	 * XXX - the GPU temp is reported as a 64 bit value with no
320 	 * documented structure. Disabled for now
321 	 */
322 	sc->sensors[ITHERM_SENSOR_GPUTEMP].flags |= SENSOR_FINVALID;
323 #if 0
324 	bus_space_read_multi_4(sc->iot, sc->ioh, ITHERM_MGTV,
325 	    (u_int32_t *)&sc->sensors[ITHERM_SENSOR_GPUTEMP].value, 2);
326 	sc->sensors[ITHERM_SENSOR_GPUTEMP].value *= 1000000;
327 	sc->sensors[ITHERM_SENSOR_GPUTEMP].value += 273150000;
328 #endif
329 
330 	/* Max processor temperature */
331 	sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].value =
332 	    IREAD1(sc, ITHERM_PTV) * 1000000;
333 	itherm_bias_temperature_sensor(
334 	    &sc->sensors[ITHERM_SENSOR_MAXPROCTEMP]);
335 
336 	/* DIMM 1 */
337 	sc->sensors[ITHERM_SENSOR_DIMMTEMP1].value =
338 	    IREAD1(sc, ITHERM_DTV) * 1000000;
339 	itherm_bias_temperature_sensor(
340 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP1]);
341 
342 	/* DIMM 2 */
343 	sc->sensors[ITHERM_SENSOR_DIMMTEMP2].value =
344 	    IREAD1(sc, ITHERM_DTV+1) * 1000000;
345 	itherm_bias_temperature_sensor(
346 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP2]);
347 
348 	/* DIMM 3 */
349 	sc->sensors[ITHERM_SENSOR_DIMMTEMP3].value =
350 	    IREAD1(sc, ITHERM_DTV+2) * 1000000;
351 	itherm_bias_temperature_sensor(
352 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP3]);
353 
354 	/* DIMM 4 */
355 	sc->sensors[ITHERM_SENSOR_DIMMTEMP4].value =
356 	    IREAD1(sc, ITHERM_DTV+3) * 1000000;
357 	itherm_bias_temperature_sensor(
358 	    &sc->sensors[ITHERM_SENSOR_DIMMTEMP4]);
359 
360 	/* GPU Temperature */
361 	sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].value =
362 	    IREAD1(sc, ITHERM_ITV+1) * 1000000;
363 	itherm_bias_temperature_sensor(
364 	    &sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE]);
365 
366 	/* PCH Temperature */
367 	sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].value =
368 	    IREAD1(sc, ITHERM_ITV) * 1000000;
369 	itherm_bias_temperature_sensor(
370 	    &sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE]);
371 }
372 
373 void
374 itherm_bias_temperature_sensor(struct ksensor *sensor)
375 {
376 	if (sensor->value == 0 || sensor->value == 0xff)
377 		sensor->flags |= SENSOR_FINVALID;
378 	else
379 		sensor->flags &= ~SENSOR_FINVALID;
380 
381 	/* Bias anyway from degC to degK, even if invalid */
382 	sensor->value += 273150000;
383 }
384 
385 void
386 itherm_refresh(void *arg)
387 {
388 	struct itherm_softc *sc = (struct itherm_softc *)arg;
389 
390 	itherm_refresh_sensor_data(sc);
391 }
392