amdtemp.c revision 273383
1178151Srpaulo/*- 2189769Srpaulo * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 3189769Srpaulo * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 4232090Sjkim * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org> 5178151Srpaulo * All rights reserved. 6178151Srpaulo * 7178151Srpaulo * Redistribution and use in source and binary forms, with or without 8178151Srpaulo * modification, are permitted provided that the following conditions 9178151Srpaulo * are met: 10178151Srpaulo * 1. Redistributions of source code must retain the above copyright 11178151Srpaulo * notice, this list of conditions and the following disclaimer. 12178151Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 13178151Srpaulo * notice, this list of conditions and the following disclaimer in the 14178151Srpaulo * documentation and/or other materials provided with the distribution. 15178151Srpaulo * 16178151Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17178151Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18178151Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19178151Srpaulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20178151Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21178151Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22178151Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23178151Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24178151Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25178151Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26178151Srpaulo * POSSIBILITY OF SUCH DAMAGE. 27178151Srpaulo */ 28178151Srpaulo 29178151Srpaulo/* 30232090Sjkim * Driver for the AMD CPU on-die thermal sensors. 31197102Sjkim * Initially based on the k8temp Linux driver. 32178151Srpaulo */ 33178151Srpaulo 34178151Srpaulo#include <sys/cdefs.h> 35178151Srpaulo__FBSDID("$FreeBSD: stable/10/sys/dev/amdtemp/amdtemp.c 273383 2014-10-21 13:07:36Z brueffer $"); 36178151Srpaulo 37178151Srpaulo#include <sys/param.h> 38178151Srpaulo#include <sys/bus.h> 39178151Srpaulo#include <sys/conf.h> 40178151Srpaulo#include <sys/kernel.h> 41197102Sjkim#include <sys/module.h> 42178151Srpaulo#include <sys/sysctl.h> 43197102Sjkim#include <sys/systm.h> 44178151Srpaulo 45197205Sjkim#include <machine/cpufunc.h> 46197102Sjkim#include <machine/md_var.h> 47178151Srpaulo#include <machine/specialreg.h> 48178151Srpaulo 49178151Srpaulo#include <dev/pci/pcivar.h> 50232090Sjkim#include <x86/pci_cfgreg.h> 51178151Srpaulo 52189769Srpaulotypedef enum { 53232090Sjkim CORE0_SENSOR0, 54232090Sjkim CORE0_SENSOR1, 55232090Sjkim CORE1_SENSOR0, 56232090Sjkim CORE1_SENSOR1, 57189769Srpaulo CORE0, 58189769Srpaulo CORE1 59189769Srpaulo} amdsensor_t; 60189769Srpaulo 61189769Srpaulostruct amdtemp_softc { 62178151Srpaulo device_t sc_dev; 63197102Sjkim int sc_ncores; 64178151Srpaulo int sc_ntemps; 65197205Sjkim int sc_flags; 66232090Sjkim#define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ 67232090Sjkim#define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ 68232090Sjkim#define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */ 69232090Sjkim int32_t sc_offset; 70197102Sjkim int32_t (*sc_gettemp)(device_t, amdsensor_t); 71197102Sjkim struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 72180312Srpaulo struct intr_config_hook sc_ich; 73178151Srpaulo}; 74178151Srpaulo 75197102Sjkim#define VENDORID_AMD 0x1022 76197102Sjkim#define DEVICEID_AMD_MISC0F 0x1103 77197102Sjkim#define DEVICEID_AMD_MISC10 0x1203 78197102Sjkim#define DEVICEID_AMD_MISC11 0x1303 79254924Sjmg#define DEVICEID_AMD_MISC12 0x1403 80232090Sjkim#define DEVICEID_AMD_MISC14 0x1703 81232090Sjkim#define DEVICEID_AMD_MISC15 0x1603 82263869Sbrueffer#define DEVICEID_AMD_MISC16 0x1533 83273383Sbrueffer#define DEVICEID_AMD_MISC17 0x141d 84178151Srpaulo 85189769Srpaulostatic struct amdtemp_product { 86189769Srpaulo uint16_t amdtemp_vendorid; 87189769Srpaulo uint16_t amdtemp_deviceid; 88189769Srpaulo} amdtemp_products[] = { 89189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 90189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 91189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 92254924Sjmg { VENDORID_AMD, DEVICEID_AMD_MISC12 }, 93232090Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 94232090Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 95263869Sbrueffer { VENDORID_AMD, DEVICEID_AMD_MISC16 }, 96273383Sbrueffer { VENDORID_AMD, DEVICEID_AMD_MISC17 }, 97178151Srpaulo { 0, 0 } 98178151Srpaulo}; 99178151Srpaulo 100178151Srpaulo/* 101232090Sjkim * Reported Temperature Control Register 102178151Srpaulo */ 103197102Sjkim#define AMDTEMP_REPTMP_CTRL 0xa4 104178151Srpaulo 105189769Srpaulo/* 106232090Sjkim * Thermaltrip Status Register (Family 0Fh only) 107189769Srpaulo */ 108197102Sjkim#define AMDTEMP_THERMTP_STAT 0xe4 109232090Sjkim#define AMDTEMP_TTSR_SELCORE 0x04 110232090Sjkim#define AMDTEMP_TTSR_SELSENSOR 0x40 111178151Srpaulo 112197102Sjkim/* 113232090Sjkim * DRAM Configuration High Register 114232090Sjkim */ 115232090Sjkim#define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 116232090Sjkim#define AMDTEMP_DRAM_MODE_DDR3 0x0100 117232090Sjkim 118232090Sjkim/* 119197102Sjkim * CPU Family/Model Register 120197102Sjkim */ 121197102Sjkim#define AMDTEMP_CPUID 0xfc 122178151Srpaulo 123178151Srpaulo/* 124178151Srpaulo * Device methods. 125178151Srpaulo */ 126189769Srpaulostatic void amdtemp_identify(driver_t *driver, device_t parent); 127189769Srpaulostatic int amdtemp_probe(device_t dev); 128189769Srpaulostatic int amdtemp_attach(device_t dev); 129189769Srpaulostatic void amdtemp_intrhook(void *arg); 130189769Srpaulostatic int amdtemp_detach(device_t dev); 131189769Srpaulostatic int amdtemp_match(device_t dev); 132189769Srpaulostatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 133189769Srpaulostatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 134189769Srpaulostatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 135178151Srpaulo 136189769Srpaulostatic device_method_t amdtemp_methods[] = { 137178151Srpaulo /* Device interface */ 138189769Srpaulo DEVMETHOD(device_identify, amdtemp_identify), 139189769Srpaulo DEVMETHOD(device_probe, amdtemp_probe), 140189769Srpaulo DEVMETHOD(device_attach, amdtemp_attach), 141189769Srpaulo DEVMETHOD(device_detach, amdtemp_detach), 142178151Srpaulo 143246128Ssbz DEVMETHOD_END 144178151Srpaulo}; 145178151Srpaulo 146189769Srpaulostatic driver_t amdtemp_driver = { 147189769Srpaulo "amdtemp", 148189769Srpaulo amdtemp_methods, 149189769Srpaulo sizeof(struct amdtemp_softc), 150178151Srpaulo}; 151178151Srpaulo 152189769Srpaulostatic devclass_t amdtemp_devclass; 153189769SrpauloDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 154178151Srpaulo 155178151Srpaulostatic int 156189769Srpauloamdtemp_match(device_t dev) 157178151Srpaulo{ 158178151Srpaulo int i; 159178151Srpaulo uint16_t vendor, devid; 160197102Sjkim 161197102Sjkim vendor = pci_get_vendor(dev); 162178151Srpaulo devid = pci_get_device(dev); 163178151Srpaulo 164189769Srpaulo for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 165189769Srpaulo if (vendor == amdtemp_products[i].amdtemp_vendorid && 166189769Srpaulo devid == amdtemp_products[i].amdtemp_deviceid) 167178151Srpaulo return (1); 168178151Srpaulo } 169178151Srpaulo 170178151Srpaulo return (0); 171178151Srpaulo} 172178151Srpaulo 173178151Srpaulostatic void 174189769Srpauloamdtemp_identify(driver_t *driver, device_t parent) 175178151Srpaulo{ 176178151Srpaulo device_t child; 177178151Srpaulo 178178151Srpaulo /* Make sure we're not being doubly invoked. */ 179189769Srpaulo if (device_find_child(parent, "amdtemp", -1) != NULL) 180178151Srpaulo return; 181197102Sjkim 182189769Srpaulo if (amdtemp_match(parent)) { 183189769Srpaulo child = device_add_child(parent, "amdtemp", -1); 184178151Srpaulo if (child == NULL) 185189769Srpaulo device_printf(parent, "add amdtemp child failed\n"); 186178151Srpaulo } 187178151Srpaulo} 188178151Srpaulo 189178151Srpaulostatic int 190189769Srpauloamdtemp_probe(device_t dev) 191178151Srpaulo{ 192197205Sjkim uint32_t family, model; 193197102Sjkim 194241885Seadler if (resource_disabled("amdtemp", 0)) 195241885Seadler return (ENXIO); 196241885Seadler 197197205Sjkim family = CPUID_TO_FAMILY(cpu_id); 198197205Sjkim model = CPUID_TO_MODEL(cpu_id); 199197102Sjkim 200197102Sjkim switch (family) { 201197102Sjkim case 0x0f: 202197205Sjkim if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 203197205Sjkim (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 204197102Sjkim return (ENXIO); 205197102Sjkim break; 206197102Sjkim case 0x10: 207197102Sjkim case 0x11: 208232090Sjkim case 0x12: 209232090Sjkim case 0x14: 210232090Sjkim case 0x15: 211263869Sbrueffer case 0x16: 212197102Sjkim break; 213197102Sjkim default: 214178151Srpaulo return (ENXIO); 215178151Srpaulo } 216197102Sjkim device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 217197102Sjkim 218178151Srpaulo return (BUS_PROBE_GENERIC); 219178151Srpaulo} 220178151Srpaulo 221178151Srpaulostatic int 222189769Srpauloamdtemp_attach(device_t dev) 223178151Srpaulo{ 224232090Sjkim char tn[32]; 225232090Sjkim u_int regs[4]; 226189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 227178151Srpaulo struct sysctl_ctx_list *sysctlctx; 228178151Srpaulo struct sysctl_oid *sysctlnode; 229197102Sjkim uint32_t cpuid, family, model; 230232090Sjkim u_int bid; 231232090Sjkim int erratum319, unit; 232178151Srpaulo 233232090Sjkim erratum319 = 0; 234180312Srpaulo 235197205Sjkim /* 236197205Sjkim * CPUID Register is available from Revision F. 237197205Sjkim */ 238232090Sjkim cpuid = cpu_id; 239232090Sjkim family = CPUID_TO_FAMILY(cpuid); 240232090Sjkim model = CPUID_TO_MODEL(cpuid); 241197205Sjkim if (family != 0x0f || model >= 0x40) { 242197205Sjkim cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 243197205Sjkim family = CPUID_TO_FAMILY(cpuid); 244197205Sjkim model = CPUID_TO_MODEL(cpuid); 245197205Sjkim } 246197205Sjkim 247197102Sjkim switch (family) { 248197102Sjkim case 0x0f: 249197102Sjkim /* 250197205Sjkim * Thermaltrip Status Register 251197102Sjkim * 252197205Sjkim * - ThermSenseCoreSel 253197205Sjkim * 254197205Sjkim * Revision F & G: 0 - Core1, 1 - Core0 255197205Sjkim * Other: 0 - Core0, 1 - Core1 256197205Sjkim * 257197205Sjkim * - CurTmp 258197205Sjkim * 259197102Sjkim * Revision G: bits 23-14 260197205Sjkim * Other: bits 23-16 261197102Sjkim * 262197205Sjkim * XXX According to the BKDG, CurTmp, ThermSenseSel and 263197205Sjkim * ThermSenseCoreSel bits were introduced in Revision F 264197205Sjkim * but CurTmp seems working fine as early as Revision C. 265197205Sjkim * However, it is not clear whether ThermSenseSel and/or 266197205Sjkim * ThermSenseCoreSel work in undocumented cases as well. 267197205Sjkim * In fact, the Linux driver suggests it may not work but 268197205Sjkim * we just assume it does until we find otherwise. 269232090Sjkim * 270232090Sjkim * XXX According to Linux, CurTmp starts at -28C on 271232090Sjkim * Socket AM2 Revision G processors, which is not 272232090Sjkim * documented anywhere. 273197102Sjkim */ 274232090Sjkim if (model >= 0x40) 275197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 276232090Sjkim if (model >= 0x60 && model != 0xc1) { 277232090Sjkim do_cpuid(0x80000001, regs); 278232090Sjkim bid = (regs[1] >> 9) & 0x1f; 279232090Sjkim switch (model) { 280232090Sjkim case 0x68: /* Socket S1g1 */ 281232090Sjkim case 0x6c: 282232090Sjkim case 0x7c: 283232090Sjkim break; 284232090Sjkim case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ 285232090Sjkim if (bid != 0x0b && bid != 0x0c) 286232090Sjkim sc->sc_flags |= 287232090Sjkim AMDTEMP_FLAG_ALT_OFFSET; 288232090Sjkim break; 289232090Sjkim case 0x6f: /* Socket AM2 and ASB1 (1 core) */ 290232090Sjkim case 0x7f: 291232090Sjkim if (bid != 0x07 && bid != 0x09 && 292232090Sjkim bid != 0x0c) 293232090Sjkim sc->sc_flags |= 294232090Sjkim AMDTEMP_FLAG_ALT_OFFSET; 295232090Sjkim break; 296232090Sjkim default: 297232090Sjkim sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; 298232090Sjkim } 299232090Sjkim sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 300197205Sjkim } 301197102Sjkim 302197102Sjkim /* 303197102Sjkim * There are two sensors per core. 304197102Sjkim */ 305197102Sjkim sc->sc_ntemps = 2; 306197102Sjkim 307189769Srpaulo sc->sc_gettemp = amdtemp_gettemp0f; 308197102Sjkim break; 309197102Sjkim case 0x10: 310232090Sjkim /* 311232090Sjkim * Erratum 319 Inaccurate Temperature Measurement 312232090Sjkim * 313232090Sjkim * http://support.amd.com/us/Processor_TechDocs/41322.pdf 314232090Sjkim */ 315232090Sjkim do_cpuid(0x80000001, regs); 316232090Sjkim switch ((regs[1] >> 28) & 0xf) { 317232090Sjkim case 0: /* Socket F */ 318232090Sjkim erratum319 = 1; 319232090Sjkim break; 320232090Sjkim case 1: /* Socket AM2+ or AM3 */ 321232090Sjkim if ((pci_cfgregread(pci_get_bus(dev), 322232090Sjkim pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & 323232090Sjkim AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || 324232090Sjkim (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) 325232090Sjkim break; 326232090Sjkim /* XXX 00100F42h (RB-C2) exists in both formats. */ 327232090Sjkim erratum319 = 1; 328232090Sjkim break; 329232090Sjkim } 330232090Sjkim /* FALLTHROUGH */ 331197102Sjkim case 0x11: 332232090Sjkim case 0x12: 333232090Sjkim case 0x14: 334232090Sjkim case 0x15: 335263869Sbrueffer case 0x16: 336197102Sjkim /* 337197102Sjkim * There is only one sensor per package. 338197102Sjkim */ 339197102Sjkim sc->sc_ntemps = 1; 340197102Sjkim 341189769Srpaulo sc->sc_gettemp = amdtemp_gettemp; 342197102Sjkim break; 343189769Srpaulo } 344189769Srpaulo 345197102Sjkim /* Find number of cores per package. */ 346197102Sjkim sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 347197102Sjkim (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 348197102Sjkim if (sc->sc_ncores > MAXCPU) 349197102Sjkim return (ENXIO); 350197102Sjkim 351232090Sjkim if (erratum319) 352232090Sjkim device_printf(dev, 353232090Sjkim "Erratum 319: temperature measurement may be inaccurate\n"); 354197102Sjkim if (bootverbose) 355197102Sjkim device_printf(dev, "Found %d cores and %d sensors.\n", 356197102Sjkim sc->sc_ncores, 357197102Sjkim sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 358197102Sjkim 359178151Srpaulo /* 360189769Srpaulo * dev.amdtemp.N tree. 361178151Srpaulo */ 362232090Sjkim unit = device_get_unit(dev); 363232090Sjkim snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); 364232090Sjkim TUNABLE_INT_FETCH(tn, &sc->sc_offset); 365232090Sjkim 366178151Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 367232090Sjkim SYSCTL_ADD_INT(sysctlctx, 368232090Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 369232090Sjkim "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, 370232090Sjkim "Temperature sensor offset"); 371178151Srpaulo sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 372197102Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 373232090Sjkim "core0", CTLFLAG_RD, 0, "Core 0"); 374197102Sjkim 375178151Srpaulo SYSCTL_ADD_PROC(sysctlctx, 376178151Srpaulo SYSCTL_CHILDREN(sysctlnode), 377232090Sjkim OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 378232090Sjkim dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", 379232090Sjkim "Core 0 / Sensor 0 temperature"); 380178151Srpaulo 381197102Sjkim if (sc->sc_ntemps > 1) { 382197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 383197102Sjkim SYSCTL_CHILDREN(sysctlnode), 384232090Sjkim OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 385232090Sjkim dev, CORE0_SENSOR1, amdtemp_sysctl, "IK", 386232090Sjkim "Core 0 / Sensor 1 temperature"); 387197102Sjkim 388232090Sjkim if (sc->sc_ncores > 1) { 389232090Sjkim sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 390232090Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 391232090Sjkim OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1"); 392232090Sjkim 393197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 394197102Sjkim SYSCTL_CHILDREN(sysctlnode), 395232090Sjkim OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 396232090Sjkim dev, CORE1_SENSOR0, amdtemp_sysctl, "IK", 397232090Sjkim "Core 1 / Sensor 0 temperature"); 398232090Sjkim 399232090Sjkim SYSCTL_ADD_PROC(sysctlctx, 400232090Sjkim SYSCTL_CHILDREN(sysctlnode), 401232090Sjkim OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 402232090Sjkim dev, CORE1_SENSOR1, amdtemp_sysctl, "IK", 403232090Sjkim "Core 1 / Sensor 1 temperature"); 404232090Sjkim } 405197102Sjkim } 406197102Sjkim 407197102Sjkim /* 408197102Sjkim * Try to create dev.cpu sysctl entries and setup intrhook function. 409197102Sjkim * This is needed because the cpu driver may be loaded late on boot, 410197102Sjkim * after us. 411197102Sjkim */ 412197102Sjkim amdtemp_intrhook(dev); 413197102Sjkim sc->sc_ich.ich_func = amdtemp_intrhook; 414197102Sjkim sc->sc_ich.ich_arg = dev; 415197102Sjkim if (config_intrhook_establish(&sc->sc_ich) != 0) { 416197102Sjkim device_printf(dev, "config_intrhook_establish failed!\n"); 417197102Sjkim return (ENXIO); 418197102Sjkim } 419197102Sjkim 420178151Srpaulo return (0); 421178151Srpaulo} 422178151Srpaulo 423180312Srpaulovoid 424189769Srpauloamdtemp_intrhook(void *arg) 425180312Srpaulo{ 426189769Srpaulo struct amdtemp_softc *sc; 427180312Srpaulo struct sysctl_ctx_list *sysctlctx; 428197102Sjkim device_t dev = (device_t)arg; 429197102Sjkim device_t acpi, cpu, nexus; 430197102Sjkim amdsensor_t sensor; 431197102Sjkim int i; 432180312Srpaulo 433180312Srpaulo sc = device_get_softc(dev); 434197102Sjkim 435180312Srpaulo /* 436180312Srpaulo * dev.cpu.N.temperature. 437180312Srpaulo */ 438180312Srpaulo nexus = device_find_child(root_bus, "nexus", 0); 439180312Srpaulo acpi = device_find_child(nexus, "acpi", 0); 440180312Srpaulo 441197102Sjkim for (i = 0; i < sc->sc_ncores; i++) { 442197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 443197102Sjkim continue; 444180312Srpaulo cpu = device_find_child(acpi, "cpu", 445197102Sjkim device_get_unit(dev) * sc->sc_ncores + i); 446197102Sjkim if (cpu != NULL) { 447180312Srpaulo sysctlctx = device_get_sysctl_ctx(cpu); 448180312Srpaulo 449197102Sjkim sensor = sc->sc_ntemps > 1 ? 450232090Sjkim (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; 451180312Srpaulo sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 452180312Srpaulo SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 453180312Srpaulo OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 454197102Sjkim dev, sensor, amdtemp_sysctl, "IK", 455197102Sjkim "Current temparature"); 456180312Srpaulo } 457180312Srpaulo } 458197102Sjkim if (sc->sc_ich.ich_arg != NULL) 459197102Sjkim config_intrhook_disestablish(&sc->sc_ich); 460180312Srpaulo} 461180312Srpaulo 462178151Srpauloint 463189769Srpauloamdtemp_detach(device_t dev) 464178151Srpaulo{ 465197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 466178151Srpaulo int i; 467197102Sjkim 468197102Sjkim for (i = 0; i < sc->sc_ncores; i++) 469197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 470178151Srpaulo sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 471178151Srpaulo 472189769Srpaulo /* NewBus removes the dev.amdtemp.N tree by itself. */ 473197102Sjkim 474178151Srpaulo return (0); 475178151Srpaulo} 476178151Srpaulo 477178151Srpaulostatic int 478189769Srpauloamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 479178151Srpaulo{ 480197102Sjkim device_t dev = (device_t)arg1; 481189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 482197102Sjkim amdsensor_t sensor = (amdsensor_t)arg2; 483197102Sjkim int32_t auxtemp[2], temp; 484178151Srpaulo int error; 485178151Srpaulo 486197102Sjkim switch (sensor) { 487178151Srpaulo case CORE0: 488232090Sjkim auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); 489232090Sjkim auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); 490178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 491178151Srpaulo break; 492178151Srpaulo case CORE1: 493232090Sjkim auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); 494232090Sjkim auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); 495178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 496178151Srpaulo break; 497178151Srpaulo default: 498197102Sjkim temp = sc->sc_gettemp(dev, sensor); 499178151Srpaulo break; 500178151Srpaulo } 501178151Srpaulo error = sysctl_handle_int(oidp, &temp, 0, req); 502197102Sjkim 503178151Srpaulo return (error); 504178151Srpaulo} 505178151Srpaulo 506197102Sjkim#define AMDTEMP_ZERO_C_TO_K 2732 507197102Sjkim 508178151Srpaulostatic int32_t 509189769Srpauloamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 510178151Srpaulo{ 511197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 512232090Sjkim uint32_t mask, offset, temp; 513197102Sjkim 514197102Sjkim /* Set Sensor/Core selector. */ 515232090Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 516232090Sjkim temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); 517178151Srpaulo switch (sensor) { 518232090Sjkim case CORE0_SENSOR1: 519232090Sjkim temp |= AMDTEMP_TTSR_SELSENSOR; 520197103Sjkim /* FALLTHROUGH */ 521232090Sjkim case CORE0_SENSOR0: 522197102Sjkim case CORE0: 523197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 524232090Sjkim temp |= AMDTEMP_TTSR_SELCORE; 525178151Srpaulo break; 526232090Sjkim case CORE1_SENSOR1: 527232090Sjkim temp |= AMDTEMP_TTSR_SELSENSOR; 528197103Sjkim /* FALLTHROUGH */ 529232090Sjkim case CORE1_SENSOR0: 530197102Sjkim case CORE1: 531197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 532232090Sjkim temp |= AMDTEMP_TTSR_SELCORE; 533178151Srpaulo break; 534178151Srpaulo } 535232090Sjkim pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); 536197102Sjkim 537232090Sjkim mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 538232090Sjkim offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; 539197102Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 540232090Sjkim temp = ((temp >> 14) & mask) * 5 / 2; 541232090Sjkim temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; 542197102Sjkim 543178151Srpaulo return (temp); 544178151Srpaulo} 545189769Srpaulo 546189769Srpaulostatic int32_t 547189769Srpauloamdtemp_gettemp(device_t dev, amdsensor_t sensor) 548189769Srpaulo{ 549232090Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 550189769Srpaulo uint32_t temp; 551189769Srpaulo 552197102Sjkim temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 553232090Sjkim temp = ((temp >> 21) & 0x7ff) * 5 / 4; 554232090Sjkim temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; 555197102Sjkim 556189769Srpaulo return (temp); 557189769Srpaulo} 558