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