1 /*- 2 * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 3 * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 4 * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Driver for the AMD CPU on-die thermal sensors. 31 * Initially based on the k8temp Linux driver. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/conf.h> 40 #include <sys/kernel.h> 41 #include <sys/module.h> 42 #include <sys/sysctl.h> 43 #include <sys/systm.h> 44 45 #include <machine/cpufunc.h> 46 #include <machine/md_var.h> 47 #include <machine/specialreg.h> 48 49 #include <dev/pci/pcivar.h> 50 #include <x86/pci_cfgreg.h> 51 52 typedef enum { 53 CORE0_SENSOR0, 54 CORE0_SENSOR1, 55 CORE1_SENSOR0, 56 CORE1_SENSOR1, 57 CORE0, 58 CORE1 59 } amdsensor_t; 60 61 struct amdtemp_softc { 62 device_t sc_dev; 63 int sc_ncores; 64 int sc_ntemps; 65 int sc_flags; 66 #define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ 67 #define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ 68 #define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */ 69 int32_t sc_offset; 70 int32_t (*sc_gettemp)(device_t, amdsensor_t); 71 struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 72 struct intr_config_hook sc_ich; 73 }; 74 75 #define VENDORID_AMD 0x1022 76 #define DEVICEID_AMD_MISC0F 0x1103 77 #define DEVICEID_AMD_MISC10 0x1203 78 #define DEVICEID_AMD_MISC11 0x1303 79 #define DEVICEID_AMD_MISC14 0x1703 80 #define DEVICEID_AMD_MISC15 0x1603 81 82 static struct amdtemp_product { 83 uint16_t amdtemp_vendorid; 84 uint16_t amdtemp_deviceid; 85 } amdtemp_products[] = { 86 { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 87 { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 88 { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 89 { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 90 { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 91 { 0, 0 } 92 }; 93 94 /* 95 * Reported Temperature Control Register 96 */ 97 #define AMDTEMP_REPTMP_CTRL 0xa4 98 99 /* 100 * Thermaltrip Status Register (Family 0Fh only) 101 */ 102 #define AMDTEMP_THERMTP_STAT 0xe4 103 #define AMDTEMP_TTSR_SELCORE 0x04 104 #define AMDTEMP_TTSR_SELSENSOR 0x40 105 106 /* 107 * DRAM Configuration High Register 108 */ 109 #define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 110 #define AMDTEMP_DRAM_MODE_DDR3 0x0100 111 112 /* 113 * CPU Family/Model Register 114 */ 115 #define AMDTEMP_CPUID 0xfc 116 117 /* 118 * Device methods. 119 */ 120 static void amdtemp_identify(driver_t *driver, device_t parent); 121 static int amdtemp_probe(device_t dev); 122 static int amdtemp_attach(device_t dev); 123 static void amdtemp_intrhook(void *arg); 124 static int amdtemp_detach(device_t dev); 125 static int amdtemp_match(device_t dev); 126 static int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 127 static int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 128 static int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 129 130 static device_method_t amdtemp_methods[] = { 131 /* Device interface */ 132 DEVMETHOD(device_identify, amdtemp_identify), 133 DEVMETHOD(device_probe, amdtemp_probe), 134 DEVMETHOD(device_attach, amdtemp_attach), 135 DEVMETHOD(device_detach, amdtemp_detach), 136 137 DEVMETHOD_END 138 }; 139 140 static driver_t amdtemp_driver = { 141 "amdtemp", 142 amdtemp_methods, 143 sizeof(struct amdtemp_softc), 144 }; 145 146 static devclass_t amdtemp_devclass; 147 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 148 149 static int 150 amdtemp_match(device_t dev) 151 { 152 int i; 153 uint16_t vendor, devid; 154 155 vendor = pci_get_vendor(dev); 156 devid = pci_get_device(dev); 157 158 for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 159 if (vendor == amdtemp_products[i].amdtemp_vendorid && 160 devid == amdtemp_products[i].amdtemp_deviceid) 161 return (1); 162 } 163 164 return (0); 165 } 166 167 static void 168 amdtemp_identify(driver_t *driver, device_t parent) 169 { 170 device_t child; 171 172 /* Make sure we're not being doubly invoked. */ 173 if (device_find_child(parent, "amdtemp", -1) != NULL) 174 return; 175 176 if (amdtemp_match(parent)) { 177 child = device_add_child(parent, "amdtemp", -1); 178 if (child == NULL) 179 device_printf(parent, "add amdtemp child failed\n"); 180 } 181 } 182 183 static int 184 amdtemp_probe(device_t dev) 185 { 186 uint32_t family, model; 187 188 if (resource_disabled("amdtemp", 0)) 189 return (ENXIO); 190 191 family = CPUID_TO_FAMILY(cpu_id); 192 model = CPUID_TO_MODEL(cpu_id); 193 194 switch (family) { 195 case 0x0f: 196 if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 197 (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 198 return (ENXIO); 199 break; 200 case 0x10: 201 case 0x11: 202 case 0x12: 203 case 0x14: 204 case 0x15: 205 break; 206 default: 207 return (ENXIO); 208 } 209 device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 210 211 return (BUS_PROBE_GENERIC); 212 } 213 214 static int 215 amdtemp_attach(device_t dev) 216 { 217 char tn[32]; 218 u_int regs[4]; 219 struct amdtemp_softc *sc = device_get_softc(dev); 220 struct sysctl_ctx_list *sysctlctx; 221 struct sysctl_oid *sysctlnode; 222 uint32_t cpuid, family, model; 223 u_int bid; 224 int erratum319, unit; 225 226 erratum319 = 0; 227 228 /* 229 * CPUID Register is available from Revision F. 230 */ 231 cpuid = cpu_id; 232 family = CPUID_TO_FAMILY(cpuid); 233 model = CPUID_TO_MODEL(cpuid); 234 if (family != 0x0f || model >= 0x40) { 235 cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 236 family = CPUID_TO_FAMILY(cpuid); 237 model = CPUID_TO_MODEL(cpuid); 238 } 239 240 switch (family) { 241 case 0x0f: 242 /* 243 * Thermaltrip Status Register 244 * 245 * - ThermSenseCoreSel 246 * 247 * Revision F & G: 0 - Core1, 1 - Core0 248 * Other: 0 - Core0, 1 - Core1 249 * 250 * - CurTmp 251 * 252 * Revision G: bits 23-14 253 * Other: bits 23-16 254 * 255 * XXX According to the BKDG, CurTmp, ThermSenseSel and 256 * ThermSenseCoreSel bits were introduced in Revision F 257 * but CurTmp seems working fine as early as Revision C. 258 * However, it is not clear whether ThermSenseSel and/or 259 * ThermSenseCoreSel work in undocumented cases as well. 260 * In fact, the Linux driver suggests it may not work but 261 * we just assume it does until we find otherwise. 262 * 263 * XXX According to Linux, CurTmp starts at -28C on 264 * Socket AM2 Revision G processors, which is not 265 * documented anywhere. 266 */ 267 if (model >= 0x40) 268 sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 269 if (model >= 0x60 && model != 0xc1) { 270 do_cpuid(0x80000001, regs); 271 bid = (regs[1] >> 9) & 0x1f; 272 switch (model) { 273 case 0x68: /* Socket S1g1 */ 274 case 0x6c: 275 case 0x7c: 276 break; 277 case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ 278 if (bid != 0x0b && bid != 0x0c) 279 sc->sc_flags |= 280 AMDTEMP_FLAG_ALT_OFFSET; 281 break; 282 case 0x6f: /* Socket AM2 and ASB1 (1 core) */ 283 case 0x7f: 284 if (bid != 0x07 && bid != 0x09 && 285 bid != 0x0c) 286 sc->sc_flags |= 287 AMDTEMP_FLAG_ALT_OFFSET; 288 break; 289 default: 290 sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; 291 } 292 sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 293 } 294 295 /* 296 * There are two sensors per core. 297 */ 298 sc->sc_ntemps = 2; 299 300 sc->sc_gettemp = amdtemp_gettemp0f; 301 break; 302 case 0x10: 303 /* 304 * Erratum 319 Inaccurate Temperature Measurement 305 * 306 * http://support.amd.com/us/Processor_TechDocs/41322.pdf 307 */ 308 do_cpuid(0x80000001, regs); 309 switch ((regs[1] >> 28) & 0xf) { 310 case 0: /* Socket F */ 311 erratum319 = 1; 312 break; 313 case 1: /* Socket AM2+ or AM3 */ 314 if ((pci_cfgregread(pci_get_bus(dev), 315 pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & 316 AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || 317 (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) 318 break; 319 /* XXX 00100F42h (RB-C2) exists in both formats. */ 320 erratum319 = 1; 321 break; 322 } 323 /* FALLTHROUGH */ 324 case 0x11: 325 case 0x12: 326 case 0x14: 327 case 0x15: 328 /* 329 * There is only one sensor per package. 330 */ 331 sc->sc_ntemps = 1; 332 333 sc->sc_gettemp = amdtemp_gettemp; 334 break; 335 } 336 337 /* Find number of cores per package. */ 338 sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 339 (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 340 if (sc->sc_ncores > MAXCPU) 341 return (ENXIO); 342 343 if (erratum319) 344 device_printf(dev, 345 "Erratum 319: temperature measurement may be inaccurate\n"); 346 if (bootverbose) 347 device_printf(dev, "Found %d cores and %d sensors.\n", 348 sc->sc_ncores, 349 sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 350 351 /* 352 * dev.amdtemp.N tree. 353 */ 354 unit = device_get_unit(dev); 355 snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); 356 TUNABLE_INT_FETCH(tn, &sc->sc_offset); 357 358 sysctlctx = device_get_sysctl_ctx(dev); 359 SYSCTL_ADD_INT(sysctlctx, 360 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 361 "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, 362 "Temperature sensor offset"); 363 sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 364 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 365 "core0", CTLFLAG_RD, 0, "Core 0"); 366 367 SYSCTL_ADD_PROC(sysctlctx, 368 SYSCTL_CHILDREN(sysctlnode), 369 OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 370 dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", 371 "Core 0 / Sensor 0 temperature"); 372 373 if (sc->sc_ntemps > 1) { 374 SYSCTL_ADD_PROC(sysctlctx, 375 SYSCTL_CHILDREN(sysctlnode), 376 OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 377 dev, CORE0_SENSOR1, amdtemp_sysctl, "IK", 378 "Core 0 / Sensor 1 temperature"); 379 380 if (sc->sc_ncores > 1) { 381 sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 382 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 383 OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1"); 384 385 SYSCTL_ADD_PROC(sysctlctx, 386 SYSCTL_CHILDREN(sysctlnode), 387 OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 388 dev, CORE1_SENSOR0, amdtemp_sysctl, "IK", 389 "Core 1 / Sensor 0 temperature"); 390 391 SYSCTL_ADD_PROC(sysctlctx, 392 SYSCTL_CHILDREN(sysctlnode), 393 OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 394 dev, CORE1_SENSOR1, amdtemp_sysctl, "IK", 395 "Core 1 / Sensor 1 temperature"); 396 } 397 } 398 399 /* 400 * Try to create dev.cpu sysctl entries and setup intrhook function. 401 * This is needed because the cpu driver may be loaded late on boot, 402 * after us. 403 */ 404 amdtemp_intrhook(dev); 405 sc->sc_ich.ich_func = amdtemp_intrhook; 406 sc->sc_ich.ich_arg = dev; 407 if (config_intrhook_establish(&sc->sc_ich) != 0) { 408 device_printf(dev, "config_intrhook_establish failed!\n"); 409 return (ENXIO); 410 } 411 412 return (0); 413 } 414 415 void 416 amdtemp_intrhook(void *arg) 417 { 418 struct amdtemp_softc *sc; 419 struct sysctl_ctx_list *sysctlctx; 420 device_t dev = (device_t)arg; 421 device_t acpi, cpu, nexus; 422 amdsensor_t sensor; 423 int i; 424 425 sc = device_get_softc(dev); 426 427 /* 428 * dev.cpu.N.temperature. 429 */ 430 nexus = device_find_child(root_bus, "nexus", 0); 431 acpi = device_find_child(nexus, "acpi", 0); 432 433 for (i = 0; i < sc->sc_ncores; i++) { 434 if (sc->sc_sysctl_cpu[i] != NULL) 435 continue; 436 cpu = device_find_child(acpi, "cpu", 437 device_get_unit(dev) * sc->sc_ncores + i); 438 if (cpu != NULL) { 439 sysctlctx = device_get_sysctl_ctx(cpu); 440 441 sensor = sc->sc_ntemps > 1 ? 442 (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; 443 sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 444 SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 445 OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 446 dev, sensor, amdtemp_sysctl, "IK", 447 "Current temparature"); 448 } 449 } 450 if (sc->sc_ich.ich_arg != NULL) 451 config_intrhook_disestablish(&sc->sc_ich); 452 } 453 454 int 455 amdtemp_detach(device_t dev) 456 { 457 struct amdtemp_softc *sc = device_get_softc(dev); 458 int i; 459 460 for (i = 0; i < sc->sc_ncores; i++) 461 if (sc->sc_sysctl_cpu[i] != NULL) 462 sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 463 464 /* NewBus removes the dev.amdtemp.N tree by itself. */ 465 466 return (0); 467 } 468 469 static int 470 amdtemp_sysctl(SYSCTL_HANDLER_ARGS) 471 { 472 device_t dev = (device_t)arg1; 473 struct amdtemp_softc *sc = device_get_softc(dev); 474 amdsensor_t sensor = (amdsensor_t)arg2; 475 int32_t auxtemp[2], temp; 476 int error; 477 478 switch (sensor) { 479 case CORE0: 480 auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); 481 auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); 482 temp = imax(auxtemp[0], auxtemp[1]); 483 break; 484 case CORE1: 485 auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); 486 auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); 487 temp = imax(auxtemp[0], auxtemp[1]); 488 break; 489 default: 490 temp = sc->sc_gettemp(dev, sensor); 491 break; 492 } 493 error = sysctl_handle_int(oidp, &temp, 0, req); 494 495 return (error); 496 } 497 498 #define AMDTEMP_ZERO_C_TO_K 2732 499 500 static int32_t 501 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 502 { 503 struct amdtemp_softc *sc = device_get_softc(dev); 504 uint32_t mask, offset, temp; 505 506 /* Set Sensor/Core selector. */ 507 temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 508 temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); 509 switch (sensor) { 510 case CORE0_SENSOR1: 511 temp |= AMDTEMP_TTSR_SELSENSOR; 512 /* FALLTHROUGH */ 513 case CORE0_SENSOR0: 514 case CORE0: 515 if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 516 temp |= AMDTEMP_TTSR_SELCORE; 517 break; 518 case CORE1_SENSOR1: 519 temp |= AMDTEMP_TTSR_SELSENSOR; 520 /* FALLTHROUGH */ 521 case CORE1_SENSOR0: 522 case CORE1: 523 if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 524 temp |= AMDTEMP_TTSR_SELCORE; 525 break; 526 } 527 pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); 528 529 mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 530 offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; 531 temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 532 temp = ((temp >> 14) & mask) * 5 / 2; 533 temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; 534 535 return (temp); 536 } 537 538 static int32_t 539 amdtemp_gettemp(device_t dev, amdsensor_t sensor) 540 { 541 struct amdtemp_softc *sc = device_get_softc(dev); 542 uint32_t temp; 543 544 temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 545 temp = ((temp >> 21) & 0x7ff) * 5 / 4; 546 temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; 547 548 return (temp); 549 } 550