amdtemp.c revision 241885
155682Smarkm/*- 272445Sassar * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 355682Smarkm * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 455682Smarkm * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org> 555682Smarkm * All rights reserved. 655682Smarkm * 755682Smarkm * Redistribution and use in source and binary forms, with or without 855682Smarkm * modification, are permitted provided that the following conditions 955682Smarkm * are met: 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1355682Smarkm * notice, this list of conditions and the following disclaimer in the 1455682Smarkm * documentation and/or other materials provided with the distribution. 1555682Smarkm * 1655682Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1755682Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1855682Smarkm * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1955682Smarkm * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2055682Smarkm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2155682Smarkm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2255682Smarkm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2355682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2455682Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2555682Smarkm * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2655682Smarkm * POSSIBILITY OF SUCH DAMAGE. 2755682Smarkm */ 2855682Smarkm 2955682Smarkm/* 3055682Smarkm * Driver for the AMD CPU on-die thermal sensors. 3155682Smarkm * Initially based on the k8temp Linux driver. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include <sys/cdefs.h> 3555682Smarkm__FBSDID("$FreeBSD: head/sys/dev/amdtemp/amdtemp.c 241885 2012-10-22 13:06:09Z eadler $"); 3672445Sassar 3755682Smarkm#include <sys/param.h> 3855682Smarkm#include <sys/bus.h> 3955682Smarkm#include <sys/conf.h> 4055682Smarkm#include <sys/kernel.h> 4155682Smarkm#include <sys/module.h> 4255682Smarkm#include <sys/sysctl.h> 4355682Smarkm#include <sys/systm.h> 4455682Smarkm 4572445Sassar#include <machine/cpufunc.h> 4655682Smarkm#include <machine/md_var.h> 4755682Smarkm#include <machine/specialreg.h> 4855682Smarkm 4955682Smarkm#include <dev/pci/pcivar.h> 5055682Smarkm#include <x86/pci_cfgreg.h> 5155682Smarkm 5255682Smarkmtypedef enum { 5355682Smarkm CORE0_SENSOR0, 5455682Smarkm CORE0_SENSOR1, 5555682Smarkm CORE1_SENSOR0, 5655682Smarkm CORE1_SENSOR1, 5755682Smarkm CORE0, 5855682Smarkm CORE1 5955682Smarkm} amdsensor_t; 6072445Sassar 6172445Sassarstruct amdtemp_softc { 6272445Sassar device_t sc_dev; 6372445Sassar int sc_ncores; 6455682Smarkm int sc_ntemps; 6572445Sassar int sc_flags; 6672445Sassar#define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ 6772445Sassar#define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ 6872445Sassar#define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */ 6972445Sassar int32_t sc_offset; 7072445Sassar int32_t (*sc_gettemp)(device_t, amdsensor_t); 7172445Sassar struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 7272445Sassar struct intr_config_hook sc_ich; 7372445Sassar}; 7455682Smarkm 7555682Smarkm#define VENDORID_AMD 0x1022 7655682Smarkm#define DEVICEID_AMD_MISC0F 0x1103 7755682Smarkm#define DEVICEID_AMD_MISC10 0x1203 7855682Smarkm#define DEVICEID_AMD_MISC11 0x1303 7955682Smarkm#define DEVICEID_AMD_MISC14 0x1703 8055682Smarkm#define DEVICEID_AMD_MISC15 0x1603 8155682Smarkm 8255682Smarkmstatic struct amdtemp_product { 8355682Smarkm uint16_t amdtemp_vendorid; 8455682Smarkm uint16_t amdtemp_deviceid; 8555682Smarkm} amdtemp_products[] = { 8655682Smarkm { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 8755682Smarkm { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 8855682Smarkm { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 8955682Smarkm { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 9055682Smarkm { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 9155682Smarkm { 0, 0 } 9255682Smarkm}; 9355682Smarkm 9455682Smarkm/* 9555682Smarkm * Reported Temperature Control Register 9655682Smarkm */ 9755682Smarkm#define AMDTEMP_REPTMP_CTRL 0xa4 9855682Smarkm 9955682Smarkm/* 10055682Smarkm * Thermaltrip Status Register (Family 0Fh only) 10155682Smarkm */ 10255682Smarkm#define AMDTEMP_THERMTP_STAT 0xe4 10355682Smarkm#define AMDTEMP_TTSR_SELCORE 0x04 10455682Smarkm#define AMDTEMP_TTSR_SELSENSOR 0x40 10555682Smarkm 10655682Smarkm/* 10755682Smarkm * DRAM Configuration High Register 10855682Smarkm */ 10955682Smarkm#define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 11055682Smarkm#define AMDTEMP_DRAM_MODE_DDR3 0x0100 11155682Smarkm 11255682Smarkm/* 11355682Smarkm * CPU Family/Model Register 11455682Smarkm */ 11555682Smarkm#define AMDTEMP_CPUID 0xfc 11655682Smarkm 11755682Smarkm/* 11855682Smarkm * Device methods. 11955682Smarkm */ 12055682Smarkmstatic void amdtemp_identify(driver_t *driver, device_t parent); 12155682Smarkmstatic int amdtemp_probe(device_t dev); 12255682Smarkmstatic int amdtemp_attach(device_t dev); 12355682Smarkmstatic void amdtemp_intrhook(void *arg); 12455682Smarkmstatic int amdtemp_detach(device_t dev); 12555682Smarkmstatic int amdtemp_match(device_t dev); 12655682Smarkmstatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 12755682Smarkmstatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 12855682Smarkmstatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 12955682Smarkm 13055682Smarkmstatic device_method_t amdtemp_methods[] = { 13155682Smarkm /* Device interface */ 13255682Smarkm DEVMETHOD(device_identify, amdtemp_identify), 13355682Smarkm DEVMETHOD(device_probe, amdtemp_probe), 13472445Sassar DEVMETHOD(device_attach, amdtemp_attach), 13555682Smarkm DEVMETHOD(device_detach, amdtemp_detach), 13655682Smarkm 13755682Smarkm {0, 0} 13855682Smarkm}; 13955682Smarkm 14055682Smarkmstatic driver_t amdtemp_driver = { 14155682Smarkm "amdtemp", 14255682Smarkm amdtemp_methods, 14355682Smarkm sizeof(struct amdtemp_softc), 14455682Smarkm}; 14555682Smarkm 14655682Smarkmstatic devclass_t amdtemp_devclass; 14755682SmarkmDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 14855682Smarkm 14955682Smarkmstatic int 15055682Smarkmamdtemp_match(device_t dev) 15155682Smarkm{ 15255682Smarkm int i; 15355682Smarkm uint16_t vendor, devid; 15455682Smarkm 15555682Smarkm vendor = pci_get_vendor(dev); 15655682Smarkm devid = pci_get_device(dev); 15755682Smarkm 15855682Smarkm for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 15955682Smarkm if (vendor == amdtemp_products[i].amdtemp_vendorid && 16055682Smarkm devid == amdtemp_products[i].amdtemp_deviceid) 16155682Smarkm return (1); 16255682Smarkm } 16355682Smarkm 16455682Smarkm return (0); 16555682Smarkm} 16655682Smarkm 16755682Smarkmstatic void 16855682Smarkmamdtemp_identify(driver_t *driver, device_t parent) 16955682Smarkm{ 17055682Smarkm device_t child; 17155682Smarkm 17255682Smarkm /* Make sure we're not being doubly invoked. */ 17355682Smarkm if (device_find_child(parent, "amdtemp", -1) != NULL) 17455682Smarkm return; 17572445Sassar 17672445Sassar if (amdtemp_match(parent)) { 17772445Sassar child = device_add_child(parent, "amdtemp", -1); 17872445Sassar if (child == NULL) 17972445Sassar device_printf(parent, "add amdtemp child failed\n"); 18072445Sassar } 18172445Sassar} 18272445Sassar 18372445Sassarstatic int 18472445Sassaramdtemp_probe(device_t dev) 18572445Sassar{ 18672445Sassar uint32_t family, model; 18772445Sassar 18872445Sassar if (resource_disabled("amdtemp", 0)) 18972445Sassar return (ENXIO); 19072445Sassar 19172445Sassar family = CPUID_TO_FAMILY(cpu_id); 19272445Sassar model = CPUID_TO_MODEL(cpu_id); 19372445Sassar 19472445Sassar switch (family) { 19555682Smarkm case 0x0f: 19655682Smarkm if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 19772445Sassar (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 19872445Sassar return (ENXIO); 19955682Smarkm break; 20055682Smarkm case 0x10: 20172445Sassar case 0x11: 20255682Smarkm case 0x12: 20355682Smarkm case 0x14: 20455682Smarkm case 0x15: 20572445Sassar break; 20655682Smarkm default: 20755682Smarkm return (ENXIO); 20855682Smarkm } 20955682Smarkm device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 21072445Sassar 21155682Smarkm return (BUS_PROBE_GENERIC); 21255682Smarkm} 21355682Smarkm 21455682Smarkmstatic int 21555682Smarkmamdtemp_attach(device_t dev) 21655682Smarkm{ 21755682Smarkm char tn[32]; 21855682Smarkm u_int regs[4]; 21955682Smarkm struct amdtemp_softc *sc = device_get_softc(dev); 22055682Smarkm 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 415void 416amdtemp_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 454int 455amdtemp_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 469static int 470amdtemp_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 500static int32_t 501amdtemp_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 538static int32_t 539amdtemp_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