amdtemp.c revision 263169
133965Sjdp/*- 278828Sobrien * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 389857Sobrien * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 438889Sjdp * Copyright (c) 2009-2012 Jung-uk Kim <jkim@FreeBSD.org> 533965Sjdp * All rights reserved. 633965Sjdp * 733965Sjdp * Redistribution and use in source and binary forms, with or without 833965Sjdp * modification, are permitted provided that the following conditions 933965Sjdp * are met: 1033965Sjdp * 1. Redistributions of source code must retain the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer. 1233965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1333965Sjdp * notice, this list of conditions and the following disclaimer in the 1433965Sjdp * documentation and/or other materials provided with the distribution. 1533965Sjdp * 1633965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1733965Sjdp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1833965Sjdp * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1933965Sjdp * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2033965Sjdp * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2133965Sjdp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2233965Sjdp * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2333965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2433965Sjdp * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2533965Sjdp * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2633965Sjdp * POSSIBILITY OF SUCH DAMAGE. 2733965Sjdp */ 2833965Sjdp 2977298Sobrien/* 3033965Sjdp * Driver for the AMD CPU on-die thermal sensors. 3133965Sjdp * Initially based on the k8temp Linux driver. 3233965Sjdp */ 3333965Sjdp 3433965Sjdp#include <sys/cdefs.h> 3533965Sjdp__FBSDID("$FreeBSD: head/sys/dev/amdtemp/amdtemp.c 263169 2014-03-14 12:15:28Z brueffer $"); 3633965Sjdp 3733965Sjdp#include <sys/param.h> 3877298Sobrien#include <sys/bus.h> 3933965Sjdp#include <sys/conf.h> 4033965Sjdp#include <sys/kernel.h> 4133965Sjdp#include <sys/module.h> 4233965Sjdp#include <sys/sysctl.h> 4333965Sjdp#include <sys/systm.h> 4433965Sjdp 4533965Sjdp#include <machine/cpufunc.h> 4677298Sobrien#include <machine/md_var.h> 4733965Sjdp#include <machine/specialreg.h> 4833965Sjdp 4933965Sjdp#include <dev/pci/pcivar.h> 5077298Sobrien#include <x86/pci_cfgreg.h> 5133965Sjdp 5233965Sjdptypedef enum { 5333965Sjdp CORE0_SENSOR0, 5433965Sjdp CORE0_SENSOR1, 5533965Sjdp CORE1_SENSOR0, 5633965Sjdp CORE1_SENSOR1, 5733965Sjdp CORE0, 5833965Sjdp CORE1 5933965Sjdp} amdsensor_t; 6077298Sobrien 6133965Sjdpstruct amdtemp_softc { 6233965Sjdp device_t sc_dev; 6333965Sjdp int sc_ncores; 6433965Sjdp int sc_ntemps; 6533965Sjdp int sc_flags; 6633965Sjdp#define AMDTEMP_FLAG_CS_SWAP 0x01 /* ThermSenseCoreSel is inverted. */ 6733965Sjdp#define AMDTEMP_FLAG_CT_10BIT 0x02 /* CurTmp is 10-bit wide. */ 6833965Sjdp#define AMDTEMP_FLAG_ALT_OFFSET 0x04 /* CurTmp starts at -28C. */ 6933965Sjdp int32_t sc_offset; 7077298Sobrien int32_t (*sc_gettemp)(device_t, amdsensor_t); 7133965Sjdp struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 7233965Sjdp struct intr_config_hook sc_ich; 7333965Sjdp}; 7433965Sjdp 7533965Sjdp#define VENDORID_AMD 0x1022 7633965Sjdp#define DEVICEID_AMD_MISC0F 0x1103 7733965Sjdp#define DEVICEID_AMD_MISC10 0x1203 7833965Sjdp#define DEVICEID_AMD_MISC11 0x1303 7933965Sjdp#define DEVICEID_AMD_MISC12 0x1403 8033965Sjdp#define DEVICEID_AMD_MISC14 0x1703 8133965Sjdp#define DEVICEID_AMD_MISC15 0x1603 8233965Sjdp#define DEVICEID_AMD_MISC16 0x1533 8333965Sjdp 8433965Sjdpstatic struct amdtemp_product { 8533965Sjdp uint16_t amdtemp_vendorid; 8633965Sjdp uint16_t amdtemp_deviceid; 8733965Sjdp} amdtemp_products[] = { 8833965Sjdp { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 8933965Sjdp { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 9077298Sobrien { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 9133965Sjdp { VENDORID_AMD, DEVICEID_AMD_MISC12 }, 9233965Sjdp { VENDORID_AMD, DEVICEID_AMD_MISC14 }, 9377298Sobrien { VENDORID_AMD, DEVICEID_AMD_MISC15 }, 9433965Sjdp { VENDORID_AMD, DEVICEID_AMD_MISC16 }, 9533965Sjdp { 0, 0 } 9633965Sjdp}; 9733965Sjdp 9833965Sjdp/* 9933965Sjdp * Reported Temperature Control Register 10077298Sobrien */ 10133965Sjdp#define AMDTEMP_REPTMP_CTRL 0xa4 10233965Sjdp 10333965Sjdp/* 10433965Sjdp * Thermaltrip Status Register (Family 0Fh only) 10533965Sjdp */ 10633965Sjdp#define AMDTEMP_THERMTP_STAT 0xe4 10733965Sjdp#define AMDTEMP_TTSR_SELCORE 0x04 10833965Sjdp#define AMDTEMP_TTSR_SELSENSOR 0x40 10933965Sjdp 11033965Sjdp/* 11133965Sjdp * DRAM Configuration High Register 11233965Sjdp */ 11333965Sjdp#define AMDTEMP_DRAM_CONF_HIGH 0x94 /* Function 2 */ 11433965Sjdp#define AMDTEMP_DRAM_MODE_DDR3 0x0100 11533965Sjdp 11633965Sjdp/* 11733965Sjdp * CPU Family/Model Register 11833965Sjdp */ 11977298Sobrien#define AMDTEMP_CPUID 0xfc 12033965Sjdp 12133965Sjdp/* 12233965Sjdp * Device methods. 12333965Sjdp */ 12433965Sjdpstatic void amdtemp_identify(driver_t *driver, device_t parent); 12577298Sobrienstatic int amdtemp_probe(device_t dev); 12633965Sjdpstatic int amdtemp_attach(device_t dev); 12733965Sjdpstatic void amdtemp_intrhook(void *arg); 12891041Sobrienstatic int amdtemp_detach(device_t dev); 12933965Sjdpstatic int amdtemp_match(device_t dev); 13033965Sjdpstatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 13133965Sjdpstatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 13233965Sjdpstatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 13333965Sjdp 13433965Sjdpstatic device_method_t amdtemp_methods[] = { 13533965Sjdp /* Device interface */ 13677298Sobrien DEVMETHOD(device_identify, amdtemp_identify), 13733965Sjdp DEVMETHOD(device_probe, amdtemp_probe), 13891041Sobrien DEVMETHOD(device_attach, amdtemp_attach), 13991041Sobrien DEVMETHOD(device_detach, amdtemp_detach), 14033965Sjdp 14133965Sjdp DEVMETHOD_END 14233965Sjdp}; 14333965Sjdp 14477298Sobrienstatic driver_t amdtemp_driver = { 14533965Sjdp "amdtemp", 14633965Sjdp amdtemp_methods, 14733965Sjdp sizeof(struct amdtemp_softc), 14833965Sjdp}; 14933965Sjdp 15033965Sjdpstatic devclass_t amdtemp_devclass; 15133965SjdpDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 15233965Sjdp 15333965Sjdpstatic int 15433965Sjdpamdtemp_match(device_t dev) 15533965Sjdp{ 15660484Sobrien int i; 15789857Sobrien uint16_t vendor, devid; 15889857Sobrien 15933965Sjdp vendor = pci_get_vendor(dev); 16033965Sjdp devid = pci_get_device(dev); 16133965Sjdp 16233965Sjdp for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 16333965Sjdp if (vendor == amdtemp_products[i].amdtemp_vendorid && 16433965Sjdp devid == amdtemp_products[i].amdtemp_deviceid) 16533965Sjdp return (1); 16633965Sjdp } 16733965Sjdp 16891041Sobrien return (0); 16933965Sjdp} 17091041Sobrien 17191041Sobrienstatic void 17291041Sobrienamdtemp_identify(driver_t *driver, device_t parent) 17333965Sjdp{ 17491041Sobrien device_t child; 17591041Sobrien 17633965Sjdp /* Make sure we're not being doubly invoked. */ 17791041Sobrien if (device_find_child(parent, "amdtemp", -1) != NULL) 17891041Sobrien return; 17933965Sjdp 18091041Sobrien if (amdtemp_match(parent)) { 18191041Sobrien child = device_add_child(parent, "amdtemp", -1); 18291041Sobrien if (child == NULL) 18377298Sobrien device_printf(parent, "add amdtemp child failed\n"); 18491041Sobrien } 18591041Sobrien} 18691041Sobrien 18733965Sjdpstatic int 18891041Sobrienamdtemp_probe(device_t dev) 18991041Sobrien{ 19091041Sobrien uint32_t family, model; 19133965Sjdp 19291041Sobrien if (resource_disabled("amdtemp", 0)) 19391041Sobrien return (ENXIO); 19477298Sobrien 19591041Sobrien family = CPUID_TO_FAMILY(cpu_id); 19691041Sobrien model = CPUID_TO_MODEL(cpu_id); 19733965Sjdp 19891041Sobrien switch (family) { 19991041Sobrien case 0x0f: 20091041Sobrien if ((model == 0x04 && (cpu_id & CPUID_STEPPING) == 0) || 20191041Sobrien (model == 0x05 && (cpu_id & CPUID_STEPPING) <= 1)) 20289857Sobrien return (ENXIO); 20333965Sjdp break; 20489857Sobrien case 0x10: 20589857Sobrien case 0x11: 20633965Sjdp case 0x12: 20789857Sobrien case 0x14: 20889857Sobrien case 0x15: 20933965Sjdp case 0x16: 21089857Sobrien break; 21191041Sobrien default: 21291041Sobrien return (ENXIO); 21389857Sobrien } 21433965Sjdp device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 21589857Sobrien 21689857Sobrien return (BUS_PROBE_GENERIC); 21733965Sjdp} 21889857Sobrien 21989857Sobrienstatic int 22033965Sjdpamdtemp_attach(device_t dev) 22189857Sobrien{ 22291041Sobrien char tn[32]; 22391041Sobrien u_int regs[4]; 22491041Sobrien struct amdtemp_softc *sc = device_get_softc(dev); 22591041Sobrien struct sysctl_ctx_list *sysctlctx; 22691041Sobrien struct sysctl_oid *sysctlnode; 22733965Sjdp uint32_t cpuid, family, model; 22891041Sobrien u_int bid; 22991041Sobrien int erratum319, unit; 23089857Sobrien 23191041Sobrien erratum319 = 0; 23291041Sobrien 23389857Sobrien /* 23491041Sobrien * CPUID Register is available from Revision F. 23560484Sobrien */ 23660484Sobrien cpuid = cpu_id; 23733965Sjdp family = CPUID_TO_FAMILY(cpuid); 23833965Sjdp model = CPUID_TO_MODEL(cpuid); 23989857Sobrien if (family != 0x0f || model >= 0x40) { 24089857Sobrien cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 24189857Sobrien family = CPUID_TO_FAMILY(cpuid); 24289857Sobrien model = CPUID_TO_MODEL(cpuid); 24389857Sobrien } 24489857Sobrien 24589857Sobrien switch (family) { 24689857Sobrien case 0x0f: 24789857Sobrien /* 24833965Sjdp * Thermaltrip Status Register 24933965Sjdp * 25089857Sobrien * - ThermSenseCoreSel 25133965Sjdp * 25289857Sobrien * Revision F & G: 0 - Core1, 1 - Core0 25333965Sjdp * Other: 0 - Core0, 1 - Core1 25489857Sobrien * 25533965Sjdp * - CurTmp 25689857Sobrien * 25789857Sobrien * Revision G: bits 23-14 25889857Sobrien * Other: bits 23-16 25989857Sobrien * 26033965Sjdp * XXX According to the BKDG, CurTmp, ThermSenseSel and 26133965Sjdp * ThermSenseCoreSel bits were introduced in Revision F 26289857Sobrien * but CurTmp seems working fine as early as Revision C. 26389857Sobrien * However, it is not clear whether ThermSenseSel and/or 26489857Sobrien * ThermSenseCoreSel work in undocumented cases as well. 26589857Sobrien * In fact, the Linux driver suggests it may not work but 26689857Sobrien * we just assume it does until we find otherwise. 26789857Sobrien * 26889857Sobrien * XXX According to Linux, CurTmp starts at -28C on 26933965Sjdp * Socket AM2 Revision G processors, which is not 27033965Sjdp * documented anywhere. 27189857Sobrien */ 27233965Sjdp if (model >= 0x40) 27333965Sjdp sc->sc_flags |= AMDTEMP_FLAG_CS_SWAP; 27489857Sobrien if (model >= 0x60 && model != 0xc1) { 27533965Sjdp do_cpuid(0x80000001, regs); 27633965Sjdp bid = (regs[1] >> 9) & 0x1f; 27789857Sobrien switch (model) { 27889857Sobrien case 0x68: /* Socket S1g1 */ 27977298Sobrien case 0x6c: 28033965Sjdp case 0x7c: 28189857Sobrien break; 28289857Sobrien case 0x6b: /* Socket AM2 and ASB1 (2 cores) */ 28391041Sobrien if (bid != 0x0b && bid != 0x0c) 28489857Sobrien sc->sc_flags |= 28533965Sjdp AMDTEMP_FLAG_ALT_OFFSET; 28691041Sobrien break; 28789857Sobrien case 0x6f: /* Socket AM2 and ASB1 (1 core) */ 28833965Sjdp case 0x7f: 28933965Sjdp if (bid != 0x07 && bid != 0x09 && 29089857Sobrien bid != 0x0c) 29189857Sobrien sc->sc_flags |= 29289857Sobrien AMDTEMP_FLAG_ALT_OFFSET; 29389857Sobrien break; 29433965Sjdp default: 29533965Sjdp sc->sc_flags |= AMDTEMP_FLAG_ALT_OFFSET; 29633965Sjdp } 29733965Sjdp sc->sc_flags |= AMDTEMP_FLAG_CT_10BIT; 29833965Sjdp } 29989857Sobrien 30089857Sobrien /* 30189857Sobrien * There are two sensors per core. 30289857Sobrien */ 30389857Sobrien sc->sc_ntemps = 2; 30489857Sobrien 30589857Sobrien sc->sc_gettemp = amdtemp_gettemp0f; 30689857Sobrien break; 30789857Sobrien case 0x10: 30889857Sobrien /* 30989857Sobrien * Erratum 319 Inaccurate Temperature Measurement 31033965Sjdp * 31133965Sjdp * http://support.amd.com/us/Processor_TechDocs/41322.pdf 31233965Sjdp */ 31389857Sobrien do_cpuid(0x80000001, regs); 31489857Sobrien switch ((regs[1] >> 28) & 0xf) { 31589857Sobrien case 0: /* Socket F */ 31689857Sobrien erratum319 = 1; 31789857Sobrien break; 31889857Sobrien case 1: /* Socket AM2+ or AM3 */ 31933965Sjdp if ((pci_cfgregread(pci_get_bus(dev), 32033965Sjdp pci_get_slot(dev), 2, AMDTEMP_DRAM_CONF_HIGH, 2) & 32133965Sjdp AMDTEMP_DRAM_MODE_DDR3) != 0 || model > 0x04 || 32233965Sjdp (model == 0x04 && (cpuid & CPUID_STEPPING) >= 3)) 32333965Sjdp break; 32433965Sjdp /* XXX 00100F42h (RB-C2) exists in both formats. */ 32589857Sobrien erratum319 = 1; 32689857Sobrien break; 32789857Sobrien } 32889857Sobrien /* FALLTHROUGH */ 32989857Sobrien case 0x11: 33089857Sobrien case 0x12: 33189857Sobrien case 0x14: 33289857Sobrien case 0x15: 33389857Sobrien case 0x16: 33489857Sobrien /* 33589857Sobrien * There is only one sensor per package. 33689857Sobrien */ 33789857Sobrien sc->sc_ntemps = 1; 33889857Sobrien 33989857Sobrien sc->sc_gettemp = amdtemp_gettemp; 34089857Sobrien break; 34189857Sobrien } 34289857Sobrien 34389857Sobrien /* Find number of cores per package. */ 34489857Sobrien sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 34533965Sjdp (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 34689857Sobrien if (sc->sc_ncores > MAXCPU) 34789857Sobrien return (ENXIO); 34889857Sobrien 34933965Sjdp if (erratum319) 35089857Sobrien device_printf(dev, 35133965Sjdp "Erratum 319: temperature measurement may be inaccurate\n"); 35289857Sobrien if (bootverbose) 35389857Sobrien device_printf(dev, "Found %d cores and %d sensors.\n", 35489857Sobrien sc->sc_ncores, 35589857Sobrien sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 35633965Sjdp 35733965Sjdp /* 35833965Sjdp * dev.amdtemp.N tree. 35989857Sobrien */ 36089857Sobrien unit = device_get_unit(dev); 36133965Sjdp snprintf(tn, sizeof(tn), "dev.amdtemp.%d.sensor_offset", unit); 36233965Sjdp TUNABLE_INT_FETCH(tn, &sc->sc_offset); 36389857Sobrien 36489857Sobrien sysctlctx = device_get_sysctl_ctx(dev); 36533965Sjdp SYSCTL_ADD_INT(sysctlctx, 36633965Sjdp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 36733965Sjdp "sensor_offset", CTLFLAG_RW, &sc->sc_offset, 0, 36833965Sjdp "Temperature sensor offset"); 36933965Sjdp sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 37033965Sjdp SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 37189857Sobrien "core0", CTLFLAG_RD, 0, "Core 0"); 37289857Sobrien 37389857Sobrien SYSCTL_ADD_PROC(sysctlctx, 37489857Sobrien SYSCTL_CHILDREN(sysctlnode), 37589857Sobrien OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 37689857Sobrien dev, CORE0_SENSOR0, amdtemp_sysctl, "IK", 37789857Sobrien "Core 0 / Sensor 0 temperature"); 37833965Sjdp 37933965Sjdp if (sc->sc_ntemps > 1) { 38089857Sobrien SYSCTL_ADD_PROC(sysctlctx, 38133965Sjdp SYSCTL_CHILDREN(sysctlnode), 38233965Sjdp OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 38389857Sobrien dev, CORE0_SENSOR1, amdtemp_sysctl, "IK", 38489857Sobrien "Core 0 / Sensor 1 temperature"); 38589857Sobrien 38689857Sobrien if (sc->sc_ncores > 1) { 38789857Sobrien sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 38889857Sobrien SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 38989857Sobrien OID_AUTO, "core1", CTLFLAG_RD, 0, "Core 1"); 39033965Sjdp 39133965Sjdp SYSCTL_ADD_PROC(sysctlctx, 39289857Sobrien SYSCTL_CHILDREN(sysctlnode), 39389857Sobrien OID_AUTO, "sensor0", CTLTYPE_INT | CTLFLAG_RD, 39489857Sobrien dev, CORE1_SENSOR0, amdtemp_sysctl, "IK", 39589857Sobrien "Core 1 / Sensor 0 temperature"); 39689857Sobrien 39789857Sobrien SYSCTL_ADD_PROC(sysctlctx, 39889857Sobrien SYSCTL_CHILDREN(sysctlnode), 39989857Sobrien OID_AUTO, "sensor1", CTLTYPE_INT | CTLFLAG_RD, 40089857Sobrien dev, CORE1_SENSOR1, amdtemp_sysctl, "IK", 40189857Sobrien "Core 1 / Sensor 1 temperature"); 40289857Sobrien } 40389857Sobrien } 40489857Sobrien 40589857Sobrien /* 40633965Sjdp * Try to create dev.cpu sysctl entries and setup intrhook function. 40789857Sobrien * This is needed because the cpu driver may be loaded late on boot, 40889857Sobrien * after us. 40933965Sjdp */ 41033965Sjdp amdtemp_intrhook(dev); 41133965Sjdp sc->sc_ich.ich_func = amdtemp_intrhook; 41233965Sjdp sc->sc_ich.ich_arg = dev; 41333965Sjdp if (config_intrhook_establish(&sc->sc_ich) != 0) { 41433965Sjdp device_printf(dev, "config_intrhook_establish failed!\n"); 41589857Sobrien return (ENXIO); 41633965Sjdp } 41733965Sjdp 41833965Sjdp return (0); 41989857Sobrien} 42033965Sjdp 42133965Sjdpvoid 42289857Sobrienamdtemp_intrhook(void *arg) 42333965Sjdp{ 42460484Sobrien struct amdtemp_softc *sc; 42589857Sobrien struct sysctl_ctx_list *sysctlctx; 42660484Sobrien device_t dev = (device_t)arg; 42789857Sobrien device_t acpi, cpu, nexus; 42889857Sobrien amdsensor_t sensor; 42989857Sobrien int i; 43060484Sobrien 43189857Sobrien sc = device_get_softc(dev); 43289857Sobrien 43389857Sobrien /* 43489857Sobrien * dev.cpu.N.temperature. 43589857Sobrien */ 43691041Sobrien nexus = device_find_child(root_bus, "nexus", 0); 43789857Sobrien acpi = device_find_child(nexus, "acpi", 0); 43833965Sjdp 43989857Sobrien for (i = 0; i < sc->sc_ncores; i++) { 44033965Sjdp if (sc->sc_sysctl_cpu[i] != NULL) 44133965Sjdp continue; 44289857Sobrien cpu = device_find_child(acpi, "cpu", 44333965Sjdp device_get_unit(dev) * sc->sc_ncores + i); 44489857Sobrien if (cpu != NULL) { 44533965Sjdp sysctlctx = device_get_sysctl_ctx(cpu); 44633965Sjdp 44733965Sjdp sensor = sc->sc_ntemps > 1 ? 44860484Sobrien (i == 0 ? CORE0 : CORE1) : CORE0_SENSOR0; 44960484Sobrien sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 45060484Sobrien SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 45160484Sobrien OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 45260484Sobrien dev, sensor, amdtemp_sysctl, "IK", 45360484Sobrien "Current temparature"); 45491041Sobrien } 45591041Sobrien } 45677298Sobrien if (sc->sc_ich.ich_arg != NULL) 45760484Sobrien config_intrhook_disestablish(&sc->sc_ich); 45891041Sobrien} 45991041Sobrien 46091041Sobrienint 46177298Sobrienamdtemp_detach(device_t dev) 46233965Sjdp{ 46391041Sobrien struct amdtemp_softc *sc = device_get_softc(dev); 46433965Sjdp int i; 46533965Sjdp 46633965Sjdp for (i = 0; i < sc->sc_ncores; i++) 46733965Sjdp if (sc->sc_sysctl_cpu[i] != NULL) 46833965Sjdp sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 46933965Sjdp 47033965Sjdp /* NewBus removes the dev.amdtemp.N tree by itself. */ 47133965Sjdp 47277298Sobrien return (0); 47333965Sjdp} 47433965Sjdp 47533965Sjdpstatic int 47633965Sjdpamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 47733965Sjdp{ 47877298Sobrien device_t dev = (device_t)arg1; 47977298Sobrien struct amdtemp_softc *sc = device_get_softc(dev); 48077298Sobrien amdsensor_t sensor = (amdsensor_t)arg2; 48177298Sobrien int32_t auxtemp[2], temp; 48277298Sobrien int error; 48333965Sjdp 48460484Sobrien switch (sensor) { 48577298Sobrien case CORE0: 48633965Sjdp auxtemp[0] = sc->sc_gettemp(dev, CORE0_SENSOR0); 48777298Sobrien auxtemp[1] = sc->sc_gettemp(dev, CORE0_SENSOR1); 48833965Sjdp temp = imax(auxtemp[0], auxtemp[1]); 48933965Sjdp break; 49033965Sjdp case CORE1: 49177298Sobrien auxtemp[0] = sc->sc_gettemp(dev, CORE1_SENSOR0); 49277298Sobrien auxtemp[1] = sc->sc_gettemp(dev, CORE1_SENSOR1); 49360484Sobrien temp = imax(auxtemp[0], auxtemp[1]); 49477298Sobrien break; 49538889Sjdp default: 49677298Sobrien temp = sc->sc_gettemp(dev, sensor); 49760484Sobrien break; 49833965Sjdp } 49977298Sobrien error = sysctl_handle_int(oidp, &temp, 0, req); 50033965Sjdp 50160484Sobrien return (error); 50277298Sobrien} 50389857Sobrien 50477298Sobrien#define AMDTEMP_ZERO_C_TO_K 2732 50533965Sjdp 50660484Sobrienstatic int32_t 50733965Sjdpamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 50877298Sobrien{ 50933965Sjdp struct amdtemp_softc *sc = device_get_softc(dev); 51060484Sobrien uint32_t mask, offset, temp; 51177298Sobrien 51289857Sobrien /* Set Sensor/Core selector. */ 51333965Sjdp temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 51477298Sobrien temp &= ~(AMDTEMP_TTSR_SELCORE | AMDTEMP_TTSR_SELSENSOR); 51577298Sobrien switch (sensor) { 51677298Sobrien case CORE0_SENSOR1: 51733965Sjdp temp |= AMDTEMP_TTSR_SELSENSOR; 51833965Sjdp /* FALLTHROUGH */ 51977298Sobrien case CORE0_SENSOR0: 52077298Sobrien case CORE0: 52133965Sjdp if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) != 0) 52233965Sjdp temp |= AMDTEMP_TTSR_SELCORE; 52377298Sobrien break; 52477298Sobrien case CORE1_SENSOR1: 52533965Sjdp temp |= AMDTEMP_TTSR_SELSENSOR; 52633965Sjdp /* FALLTHROUGH */ 52789857Sobrien case CORE1_SENSOR0: 52891041Sobrien case CORE1: 52960484Sobrien if ((sc->sc_flags & AMDTEMP_FLAG_CS_SWAP) == 0) 53060484Sobrien temp |= AMDTEMP_TTSR_SELCORE; 53133965Sjdp break; 53233965Sjdp } 53389857Sobrien pci_write_config(dev, AMDTEMP_THERMTP_STAT, temp, 1); 53433965Sjdp 53577298Sobrien mask = (sc->sc_flags & AMDTEMP_FLAG_CT_10BIT) != 0 ? 0x3ff : 0x3fc; 53633965Sjdp offset = (sc->sc_flags & AMDTEMP_FLAG_ALT_OFFSET) != 0 ? 28 : 49; 53777298Sobrien temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 53889857Sobrien temp = ((temp >> 14) & mask) * 5 / 2; 53989857Sobrien temp += AMDTEMP_ZERO_C_TO_K + (sc->sc_offset - offset) * 10; 54033965Sjdp 54177298Sobrien return (temp); 54277298Sobrien} 54377298Sobrien 54438889Sjdpstatic int32_t 54589857Sobrienamdtemp_gettemp(device_t dev, amdsensor_t sensor) 54677298Sobrien{ 54733965Sjdp struct amdtemp_softc *sc = device_get_softc(dev); 54877298Sobrien uint32_t temp; 54977298Sobrien 55077298Sobrien temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 55189857Sobrien temp = ((temp >> 21) & 0x7ff) * 5 / 4; 55289857Sobrien temp += AMDTEMP_ZERO_C_TO_K + sc->sc_offset * 10; 55377298Sobrien 55489857Sobrien return (temp); 55577298Sobrien} 55633965Sjdp