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 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 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 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 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 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 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 391 itherm_refresh(void *arg) 392 { 393 struct itherm_softc *sc = (struct itherm_softc *)arg; 394 395 itherm_refresh_sensor_data(sc); 396 } 397