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