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$"); 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 83300520Sloos#define DEVICEID_AMD_MISC16_M30H 0x1583 84273383Sbrueffer#define DEVICEID_AMD_MISC17 0x141d 85178151Srpaulo 86189769Srpaulostatic struct amdtemp_product { 87189769Srpaulo uint16_t amdtemp_vendorid; 88189769Srpaulo uint16_t amdtemp_deviceid; 89189769Srpaulo} amdtemp_products[] = { 90189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 91189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 92189769Srpaulo { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 93254924Sjmg { VENDORID_AMD, DEVICEID_AMD_MISC12 }, 94232090Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 95232090Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 96263869Sbrueffer { VENDORID_AMD, DEVICEID_AMD_MISC16 }, 97300520Sloos { VENDORID_AMD, DEVICEID_AMD_MISC16_M30H }, 98273383Sbrueffer { VENDORID_AMD, DEVICEID_AMD_MISC17 }, 99178151Srpaulo { 0, 0 } 100178151Srpaulo}; 101178151Srpaulo 102178151Srpaulo/* 103232090Sjkim * Reported Temperature Control Register 104178151Srpaulo */ 105197102Sjkim#define AMDTEMP_REPTMP_CTRL 0xa4 106178151Srpaulo 107189769Srpaulo/* 108232090Sjkim * Thermaltrip Status Register (Family 0Fh only) 109189769Srpaulo */ 110197102Sjkim#define AMDTEMP_THERMTP_STAT 0xe4 111232090Sjkim#define AMDTEMP_TTSR_SELCORE 0x04 112232090Sjkim#define AMDTEMP_TTSR_SELSENSOR 0x40 113178151Srpaulo 114197102Sjkim/* 115232090Sjkim * DRAM Configuration High Register 116232090Sjkim */ 117232090Sjkim#define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 118232090Sjkim#define AMDTEMP_DRAM_MODE_DDR3 0x0100 119232090Sjkim 120232090Sjkim/* 121197102Sjkim * CPU Family/Model Register 122197102Sjkim */ 123197102Sjkim#define AMDTEMP_CPUID 0xfc 124178151Srpaulo 125178151Srpaulo/* 126178151Srpaulo * Device methods. 127178151Srpaulo */ 128189769Srpaulostatic void amdtemp_identify(driver_t *driver, device_t parent); 129189769Srpaulostatic int amdtemp_probe(device_t dev); 130189769Srpaulostatic int amdtemp_attach(device_t dev); 131189769Srpaulostatic void amdtemp_intrhook(void *arg); 132189769Srpaulostatic int amdtemp_detach(device_t dev); 133189769Srpaulostatic int amdtemp_match(device_t dev); 134189769Srpaulostatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 135189769Srpaulostatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 136189769Srpaulostatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 137178151Srpaulo 138189769Srpaulostatic device_method_t amdtemp_methods[] = { 139178151Srpaulo /* Device interface */ 140189769Srpaulo DEVMETHOD(device_identify, amdtemp_identify), 141189769Srpaulo DEVMETHOD(device_probe, amdtemp_probe), 142189769Srpaulo DEVMETHOD(device_attach, amdtemp_attach), 143189769Srpaulo DEVMETHOD(device_detach, amdtemp_detach), 144178151Srpaulo 145246128Ssbz DEVMETHOD_END 146178151Srpaulo}; 147178151Srpaulo 148189769Srpaulostatic driver_t amdtemp_driver = { 149189769Srpaulo "amdtemp", 150189769Srpaulo amdtemp_methods, 151189769Srpaulo sizeof(struct amdtemp_softc), 152178151Srpaulo}; 153178151Srpaulo 154189769Srpaulostatic devclass_t amdtemp_devclass; 155189769SrpauloDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 156178151Srpaulo 157178151Srpaulostatic int 158189769Srpauloamdtemp_match(device_t dev) 159178151Srpaulo{ 160178151Srpaulo int i; 161178151Srpaulo uint16_t vendor, devid; 162197102Sjkim 163197102Sjkim vendor = pci_get_vendor(dev); 164178151Srpaulo devid = pci_get_device(dev); 165178151Srpaulo 166189769Srpaulo for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 167189769Srpaulo if (vendor == amdtemp_products[i].amdtemp_vendorid && 168189769Srpaulo devid == amdtemp_products[i].amdtemp_deviceid) 169178151Srpaulo return (1); 170178151Srpaulo } 171178151Srpaulo 172178151Srpaulo return (0); 173178151Srpaulo} 174178151Srpaulo 175178151Srpaulostatic void 176189769Srpauloamdtemp_identify(driver_t *driver, device_t parent) 177178151Srpaulo{ 178178151Srpaulo device_t child; 179178151Srpaulo 180178151Srpaulo /* Make sure we're not being doubly invoked. */ 181189769Srpaulo if (device_find_child(parent, "amdtemp", -1) != NULL) 182178151Srpaulo return; 183197102Sjkim 184189769Srpaulo if (amdtemp_match(parent)) { 185189769Srpaulo child = device_add_child(parent, "amdtemp", -1); 186178151Srpaulo if (child == NULL) 187189769Srpaulo device_printf(parent, "add amdtemp child failed\n"); 188178151Srpaulo } 189178151Srpaulo} 190178151Srpaulo 191178151Srpaulostatic int 192189769Srpauloamdtemp_probe(device_t dev) 193178151Srpaulo{ 194197205Sjkim uint32_t family, model; 195197102Sjkim 196241885Seadler if (resource_disabled("amdtemp", 0)) 197241885Seadler return (ENXIO); 198241885Seadler 199197205Sjkim family = CPUID_TO_FAMILY(cpu_id); 200197205Sjkim model = CPUID_TO_MODEL(cpu_id); 201197102Sjkim 202197102Sjkim switch (family) { 203197102Sjkim case 0x0f: 204197205Sjkim if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 205197205Sjkim (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 206197102Sjkim return (ENXIO); 207197102Sjkim break; 208197102Sjkim case 0x10: 209197102Sjkim case 0x11: 210232090Sjkim case 0x12: 211232090Sjkim case 0x14: 212232090Sjkim case 0x15: 213263869Sbrueffer case 0x16: 214197102Sjkim break; 215197102Sjkim default: 216178151Srpaulo return (ENXIO); 217178151Srpaulo } 218197102Sjkim device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 219197102Sjkim 220178151Srpaulo return (BUS_PROBE_GENERIC); 221178151Srpaulo} 222178151Srpaulo 223178151Srpaulostatic int 224189769Srpauloamdtemp_attach(device_t dev) 225178151Srpaulo{ 226232090Sjkim char tn[32]; 227232090Sjkim u_int regs[4]; 228189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 229178151Srpaulo struct sysctl_ctx_list *sysctlctx; 230178151Srpaulo struct sysctl_oid *sysctlnode; 231197102Sjkim uint32_t cpuid, family, model; 232232090Sjkim u_int bid; 233232090Sjkim int erratum319, unit; 234178151Srpaulo 235232090Sjkim erratum319 = 0; 236180312Srpaulo 237197205Sjkim /* 238197205Sjkim * CPUID Register is available from Revision F. 239197205Sjkim */ 240232090Sjkim cpuid = cpu_id; 241232090Sjkim family = CPUID_TO_FAMILY(cpuid); 242232090Sjkim model = CPUID_TO_MODEL(cpuid); 243197205Sjkim if (family != 0x0f || model >= 0x40) { 244197205Sjkim cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 245197205Sjkim family = CPUID_TO_FAMILY(cpuid); 246197205Sjkim model = CPUID_TO_MODEL(cpuid); 247197205Sjkim } 248197205Sjkim 249197102Sjkim switch (family) { 250197102Sjkim case 0x0f: 251197102Sjkim /* 252197205Sjkim * Thermaltrip Status Register 253197102Sjkim * 254197205Sjkim * - ThermSenseCoreSel 255197205Sjkim * 256197205Sjkim * Revision F & G: 0 - Core1, 1 - Core0 257197205Sjkim * Other: 0 - Core0, 1 - Core1 258197205Sjkim * 259197205Sjkim * - CurTmp 260197205Sjkim * 261197102Sjkim * Revision G: bits 23-14 262197205Sjkim * Other: bits 23-16 263197102Sjkim * 264197205Sjkim * XXX According to the BKDG, CurTmp, ThermSenseSel and 265197205Sjkim * ThermSenseCoreSel bits were introduced in Revision F 266197205Sjkim * but CurTmp seems working fine as early as Revision C. 267197205Sjkim * However, it is not clear whether ThermSenseSel and/or 268197205Sjkim * ThermSenseCoreSel work in undocumented cases as well. 269197205Sjkim * In fact, the Linux driver suggests it may not work but 270197205Sjkim * we just assume it does until we find otherwise. 271232090Sjkim * 272232090Sjkim * XXX According to Linux, CurTmp starts at -28C on 273232090Sjkim * Socket AM2 Revision G processors, which is not 274232090Sjkim * documented anywhere. 275197102Sjkim */ 276232090Sjkim if (model >= 0x40) 277197205Sjkim sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 278232090Sjkim if (model >= 0x60 && model != 0xc1) { 279232090Sjkim do_cpuid(0x80000001, regs); 280232090Sjkim bid = (regs[1] >> 9) & 0x1f; 281232090Sjkim switch (model) { 282232090Sjkim case 0x68: /* Socket S1g1 */ 283232090Sjkim case 0x6c: 284232090Sjkim case 0x7c: 285232090Sjkim break; 286232090Sjkim case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ 287232090Sjkim if (bid != 0x0b && bid != 0x0c) 288232090Sjkim sc->sc_flags |= 289232090Sjkim AMDTEMP_FLAG_ALT_OFFSET; 290232090Sjkim break; 291232090Sjkim case 0x6f: /* Socket AM2 and ASB1 (1 core) */ 292232090Sjkim case 0x7f: 293232090Sjkim if (bid != 0x07 && bid != 0x09 && 294232090Sjkim bid != 0x0c) 295232090Sjkim sc->sc_flags |= 296232090Sjkim AMDTEMP_FLAG_ALT_OFFSET; 297232090Sjkim break; 298232090Sjkim default: 299232090Sjkim sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; 300232090Sjkim } 301232090Sjkim sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 302197205Sjkim } 303197102Sjkim 304197102Sjkim /* 305197102Sjkim * There are two sensors per core. 306197102Sjkim */ 307197102Sjkim sc->sc_ntemps = 2; 308197102Sjkim 309189769Srpaulo sc->sc_gettemp = amdtemp_gettemp0f; 310197102Sjkim break; 311197102Sjkim case 0x10: 312232090Sjkim /* 313232090Sjkim * Erratum 319 Inaccurate Temperature Measurement 314232090Sjkim * 315232090Sjkim * http://support.amd.com/us/Processor_TechDocs/41322.pdf 316232090Sjkim */ 317232090Sjkim do_cpuid(0x80000001, regs); 318232090Sjkim switch ((regs[1] >> 28) & 0xf) { 319232090Sjkim case 0: /* Socket F */ 320232090Sjkim erratum319 = 1; 321232090Sjkim break; 322232090Sjkim case 1: /* Socket AM2+ or AM3 */ 323232090Sjkim if ((pci_cfgregread(pci_get_bus(dev), 324232090Sjkim pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & 325232090Sjkim AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || 326232090Sjkim (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) 327232090Sjkim break; 328232090Sjkim /* XXX 00100F42h (RB-C2) exists in both formats. */ 329232090Sjkim erratum319 = 1; 330232090Sjkim break; 331232090Sjkim } 332232090Sjkim /* FALLTHROUGH */ 333197102Sjkim case 0x11: 334232090Sjkim case 0x12: 335232090Sjkim case 0x14: 336232090Sjkim case 0x15: 337263869Sbrueffer case 0x16: 338197102Sjkim /* 339197102Sjkim * There is only one sensor per package. 340197102Sjkim */ 341197102Sjkim sc->sc_ntemps = 1; 342197102Sjkim 343189769Srpaulo sc->sc_gettemp = amdtemp_gettemp; 344197102Sjkim break; 345189769Srpaulo } 346189769Srpaulo 347197102Sjkim /* Find number of cores per package. */ 348197102Sjkim sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 349197102Sjkim (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 350197102Sjkim if (sc->sc_ncores > MAXCPU) 351197102Sjkim return (ENXIO); 352197102Sjkim 353232090Sjkim if (erratum319) 354232090Sjkim device_printf(dev, 355232090Sjkim "Erratum 319: temperature measurement may be inaccurate\n"); 356197102Sjkim if (bootverbose) 357197102Sjkim device_printf(dev, "Found %d cores and %d sensors.\n", 358197102Sjkim sc->sc_ncores, 359197102Sjkim sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 360197102Sjkim 361178151Srpaulo /* 362189769Srpaulo * dev.amdtemp.N tree. 363178151Srpaulo */ 364232090Sjkim unit = device_get_unit(dev); 365232090Sjkim snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); 366232090Sjkim TUNABLE_INT_FETCH(tn, &sc->sc_offset); 367232090Sjkim 368178151Srpaulo sysctlctx = device_get_sysctl_ctx(dev); 369232090Sjkim SYSCTL_ADD_INT(sysctlctx, 370232090Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 371232090Sjkim "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, 372232090Sjkim "Temperature sensor offset"); 373178151Srpaulo sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 374197102Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 375232090Sjkim "core0", CTLFLAG_RD, 0, "Core 0"); 376197102Sjkim 377178151Srpaulo SYSCTL_ADD_PROC(sysctlctx, 378178151Srpaulo SYSCTL_CHILDREN(sysctlnode), 379232090Sjkim OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 380232090Sjkim dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", 381232090Sjkim "Core 0 / Sensor 0 temperature"); 382178151Srpaulo 383197102Sjkim if (sc->sc_ntemps > 1) { 384197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 385197102Sjkim SYSCTL_CHILDREN(sysctlnode), 386232090Sjkim OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 387232090Sjkim dev, CORE0_SENSOR1, amdtemp_sysctl, "IK", 388232090Sjkim "Core 0 / Sensor 1 temperature"); 389197102Sjkim 390232090Sjkim if (sc->sc_ncores > 1) { 391232090Sjkim sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 392232090Sjkim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 393232090Sjkim OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1"); 394232090Sjkim 395197102Sjkim SYSCTL_ADD_PROC(sysctlctx, 396197102Sjkim SYSCTL_CHILDREN(sysctlnode), 397232090Sjkim OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 398232090Sjkim dev, CORE1_SENSOR0, amdtemp_sysctl, "IK", 399232090Sjkim "Core 1 / Sensor 0 temperature"); 400232090Sjkim 401232090Sjkim SYSCTL_ADD_PROC(sysctlctx, 402232090Sjkim SYSCTL_CHILDREN(sysctlnode), 403232090Sjkim OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 404232090Sjkim dev, CORE1_SENSOR1, amdtemp_sysctl, "IK", 405232090Sjkim "Core 1 / Sensor 1 temperature"); 406232090Sjkim } 407197102Sjkim } 408197102Sjkim 409197102Sjkim /* 410197102Sjkim * Try to create dev.cpu sysctl entries and setup intrhook function. 411197102Sjkim * This is needed because the cpu driver may be loaded late on boot, 412197102Sjkim * after us. 413197102Sjkim */ 414197102Sjkim amdtemp_intrhook(dev); 415197102Sjkim sc->sc_ich.ich_func = amdtemp_intrhook; 416197102Sjkim sc->sc_ich.ich_arg = dev; 417197102Sjkim if (config_intrhook_establish(&sc->sc_ich) != 0) { 418197102Sjkim device_printf(dev, "config_intrhook_establish failed!\n"); 419197102Sjkim return (ENXIO); 420197102Sjkim } 421197102Sjkim 422178151Srpaulo return (0); 423178151Srpaulo} 424178151Srpaulo 425180312Srpaulovoid 426189769Srpauloamdtemp_intrhook(void *arg) 427180312Srpaulo{ 428189769Srpaulo struct amdtemp_softc *sc; 429180312Srpaulo struct sysctl_ctx_list *sysctlctx; 430197102Sjkim device_t dev = (device_t)arg; 431197102Sjkim device_t acpi, cpu, nexus; 432197102Sjkim amdsensor_t sensor; 433197102Sjkim int i; 434180312Srpaulo 435180312Srpaulo sc = device_get_softc(dev); 436197102Sjkim 437180312Srpaulo /* 438180312Srpaulo * dev.cpu.N.temperature. 439180312Srpaulo */ 440180312Srpaulo nexus = device_find_child(root_bus, "nexus", 0); 441180312Srpaulo acpi = device_find_child(nexus, "acpi", 0); 442180312Srpaulo 443197102Sjkim for (i = 0; i < sc->sc_ncores; i++) { 444197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 445197102Sjkim continue; 446180312Srpaulo cpu = device_find_child(acpi, "cpu", 447197102Sjkim device_get_unit(dev) * sc->sc_ncores + i); 448197102Sjkim if (cpu != NULL) { 449180312Srpaulo sysctlctx = device_get_sysctl_ctx(cpu); 450180312Srpaulo 451197102Sjkim sensor = sc->sc_ntemps > 1 ? 452232090Sjkim (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; 453180312Srpaulo sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 454180312Srpaulo SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 455180312Srpaulo OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 456197102Sjkim dev, sensor, amdtemp_sysctl, "IK", 457197102Sjkim "Current temparature"); 458180312Srpaulo } 459180312Srpaulo } 460197102Sjkim if (sc->sc_ich.ich_arg != NULL) 461197102Sjkim config_intrhook_disestablish(&sc->sc_ich); 462180312Srpaulo} 463180312Srpaulo 464178151Srpauloint 465189769Srpauloamdtemp_detach(device_t dev) 466178151Srpaulo{ 467197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 468178151Srpaulo int i; 469197102Sjkim 470197102Sjkim for (i = 0; i < sc->sc_ncores; i++) 471197102Sjkim if (sc->sc_sysctl_cpu[i] != NULL) 472178151Srpaulo sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 473178151Srpaulo 474189769Srpaulo /* NewBus removes the dev.amdtemp.N tree by itself. */ 475197102Sjkim 476178151Srpaulo return (0); 477178151Srpaulo} 478178151Srpaulo 479178151Srpaulostatic int 480189769Srpauloamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 481178151Srpaulo{ 482197102Sjkim device_t dev = (device_t)arg1; 483189769Srpaulo struct amdtemp_softc *sc = device_get_softc(dev); 484197102Sjkim amdsensor_t sensor = (amdsensor_t)arg2; 485197102Sjkim int32_t auxtemp[2], temp; 486178151Srpaulo int error; 487178151Srpaulo 488197102Sjkim switch (sensor) { 489178151Srpaulo case CORE0: 490232090Sjkim auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); 491232090Sjkim auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); 492178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 493178151Srpaulo break; 494178151Srpaulo case CORE1: 495232090Sjkim auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); 496232090Sjkim auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); 497178988Srpaulo temp = imax(auxtemp[0], auxtemp[1]); 498178151Srpaulo break; 499178151Srpaulo default: 500197102Sjkim temp = sc->sc_gettemp(dev, sensor); 501178151Srpaulo break; 502178151Srpaulo } 503178151Srpaulo error = sysctl_handle_int(oidp, &temp, 0, req); 504197102Sjkim 505178151Srpaulo return (error); 506178151Srpaulo} 507178151Srpaulo 508197102Sjkim#define AMDTEMP_ZERO_C_TO_K 2732 509197102Sjkim 510178151Srpaulostatic int32_t 511189769Srpauloamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 512178151Srpaulo{ 513197102Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 514232090Sjkim uint32_t mask, offset, temp; 515197102Sjkim 516197102Sjkim /* Set Sensor/Core selector. */ 517232090Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 518232090Sjkim temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); 519178151Srpaulo switch (sensor) { 520232090Sjkim case CORE0_SENSOR1: 521232090Sjkim temp |= AMDTEMP_TTSR_SELSENSOR; 522197103Sjkim /* FALLTHROUGH */ 523232090Sjkim case CORE0_SENSOR0: 524197102Sjkim case CORE0: 525197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 526232090Sjkim temp |= AMDTEMP_TTSR_SELCORE; 527178151Srpaulo break; 528232090Sjkim case CORE1_SENSOR1: 529232090Sjkim temp |= AMDTEMP_TTSR_SELSENSOR; 530197103Sjkim /* FALLTHROUGH */ 531232090Sjkim case CORE1_SENSOR0: 532197102Sjkim case CORE1: 533197205Sjkim if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 534232090Sjkim temp |= AMDTEMP_TTSR_SELCORE; 535178151Srpaulo break; 536178151Srpaulo } 537232090Sjkim pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); 538197102Sjkim 539232090Sjkim mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 540232090Sjkim offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; 541197102Sjkim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 542232090Sjkim temp = ((temp >> 14) & mask) * 5 / 2; 543232090Sjkim temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; 544197102Sjkim 545178151Srpaulo return (temp); 546178151Srpaulo} 547189769Srpaulo 548189769Srpaulostatic int32_t 549189769Srpauloamdtemp_gettemp(device_t dev, amdsensor_t sensor) 550189769Srpaulo{ 551232090Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 552189769Srpaulo uint32_t temp; 553189769Srpaulo 554197102Sjkim temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 555232090Sjkim temp = ((temp >> 21) & 0x7ff) * 5 / 4; 556232090Sjkim temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; 557197102Sjkim 558189769Srpaulo return (temp); 559189769Srpaulo} 560