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 const struct cfattach itherm_ca = {
110 sizeof(struct itherm_softc), itherm_probe, itherm_attach, NULL,
111 itherm_activate
112 };
113
114 int
itherm_probe(struct device * parent,void * match,void * aux)115 itherm_probe(struct device *parent, void *match, void *aux)
116 {
117 return (pci_matchbyid((struct pci_attach_args *)aux, itherm_devices,
118 sizeof(itherm_devices)/sizeof(itherm_devices[0])));
119 }
120
121 void
itherm_attach(struct device * parent,struct device * self,void * aux)122 itherm_attach(struct device *parent, struct device *self, void *aux)
123 {
124 struct itherm_softc *sc = (struct itherm_softc *)self;
125 struct pci_attach_args *pa = aux;
126 int i;
127 pcireg_t v;
128
129 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
130 v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
131 if (pci_mapreg_map(pa, PCI_MAPREG_START,
132 v, 0, &sc->iot, &sc->ioh, NULL, &sc->size, 0)) {
133 printf(": can't map mem space\n");
134 return;
135 }
136
137 sc->sensors[ITHERM_SENSOR_THERMOMETER].type = SENSOR_TEMP;
138 sc->sensors[ITHERM_SENSOR_CORETEMP1].type = SENSOR_TEMP;
139 sc->sensors[ITHERM_SENSOR_CORETEMP2].type = SENSOR_TEMP;
140 sc->sensors[ITHERM_SENSOR_COREENERGY].type = SENSOR_WATTS;
141 sc->sensors[ITHERM_SENSOR_GPUTEMP].type = SENSOR_TEMP;
142 sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].type = SENSOR_TEMP;
143 sc->sensors[ITHERM_SENSOR_DIMMTEMP1].type = SENSOR_TEMP;
144 sc->sensors[ITHERM_SENSOR_DIMMTEMP2].type = SENSOR_TEMP;
145 sc->sensors[ITHERM_SENSOR_DIMMTEMP3].type = SENSOR_TEMP;
146 sc->sensors[ITHERM_SENSOR_DIMMTEMP4].type = SENSOR_TEMP;
147 sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].type = SENSOR_TEMP;
148 sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].type = SENSOR_TEMP;
149
150 strlcpy(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc,
151 "Thermometer",
152 sizeof(sc->sensors[ITHERM_SENSOR_THERMOMETER].desc));
153
154 strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc,
155 "Core 1",
156 sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP1].desc));
157
158 strlcpy(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc,
159 "Core 2",
160 sizeof(sc->sensors[ITHERM_SENSOR_CORETEMP2].desc));
161
162 strlcpy(sc->sensors[ITHERM_SENSOR_COREENERGY].desc,
163 "CPU power consumption",
164 sizeof(sc->sensors[ITHERM_SENSOR_COREENERGY].desc));
165
166 strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc,
167 "GPU/Memory Controller Temp",
168 sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP].desc));
169
170 strlcpy(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc,
171 "CPU/GPU Max temp",
172 sizeof(sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].desc));
173
174 strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc,
175 "DIMM 1",
176 sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP1].desc));
177
178 strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc,
179 "DIMM 2",
180 sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP2].desc));
181
182 strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc,
183 "DIMM 3",
184 sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP3].desc));
185
186 strlcpy(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc,
187 "DIMM 4",
188 sizeof(sc->sensors[ITHERM_SENSOR_DIMMTEMP4].desc));
189
190 strlcpy(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc,
191 "GPU/Memory controller abs.",
192 sizeof(sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].desc));
193
194 strlcpy(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc,
195 "PCH abs.",
196 sizeof(sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].desc));
197
198 strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
199 sizeof(sc->sensordev.xname));
200
201 itherm_enable(sc);
202
203 for (i = 0; i < ITHERM_NUM_SENSORS; i++)
204 sensor_attach(&sc->sensordev, &sc->sensors[i]);
205
206 sensordev_install(&sc->sensordev);
207 sensor_task_register(sc, itherm_refresh, ITHERM_REFRESH_INTERVAL);
208
209 printf("\n");
210
211 return;
212 }
213
214 void
itherm_enable(struct itherm_softc * sc)215 itherm_enable(struct itherm_softc *sc)
216 {
217 sc->energy_prev = 0;
218
219 /* Enable thermal sensor */
220 IWRITE1(sc, ITHERM_TSE, ITHERM_TSE_ENABLE);
221
222 /* Enable thermal reporting */
223 IWRITE2(sc, ITHERM_TRC, (ITHERM_TEMP_READ_ENABLE |
224 ITHERM_TDR_ENABLE | ITHERM_SECOND_CORE_ENABLE));
225 }
226
227 int
itherm_activate(struct device * self,int act)228 itherm_activate(struct device *self, int act)
229 {
230 struct itherm_softc *sc = (struct itherm_softc *)self;
231
232 switch (act) {
233 case DVACT_RESUME:
234 itherm_enable(sc);
235 break;
236 }
237
238 return (0);
239 }
240
241 void
itherm_refresh_sensor_data(struct itherm_softc * sc)242 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 sc->sensors[ITHERM_SENSOR_THERMOMETER].value =
250 IREAD1(sc, ITHERM_TSTR);
251
252 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 data = IREAD2(sc, ITHERM_CTV1);
265 if (data & ITHERM_CTV_INVALID)
266 sc->sensors[ITHERM_SENSOR_CORETEMP1].flags |=
267 SENSOR_FINVALID;
268 else {
269 sc->sensors[ITHERM_SENSOR_CORETEMP1].flags &=
270 ~SENSOR_FINVALID;
271 sc->sensors[ITHERM_SENSOR_CORETEMP1].value =
272 (data & ITHERM_CTV_INT_MASK) >> 6;
273 sc->sensors[ITHERM_SENSOR_CORETEMP1].value *=
274 1000000;
275 data &= ITHERM_CTV_FRAC_MASK;
276 data *= 1000000 / 64;
277 sc->sensors[ITHERM_SENSOR_CORETEMP1].value +=
278 data;
279 itherm_bias_temperature_sensor(
280 &sc->sensors[ITHERM_SENSOR_CORETEMP1]);
281 }
282
283 /* Core 2 temperature */
284 data = IREAD2(sc, ITHERM_CTV2);
285 if (data & ITHERM_CTV_INVALID)
286 sc->sensors[ITHERM_SENSOR_CORETEMP2].flags |=
287 SENSOR_FINVALID;
288 else {
289 sc->sensors[ITHERM_SENSOR_CORETEMP2].flags &=
290 ~SENSOR_FINVALID;
291 sc->sensors[ITHERM_SENSOR_CORETEMP2].value =
292 (data & ITHERM_CTV_INT_MASK) >> 6;
293 sc->sensors[ITHERM_SENSOR_CORETEMP2].value *=
294 1000000;
295 data &= ITHERM_CTV_FRAC_MASK;
296 data *= 1000000 / 64;
297 sc->sensors[ITHERM_SENSOR_CORETEMP2].value +=
298 data;
299 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 i = IREAD4(sc, ITHERM_CEV1);
312 /* Convert to Joules per interval */
313 energy = (i / 65535);
314 energy = energy - sc->energy_prev;
315 sc->energy_prev = (i / 65535);
316 /* Convert to Joules per second */
317 energy = energy / ITHERM_REFRESH_INTERVAL;
318 /* Convert to micro Joules per second (micro Watts) */
319 energy = energy * 1000 * 1000;
320
321 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 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 sc->sensors[ITHERM_SENSOR_MAXPROCTEMP].value =
337 IREAD1(sc, ITHERM_PTV) * 1000000;
338 itherm_bias_temperature_sensor(
339 &sc->sensors[ITHERM_SENSOR_MAXPROCTEMP]);
340
341 /* DIMM 1 */
342 sc->sensors[ITHERM_SENSOR_DIMMTEMP1].value =
343 IREAD1(sc, ITHERM_DTV) * 1000000;
344 itherm_bias_temperature_sensor(
345 &sc->sensors[ITHERM_SENSOR_DIMMTEMP1]);
346
347 /* DIMM 2 */
348 sc->sensors[ITHERM_SENSOR_DIMMTEMP2].value =
349 IREAD1(sc, ITHERM_DTV+1) * 1000000;
350 itherm_bias_temperature_sensor(
351 &sc->sensors[ITHERM_SENSOR_DIMMTEMP2]);
352
353 /* DIMM 3 */
354 sc->sensors[ITHERM_SENSOR_DIMMTEMP3].value =
355 IREAD1(sc, ITHERM_DTV+2) * 1000000;
356 itherm_bias_temperature_sensor(
357 &sc->sensors[ITHERM_SENSOR_DIMMTEMP3]);
358
359 /* DIMM 4 */
360 sc->sensors[ITHERM_SENSOR_DIMMTEMP4].value =
361 IREAD1(sc, ITHERM_DTV+3) * 1000000;
362 itherm_bias_temperature_sensor(
363 &sc->sensors[ITHERM_SENSOR_DIMMTEMP4]);
364
365 /* GPU Temperature */
366 sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE].value =
367 IREAD1(sc, ITHERM_ITV+1) * 1000000;
368 itherm_bias_temperature_sensor(
369 &sc->sensors[ITHERM_SENSOR_GPUTEMP_ABSOLUTE]);
370
371 /* PCH Temperature */
372 sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE].value =
373 IREAD1(sc, ITHERM_ITV) * 1000000;
374 itherm_bias_temperature_sensor(
375 &sc->sensors[ITHERM_SENSOR_PCHTEMP_ABSOLUTE]);
376 }
377
378 void
itherm_bias_temperature_sensor(struct ksensor * sensor)379 itherm_bias_temperature_sensor(struct ksensor *sensor)
380 {
381 if (sensor->value == 0 || sensor->value == 0xff)
382 sensor->flags |= SENSOR_FINVALID;
383 else
384 sensor->flags &= ~SENSOR_FINVALID;
385
386 /* Bias anyway from degC to degK, even if invalid */
387 sensor->value += 273150000;
388 }
389
390 void
itherm_refresh(void * arg)391 itherm_refresh(void *arg)
392 {
393 struct itherm_softc *sc = (struct itherm_softc *)arg;
394
395 itherm_refresh_sensor_data(sc);
396 }
397