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_MISC12 0x1403 80 #define DEVICEID_AMD_MISC14 0x1703 81 #define DEVICEID_AMD_MISC15 0x1603 82 #define DEVICEID_AMD_MISC16 0x1533 83 #define DEVICEID_AMD_MISC16_M30H 0x1583 84 #define DEVICEID_AMD_MISC17 0x141d 85 86 static struct amdtemp_product { 87 uint16_t amdtemp_vendorid; 88 uint16_t amdtemp_deviceid; 89 } amdtemp_products[] = { 90 { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 91 { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 92 { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 93 { VENDORID_AMD, DEVICEID_AMD_MISC12 }, 94 { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 95 { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 96 { VENDORID_AMD, DEVICEID_AMD_MISC16 }, 97 { VENDORID_AMD, DEVICEID_AMD_MISC16_M30H }, 98 { VENDORID_AMD, DEVICEID_AMD_MISC17 }, 99 { 0, 0 } 100 }; 101 102 /* 103 * Reported Temperature Control Register 104 */ 105 #define AMDTEMP_REPTMP_CTRL 0xa4 106 107 /* 108 * Thermaltrip Status Register (Family 0Fh only) 109 */ 110 #define AMDTEMP_THERMTP_STAT 0xe4 111 #define AMDTEMP_TTSR_SELCORE 0x04 112 #define AMDTEMP_TTSR_SELSENSOR 0x40 113 114 /* 115 * DRAM Configuration High Register 116 */ 117 #define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 118 #define AMDTEMP_DRAM_MODE_DDR3 0x0100 119 120 /* 121 * CPU Family/Model Register 122 */ 123 #define AMDTEMP_CPUID 0xfc 124 125 /* 126 * Device methods. 127 */ 128 static void amdtemp_identify(driver_t *driver, device_t parent); 129 static int amdtemp_probe(device_t dev); 130 static int amdtemp_attach(device_t dev); 131 static void amdtemp_intrhook(void *arg); 132 static int amdtemp_detach(device_t dev); 133 static int amdtemp_match(device_t dev); 134 static int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 135 static int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 136 static int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 137 138 static device_method_t amdtemp_methods[] = { 139 /* Device interface */ 140 DEVMETHOD(device_identify, amdtemp_identify), 141 DEVMETHOD(device_probe, amdtemp_probe), 142 DEVMETHOD(device_attach, amdtemp_attach), 143 DEVMETHOD(device_detach, amdtemp_detach), 144 145 DEVMETHOD_END 146 }; 147 148 static driver_t amdtemp_driver = { 149 "amdtemp", 150 amdtemp_methods, 151 sizeof(struct amdtemp_softc), 152 }; 153 154 static devclass_t amdtemp_devclass; 155 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 156 157 static int 158 amdtemp_match(device_t dev) 159 { 160 int i; 161 uint16_t vendor, devid; 162 163 vendor = pci_get_vendor(dev); 164 devid = pci_get_device(dev); 165 166 for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 167 if (vendor == amdtemp_products[i].amdtemp_vendorid && 168 devid == amdtemp_products[i].amdtemp_deviceid) 169 return (1); 170 } 171 172 return (0); 173 } 174 175 static void 176 amdtemp_identify(driver_t *driver, device_t parent) 177 { 178 device_t child; 179 180 /* Make sure we're not being doubly invoked. */ 181 if (device_find_child(parent, "amdtemp", -1) != NULL) 182 return; 183 184 if (amdtemp_match(parent)) { 185 child = device_add_child(parent, "amdtemp", -1); 186 if (child == NULL) 187 device_printf(parent, "add amdtemp child failed\n"); 188 } 189 } 190 191 static int 192 amdtemp_probe(device_t dev) 193 { 194 uint32_t family, model; 195 196 if (resource_disabled("amdtemp", 0)) 197 return (ENXIO); 198 199 family = CPUID_TO_FAMILY(cpu_id); 200 model = CPUID_TO_MODEL(cpu_id); 201 202 switch (family) { 203 case 0x0f: 204 if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 205 (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 206 return (ENXIO); 207 break; 208 case 0x10: 209 case 0x11: 210 case 0x12: 211 case 0x14: 212 case 0x15: 213 case 0x16: 214 break; 215 default: 216 return (ENXIO); 217 } 218 device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 219 220 return (BUS_PROBE_GENERIC); 221 } 222 223 static int 224 amdtemp_attach(device_t dev) 225 { 226 char tn[32]; 227 u_int regs[4]; 228 struct amdtemp_softc *sc = device_get_softc(dev); 229 struct sysctl_ctx_list *sysctlctx; 230 struct sysctl_oid *sysctlnode; 231 uint32_t cpuid, family, model; 232 u_int bid; 233 int erratum319, unit; 234 235 erratum319 = 0; 236 237 /* 238 * CPUID Register is available from Revision F. 239 */ 240 cpuid = cpu_id; 241 family = CPUID_TO_FAMILY(cpuid); 242 model = CPUID_TO_MODEL(cpuid); 243 if (family != 0x0f || model >= 0x40) { 244 cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 245 family = CPUID_TO_FAMILY(cpuid); 246 model = CPUID_TO_MODEL(cpuid); 247 } 248 249 switch (family) { 250 case 0x0f: 251 /* 252 * Thermaltrip Status Register 253 * 254 * - ThermSenseCoreSel 255 * 256 * Revision F & G: 0 - Core1, 1 - Core0 257 * Other: 0 - Core0, 1 - Core1 258 * 259 * - CurTmp 260 * 261 * Revision G: bits 23-14 262 * Other: bits 23-16 263 * 264 * XXX According to the BKDG, CurTmp, ThermSenseSel and 265 * ThermSenseCoreSel bits were introduced in Revision F 266 * but CurTmp seems working fine as early as Revision C. 267 * However, it is not clear whether ThermSenseSel and/or 268 * ThermSenseCoreSel work in undocumented cases as well. 269 * In fact, the Linux driver suggests it may not work but 270 * we just assume it does until we find otherwise. 271 * 272 * XXX According to Linux, CurTmp starts at -28C on 273 * Socket AM2 Revision G processors, which is not 274 * documented anywhere. 275 */ 276 if (model >= 0x40) 277 sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 278 if (model >= 0x60 && model != 0xc1) { 279 do_cpuid(0x80000001, regs); 280 bid = (regs[1] >> 9) & 0x1f; 281 switch (model) { 282 case 0x68: /* Socket S1g1 */ 283 case 0x6c: 284 case 0x7c: 285 break; 286 case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ 287 if (bid != 0x0b && bid != 0x0c) 288 sc->sc_flags |= 289 AMDTEMP_FLAG_ALT_OFFSET; 290 break; 291 case 0x6f: /* Socket AM2 and ASB1 (1 core) */ 292 case 0x7f: 293 if (bid != 0x07 && bid != 0x09 && 294 bid != 0x0c) 295 sc->sc_flags |= 296 AMDTEMP_FLAG_ALT_OFFSET; 297 break; 298 default: 299 sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; 300 } 301 sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 302 } 303 304 /* 305 * There are two sensors per core. 306 */ 307 sc->sc_ntemps = 2; 308 309 sc->sc_gettemp = amdtemp_gettemp0f; 310 break; 311 case 0x10: 312 /* 313 * Erratum 319 Inaccurate Temperature Measurement 314 * 315 * http://support.amd.com/us/Processor_TechDocs/41322.pdf 316 */ 317 do_cpuid(0x80000001, regs); 318 switch ((regs[1] >> 28) & 0xf) { 319 case 0: /* Socket F */ 320 erratum319 = 1; 321 break; 322 case 1: /* Socket AM2+ or AM3 */ 323 if ((pci_cfgregread(pci_get_bus(dev), 324 pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & 325 AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || 326 (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) 327 break; 328 /* XXX 00100F42h (RB-C2) exists in both formats. */ 329 erratum319 = 1; 330 break; 331 } 332 /* FALLTHROUGH */ 333 case 0x11: 334 case 0x12: 335 case 0x14: 336 case 0x15: 337 case 0x16: 338 /* 339 * There is only one sensor per package. 340 */ 341 sc->sc_ntemps = 1; 342 343 sc->sc_gettemp = amdtemp_gettemp; 344 break; 345 } 346 347 /* Find number of cores per package. */ 348 sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 349 (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 350 if (sc->sc_ncores > MAXCPU) 351 return (ENXIO); 352 353 if (erratum319) 354 device_printf(dev, 355 "Erratum 319: temperature measurement may be inaccurate\n"); 356 if (bootverbose) 357 device_printf(dev, "Found %d cores and %d sensors.\n", 358 sc->sc_ncores, 359 sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 360 361 /* 362 * dev.amdtemp.N tree. 363 */ 364 unit = device_get_unit(dev); 365 snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); 366 TUNABLE_INT_FETCH(tn, &sc->sc_offset); 367 368 sysctlctx = device_get_sysctl_ctx(dev); 369 SYSCTL_ADD_INT(sysctlctx, 370 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 371 "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, 372 "Temperature sensor offset"); 373 sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 374 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 375 "core0", CTLFLAG_RD, 0, "Core 0"); 376 377 SYSCTL_ADD_PROC(sysctlctx, 378 SYSCTL_CHILDREN(sysctlnode), 379 OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 380 dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", 381 "Core 0 / Sensor 0 temperature"); 382 383 if (sc->sc_ntemps > 1) { 384 SYSCTL_ADD_PROC(sysctlctx, 385 SYSCTL_CHILDREN(sysctlnode), 386 OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 387 dev, CORE0_SENSOR1, amdtemp_sysctl, "IK", 388 "Core 0 / Sensor 1 temperature"); 389 390 if (sc->sc_ncores > 1) { 391 sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 392 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 393 OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1"); 394 395 SYSCTL_ADD_PROC(sysctlctx, 396 SYSCTL_CHILDREN(sysctlnode), 397 OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 398 dev, CORE1_SENSOR0, amdtemp_sysctl, "IK", 399 "Core 1 / Sensor 0 temperature"); 400 401 SYSCTL_ADD_PROC(sysctlctx, 402 SYSCTL_CHILDREN(sysctlnode), 403 OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 404 dev, CORE1_SENSOR1, amdtemp_sysctl, "IK", 405 "Core 1 / Sensor 1 temperature"); 406 } 407 } 408 409 /* 410 * Try to create dev.cpu sysctl entries and setup intrhook function. 411 * This is needed because the cpu driver may be loaded late on boot, 412 * after us. 413 */ 414 amdtemp_intrhook(dev); 415 sc->sc_ich.ich_func = amdtemp_intrhook; 416 sc->sc_ich.ich_arg = dev; 417 if (config_intrhook_establish(&sc->sc_ich) != 0) { 418 device_printf(dev, "config_intrhook_establish failed!\n"); 419 return (ENXIO); 420 } 421 422 return (0); 423 } 424 425 void 426 amdtemp_intrhook(void *arg) 427 { 428 struct amdtemp_softc *sc; 429 struct sysctl_ctx_list *sysctlctx; 430 device_t dev = (device_t)arg; 431 device_t acpi, cpu, nexus; 432 amdsensor_t sensor; 433 int i; 434 435 sc = device_get_softc(dev); 436 437 /* 438 * dev.cpu.N.temperature. 439 */ 440 nexus = device_find_child(root_bus, "nexus", 0); 441 acpi = device_find_child(nexus, "acpi", 0); 442 443 for (i = 0; i < sc->sc_ncores; i++) { 444 if (sc->sc_sysctl_cpu[i] != NULL) 445 continue; 446 cpu = device_find_child(acpi, "cpu", 447 device_get_unit(dev) * sc->sc_ncores + i); 448 if (cpu != NULL) { 449 sysctlctx = device_get_sysctl_ctx(cpu); 450 451 sensor = sc->sc_ntemps > 1 ? 452 (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; 453 sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 454 SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 455 OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 456 dev, sensor, amdtemp_sysctl, "IK", 457 "Current temparature"); 458 } 459 } 460 if (sc->sc_ich.ich_arg != NULL) 461 config_intrhook_disestablish(&sc->sc_ich); 462 } 463 464 int 465 amdtemp_detach(device_t dev) 466 { 467 struct amdtemp_softc *sc = device_get_softc(dev); 468 int i; 469 470 for (i = 0; i < sc->sc_ncores; i++) 471 if (sc->sc_sysctl_cpu[i] != NULL) 472 sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 473 474 /* NewBus removes the dev.amdtemp.N tree by itself. */ 475 476 return (0); 477 } 478 479 static int 480 amdtemp_sysctl(SYSCTL_HANDLER_ARGS) 481 { 482 device_t dev = (device_t)arg1; 483 struct amdtemp_softc *sc = device_get_softc(dev); 484 amdsensor_t sensor = (amdsensor_t)arg2; 485 int32_t auxtemp[2], temp; 486 int error; 487 488 switch (sensor) { 489 case CORE0: 490 auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); 491 auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); 492 temp = imax(auxtemp[0], auxtemp[1]); 493 break; 494 case CORE1: 495 auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); 496 auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); 497 temp = imax(auxtemp[0], auxtemp[1]); 498 break; 499 default: 500 temp = sc->sc_gettemp(dev, sensor); 501 break; 502 } 503 error = sysctl_handle_int(oidp, &temp, 0, req); 504 505 return (error); 506 } 507 508 #define AMDTEMP_ZERO_C_TO_K 2731 509 510 static int32_t 511 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 512 { 513 struct amdtemp_softc *sc = device_get_softc(dev); 514 uint32_t mask, offset, temp; 515 516 /* Set Sensor/Core selector. */ 517 temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 518 temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); 519 switch (sensor) { 520 case CORE0_SENSOR1: 521 temp |= AMDTEMP_TTSR_SELSENSOR; 522 /* FALLTHROUGH */ 523 case CORE0_SENSOR0: 524 case CORE0: 525 if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 526 temp |= AMDTEMP_TTSR_SELCORE; 527 break; 528 case CORE1_SENSOR1: 529 temp |= AMDTEMP_TTSR_SELSENSOR; 530 /* FALLTHROUGH */ 531 case CORE1_SENSOR0: 532 case CORE1: 533 if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 534 temp |= AMDTEMP_TTSR_SELCORE; 535 break; 536 } 537 pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); 538 539 mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 540 offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; 541 temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 542 temp = ((temp >> 14) & mask) * 5 / 2; 543 temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; 544 545 return (temp); 546 } 547 548 static int32_t 549 amdtemp_gettemp(device_t dev, amdsensor_t sensor) 550 { 551 struct amdtemp_softc *sc = device_get_softc(dev); 552 uint32_t temp; 553 554 temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 555 temp = ((temp >> 21) & 0x7ff) * 5 / 4; 556 temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; 557 558 return (temp); 559 } 560