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