1fc1f75e5SRui Paulo /*- 2454e82d7SRui Paulo * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 3454e82d7SRui Paulo * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 4a4165bbaSJung-uk Kim * Copyright (c) 2009 Jung-uk Kim <jkim@FreeBSD.org> 5fc1f75e5SRui Paulo * All rights reserved. 6fc1f75e5SRui Paulo * 7fc1f75e5SRui Paulo * Redistribution and use in source and binary forms, with or without 8fc1f75e5SRui Paulo * modification, are permitted provided that the following conditions 9fc1f75e5SRui Paulo * are met: 10fc1f75e5SRui Paulo * 1. Redistributions of source code must retain the above copyright 11fc1f75e5SRui Paulo * notice, this list of conditions and the following disclaimer. 12fc1f75e5SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 13fc1f75e5SRui Paulo * notice, this list of conditions and the following disclaimer in the 14fc1f75e5SRui Paulo * documentation and/or other materials provided with the distribution. 15fc1f75e5SRui Paulo * 16fc1f75e5SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17fc1f75e5SRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18fc1f75e5SRui Paulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19fc1f75e5SRui Paulo * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20fc1f75e5SRui Paulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21fc1f75e5SRui Paulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22fc1f75e5SRui Paulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23fc1f75e5SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24fc1f75e5SRui Paulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25fc1f75e5SRui Paulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26fc1f75e5SRui Paulo * POSSIBILITY OF SUCH DAMAGE. 27fc1f75e5SRui Paulo */ 28fc1f75e5SRui Paulo 29fc1f75e5SRui Paulo /* 30a4165bbaSJung-uk Kim * Driver for the AMD CPU on-die thermal sensors for Family 0Fh/10h/11h procs. 31a4165bbaSJung-uk Kim * Initially based on the k8temp Linux driver. 32fc1f75e5SRui Paulo */ 33fc1f75e5SRui Paulo 34fc1f75e5SRui Paulo #include <sys/cdefs.h> 35fc1f75e5SRui Paulo __FBSDID("$FreeBSD$"); 36fc1f75e5SRui Paulo 37fc1f75e5SRui Paulo #include <sys/param.h> 38fc1f75e5SRui Paulo #include <sys/bus.h> 39fc1f75e5SRui Paulo #include <sys/conf.h> 40fc1f75e5SRui Paulo #include <sys/kernel.h> 41a4165bbaSJung-uk Kim #include <sys/module.h> 42fc1f75e5SRui Paulo #include <sys/sysctl.h> 43a4165bbaSJung-uk Kim #include <sys/systm.h> 44fc1f75e5SRui Paulo 45fc1f75e5SRui Paulo #include <machine/md_var.h> 46a4165bbaSJung-uk Kim #include <machine/specialreg.h> 47fc1f75e5SRui Paulo 48fc1f75e5SRui Paulo #include <dev/pci/pcivar.h> 49fc1f75e5SRui Paulo 50fc1f75e5SRui Paulo typedef enum { 51fc1f75e5SRui Paulo SENSOR0_CORE0, 52fc1f75e5SRui Paulo SENSOR0_CORE1, 53fc1f75e5SRui Paulo SENSOR1_CORE0, 54fc1f75e5SRui Paulo SENSOR1_CORE1, 55fc1f75e5SRui Paulo CORE0, 56fc1f75e5SRui Paulo CORE1 57454e82d7SRui Paulo } amdsensor_t; 58454e82d7SRui Paulo 59454e82d7SRui Paulo struct amdtemp_softc { 60454e82d7SRui Paulo device_t sc_dev; 61a4165bbaSJung-uk Kim uint32_t sc_mask; 62a4165bbaSJung-uk Kim int sc_ncores; 63454e82d7SRui Paulo int sc_ntemps; 64a4165bbaSJung-uk Kim int sc_swap; 65454e82d7SRui Paulo int32_t (*sc_gettemp)(device_t, amdsensor_t); 66a4165bbaSJung-uk Kim struct sysctl_oid *sc_sysctl_cpu[MAXCPU]; 67a4165bbaSJung-uk Kim struct intr_config_hook sc_ich; 68454e82d7SRui Paulo }; 69454e82d7SRui Paulo 70454e82d7SRui Paulo #define VENDORID_AMD 0x1022 71454e82d7SRui Paulo #define DEVICEID_AMD_MISC0F 0x1103 72454e82d7SRui Paulo #define DEVICEID_AMD_MISC10 0x1203 73454e82d7SRui Paulo #define DEVICEID_AMD_MISC11 0x1303 74454e82d7SRui Paulo 75454e82d7SRui Paulo static struct amdtemp_product { 76454e82d7SRui Paulo uint16_t amdtemp_vendorid; 77454e82d7SRui Paulo uint16_t amdtemp_deviceid; 78454e82d7SRui Paulo } amdtemp_products[] = { 79454e82d7SRui Paulo { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 80454e82d7SRui Paulo { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 81454e82d7SRui Paulo { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 82454e82d7SRui Paulo { 0, 0 } 83454e82d7SRui Paulo }; 84454e82d7SRui Paulo 85454e82d7SRui Paulo /* 86a4165bbaSJung-uk Kim * Reported Temperature Control Register (Family 10h/11h only) 87454e82d7SRui Paulo */ 88a4165bbaSJung-uk Kim #define AMDTEMP_REPTMP_CTRL 0xa4 89454e82d7SRui Paulo 90454e82d7SRui Paulo /* 91a4165bbaSJung-uk Kim * Thermaltrip Status Register 92454e82d7SRui Paulo */ 93a4165bbaSJung-uk Kim #define AMDTEMP_THERMTP_STAT 0xe4 94a4165bbaSJung-uk Kim #define AMDTEMP_TTSR_SELCORE 0x04 /* Family 0Fh only */ 95a4165bbaSJung-uk Kim #define AMDTEMP_TTSR_SELSENSOR 0x40 /* Family 0Fh only */ 96454e82d7SRui Paulo 97a4165bbaSJung-uk Kim /* 98a4165bbaSJung-uk Kim * CPU Family/Model Register 99a4165bbaSJung-uk Kim */ 100a4165bbaSJung-uk Kim #define AMDTEMP_CPUID 0xfc 101fc1f75e5SRui Paulo 102fc1f75e5SRui Paulo /* 103fc1f75e5SRui Paulo * Device methods. 104fc1f75e5SRui Paulo */ 105454e82d7SRui Paulo static void amdtemp_identify(driver_t *driver, device_t parent); 106454e82d7SRui Paulo static int amdtemp_probe(device_t dev); 107454e82d7SRui Paulo static int amdtemp_attach(device_t dev); 108454e82d7SRui Paulo static void amdtemp_intrhook(void *arg); 109454e82d7SRui Paulo static int amdtemp_detach(device_t dev); 110454e82d7SRui Paulo static int amdtemp_match(device_t dev); 111454e82d7SRui Paulo static int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 112454e82d7SRui Paulo static int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 113454e82d7SRui Paulo static int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 114fc1f75e5SRui Paulo 115454e82d7SRui Paulo static device_method_t amdtemp_methods[] = { 116fc1f75e5SRui Paulo /* Device interface */ 117454e82d7SRui Paulo DEVMETHOD(device_identify, amdtemp_identify), 118454e82d7SRui Paulo DEVMETHOD(device_probe, amdtemp_probe), 119454e82d7SRui Paulo DEVMETHOD(device_attach, amdtemp_attach), 120454e82d7SRui Paulo DEVMETHOD(device_detach, amdtemp_detach), 121fc1f75e5SRui Paulo 122fc1f75e5SRui Paulo {0, 0} 123fc1f75e5SRui Paulo }; 124fc1f75e5SRui Paulo 125454e82d7SRui Paulo static driver_t amdtemp_driver = { 126454e82d7SRui Paulo "amdtemp", 127454e82d7SRui Paulo amdtemp_methods, 128454e82d7SRui Paulo sizeof(struct amdtemp_softc), 129fc1f75e5SRui Paulo }; 130fc1f75e5SRui Paulo 131454e82d7SRui Paulo static devclass_t amdtemp_devclass; 132454e82d7SRui Paulo DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 133fc1f75e5SRui Paulo 134fc1f75e5SRui Paulo static int 135454e82d7SRui Paulo amdtemp_match(device_t dev) 136fc1f75e5SRui Paulo { 137fc1f75e5SRui Paulo int i; 138fc1f75e5SRui Paulo uint16_t vendor, devid; 139fc1f75e5SRui Paulo 140fc1f75e5SRui Paulo vendor = pci_get_vendor(dev); 141fc1f75e5SRui Paulo devid = pci_get_device(dev); 142fc1f75e5SRui Paulo 143454e82d7SRui Paulo for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 144454e82d7SRui Paulo if (vendor == amdtemp_products[i].amdtemp_vendorid && 145454e82d7SRui Paulo devid == amdtemp_products[i].amdtemp_deviceid) 146fc1f75e5SRui Paulo return (1); 147fc1f75e5SRui Paulo } 148fc1f75e5SRui Paulo 149fc1f75e5SRui Paulo return (0); 150fc1f75e5SRui Paulo } 151fc1f75e5SRui Paulo 152fc1f75e5SRui Paulo static void 153454e82d7SRui Paulo amdtemp_identify(driver_t *driver, device_t parent) 154fc1f75e5SRui Paulo { 155fc1f75e5SRui Paulo device_t child; 156fc1f75e5SRui Paulo 157fc1f75e5SRui Paulo /* Make sure we're not being doubly invoked. */ 158454e82d7SRui Paulo if (device_find_child(parent, "amdtemp", -1) != NULL) 159fc1f75e5SRui Paulo return; 160fc1f75e5SRui Paulo 161454e82d7SRui Paulo if (amdtemp_match(parent)) { 162454e82d7SRui Paulo child = device_add_child(parent, "amdtemp", -1); 163fc1f75e5SRui Paulo if (child == NULL) 164454e82d7SRui Paulo device_printf(parent, "add amdtemp child failed\n"); 165fc1f75e5SRui Paulo } 166fc1f75e5SRui Paulo } 167fc1f75e5SRui Paulo 168fc1f75e5SRui Paulo static int 169454e82d7SRui Paulo amdtemp_probe(device_t dev) 170fc1f75e5SRui Paulo { 171a4165bbaSJung-uk Kim uint32_t cpuid, family, model, temp; 172fc1f75e5SRui Paulo 173454e82d7SRui Paulo if (resource_disabled("amdtemp", 0)) 174fc1f75e5SRui Paulo return (ENXIO); 175fc1f75e5SRui Paulo 176a4165bbaSJung-uk Kim cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 177a4165bbaSJung-uk Kim family = CPUID_TO_FAMILY(cpuid); 178a4165bbaSJung-uk Kim model = CPUID_TO_MODEL(cpuid); 179a4165bbaSJung-uk Kim 180a4165bbaSJung-uk Kim switch (family) { 181a4165bbaSJung-uk Kim case 0x0f: 182a4165bbaSJung-uk Kim if ((model == 0x04 && (cpuid & CPUID_STEPPING) == 0) || 183a4165bbaSJung-uk Kim (model == 0x05 && (cpuid & CPUID_STEPPING) <= 1)) 184a4165bbaSJung-uk Kim return (ENXIO); 185a4165bbaSJung-uk Kim break; 186a4165bbaSJung-uk Kim case 0x10: 187a4165bbaSJung-uk Kim case 0x11: 188a4165bbaSJung-uk Kim /* 189a4165bbaSJung-uk Kim * DiodeOffset must be non-zero if thermal diode is supported. 190a4165bbaSJung-uk Kim */ 191a4165bbaSJung-uk Kim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 192a4165bbaSJung-uk Kim temp = (temp >> 8) & 0x7f; 193a4165bbaSJung-uk Kim if (temp == 0) 194a4165bbaSJung-uk Kim return (ENXIO); 195a4165bbaSJung-uk Kim break; 196a4165bbaSJung-uk Kim default: 197fc1f75e5SRui Paulo return (ENXIO); 198fc1f75e5SRui Paulo } 199a4165bbaSJung-uk Kim device_set_desc(dev, "AMD CPU On-Die Thermal Sensors"); 200fc1f75e5SRui Paulo 201fc1f75e5SRui Paulo return (BUS_PROBE_GENERIC); 202fc1f75e5SRui Paulo } 203fc1f75e5SRui Paulo 204fc1f75e5SRui Paulo static int 205454e82d7SRui Paulo amdtemp_attach(device_t dev) 206fc1f75e5SRui Paulo { 207454e82d7SRui Paulo struct amdtemp_softc *sc = device_get_softc(dev); 208fc1f75e5SRui Paulo struct sysctl_ctx_list *sysctlctx; 209fc1f75e5SRui Paulo struct sysctl_oid *sysctlnode; 210a4165bbaSJung-uk Kim uint32_t cpuid, family, model; 211fc1f75e5SRui Paulo 212a4165bbaSJung-uk Kim cpuid = pci_read_config(dev, AMDTEMP_CPUID, 4); 213a4165bbaSJung-uk Kim family = CPUID_TO_FAMILY(cpuid); 214a4165bbaSJung-uk Kim model = CPUID_TO_MODEL(cpuid); 215a4165bbaSJung-uk Kim 216a4165bbaSJung-uk Kim switch (family) { 217a4165bbaSJung-uk Kim case 0x0f: 218a4165bbaSJung-uk Kim /* 219a4165bbaSJung-uk Kim * Thermaltrip Status Register - CurTmp 220a4165bbaSJung-uk Kim * 221a4165bbaSJung-uk Kim * Revision G: bits 23-14 222a4165bbaSJung-uk Kim * Earlier: bits 23-16 223a4165bbaSJung-uk Kim */ 224a4165bbaSJung-uk Kim if (model >= 0x60 && model != 0xc1) 225a4165bbaSJung-uk Kim sc->sc_mask = 0x3ff << 14; 226a4165bbaSJung-uk Kim else 227a4165bbaSJung-uk Kim sc->sc_mask = 0xff << 16; 228fc1f75e5SRui Paulo 229fc1f75e5SRui Paulo /* 230a4165bbaSJung-uk Kim * Thermaltrip Status Register - ThermSenseCoreSel 231a4165bbaSJung-uk Kim * 232a4165bbaSJung-uk Kim * Revision F: 0 - Core1, 1 - Core0 233a4165bbaSJung-uk Kim * Earlier: 0 - Core0, 1 - Core1 234fc1f75e5SRui Paulo */ 235a4165bbaSJung-uk Kim sc->sc_swap = (model >= 0x40); 236a4165bbaSJung-uk Kim 237a4165bbaSJung-uk Kim /* 238a4165bbaSJung-uk Kim * There are two sensors per core. 239a4165bbaSJung-uk Kim */ 240a4165bbaSJung-uk Kim sc->sc_ntemps = 2; 241a4165bbaSJung-uk Kim 242a4165bbaSJung-uk Kim sc->sc_gettemp = amdtemp_gettemp0f; 243a4165bbaSJung-uk Kim break; 244a4165bbaSJung-uk Kim case 0x10: 245a4165bbaSJung-uk Kim case 0x11: 246a4165bbaSJung-uk Kim /* 247a4165bbaSJung-uk Kim * Reported Temperature Control Register - Curtmp 248a4165bbaSJung-uk Kim */ 249a4165bbaSJung-uk Kim sc->sc_mask = 0x3ff << 21; 250a4165bbaSJung-uk Kim 251a4165bbaSJung-uk Kim /* 252a4165bbaSJung-uk Kim * There is only one sensor per package. 253a4165bbaSJung-uk Kim */ 254a4165bbaSJung-uk Kim sc->sc_ntemps = 1; 255a4165bbaSJung-uk Kim 256a4165bbaSJung-uk Kim sc->sc_gettemp = amdtemp_gettemp; 257a4165bbaSJung-uk Kim break; 258fc1f75e5SRui Paulo } 259fc1f75e5SRui Paulo 260a4165bbaSJung-uk Kim /* Find number of cores per package. */ 261a4165bbaSJung-uk Kim sc->sc_ncores = (amd_feature2 & AMDID2_CMP) != 0 ? 262a4165bbaSJung-uk Kim (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; 263a4165bbaSJung-uk Kim if (sc->sc_ncores > MAXCPU) 264a4165bbaSJung-uk Kim return (ENXIO); 265a4165bbaSJung-uk Kim 266a4165bbaSJung-uk Kim if (bootverbose) 267a4165bbaSJung-uk Kim device_printf(dev, "Found %d cores and %d sensors.\n", 268a4165bbaSJung-uk Kim sc->sc_ncores, 269a4165bbaSJung-uk Kim sc->sc_ntemps > 1 ? sc->sc_ntemps * sc->sc_ncores : 1); 270454e82d7SRui Paulo 271fc1f75e5SRui Paulo /* 272454e82d7SRui Paulo * dev.amdtemp.N tree. 273fc1f75e5SRui Paulo */ 274fc1f75e5SRui Paulo sysctlctx = device_get_sysctl_ctx(dev); 275fc1f75e5SRui Paulo sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 276a4165bbaSJung-uk Kim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 277a4165bbaSJung-uk Kim "sensor0", CTLFLAG_RD, 0, "Sensor 0"); 278fc1f75e5SRui Paulo 279fc1f75e5SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 280fc1f75e5SRui Paulo SYSCTL_CHILDREN(sysctlnode), 281fc1f75e5SRui Paulo OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 282454e82d7SRui Paulo dev, SENSOR0_CORE0, amdtemp_sysctl, "IK", 283fc1f75e5SRui Paulo "Sensor 0 / Core 0 temperature"); 284fc1f75e5SRui Paulo 285a4165bbaSJung-uk Kim if (sc->sc_ntemps > 1) { 286a4165bbaSJung-uk Kim if (sc->sc_ncores > 1) 287fc1f75e5SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 288fc1f75e5SRui Paulo SYSCTL_CHILDREN(sysctlnode), 289fc1f75e5SRui Paulo OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 290454e82d7SRui Paulo dev, SENSOR0_CORE1, amdtemp_sysctl, "IK", 291fc1f75e5SRui Paulo "Sensor 0 / Core 1 temperature"); 292fc1f75e5SRui Paulo 293fc1f75e5SRui Paulo sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 294a4165bbaSJung-uk Kim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, 295a4165bbaSJung-uk Kim "sensor1", CTLFLAG_RD, 0, "Sensor 1"); 296fc1f75e5SRui Paulo 297fc1f75e5SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 298fc1f75e5SRui Paulo SYSCTL_CHILDREN(sysctlnode), 299fc1f75e5SRui Paulo OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 300454e82d7SRui Paulo dev, SENSOR1_CORE0, amdtemp_sysctl, "IK", 301fc1f75e5SRui Paulo "Sensor 1 / Core 0 temperature"); 302fc1f75e5SRui Paulo 303a4165bbaSJung-uk Kim if (sc->sc_ncores > 1) 304fc1f75e5SRui Paulo SYSCTL_ADD_PROC(sysctlctx, 305fc1f75e5SRui Paulo SYSCTL_CHILDREN(sysctlnode), 306fc1f75e5SRui Paulo OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 307454e82d7SRui Paulo dev, SENSOR1_CORE1, amdtemp_sysctl, "IK", 308fc1f75e5SRui Paulo "Sensor 1 / Core 1 temperature"); 309a4165bbaSJung-uk Kim } 310a4165bbaSJung-uk Kim 311a4165bbaSJung-uk Kim /* 312a4165bbaSJung-uk Kim * Try to create dev.cpu sysctl entries and setup intrhook function. 313a4165bbaSJung-uk Kim * This is needed because the cpu driver may be loaded late on boot, 314a4165bbaSJung-uk Kim * after us. 315a4165bbaSJung-uk Kim */ 316a4165bbaSJung-uk Kim amdtemp_intrhook(dev); 317a4165bbaSJung-uk Kim sc->sc_ich.ich_func = amdtemp_intrhook; 318a4165bbaSJung-uk Kim sc->sc_ich.ich_arg = dev; 319a4165bbaSJung-uk Kim if (config_intrhook_establish(&sc->sc_ich) != 0) { 320a4165bbaSJung-uk Kim device_printf(dev, "config_intrhook_establish failed!\n"); 321a4165bbaSJung-uk Kim return (ENXIO); 322a4165bbaSJung-uk Kim } 323fc1f75e5SRui Paulo 324fc1f75e5SRui Paulo return (0); 325fc1f75e5SRui Paulo } 326fc1f75e5SRui Paulo 327fc1f75e5SRui Paulo void 328454e82d7SRui Paulo amdtemp_intrhook(void *arg) 329fc1f75e5SRui Paulo { 330454e82d7SRui Paulo struct amdtemp_softc *sc; 331fc1f75e5SRui Paulo struct sysctl_ctx_list *sysctlctx; 332a4165bbaSJung-uk Kim device_t dev = (device_t)arg; 333a4165bbaSJung-uk Kim device_t acpi, cpu, nexus; 334a4165bbaSJung-uk Kim amdsensor_t sensor; 335a4165bbaSJung-uk Kim int i; 336fc1f75e5SRui Paulo 337fc1f75e5SRui Paulo sc = device_get_softc(dev); 338fc1f75e5SRui Paulo 339fc1f75e5SRui Paulo /* 340fc1f75e5SRui Paulo * dev.cpu.N.temperature. 341fc1f75e5SRui Paulo */ 342fc1f75e5SRui Paulo nexus = device_find_child(root_bus, "nexus", 0); 343fc1f75e5SRui Paulo acpi = device_find_child(nexus, "acpi", 0); 344fc1f75e5SRui Paulo 345a4165bbaSJung-uk Kim for (i = 0; i < sc->sc_ncores; i++) { 346a4165bbaSJung-uk Kim if (sc->sc_sysctl_cpu[i] != NULL) 347a4165bbaSJung-uk Kim continue; 348fc1f75e5SRui Paulo cpu = device_find_child(acpi, "cpu", 349a4165bbaSJung-uk Kim device_get_unit(dev) * sc->sc_ncores + i); 350a4165bbaSJung-uk Kim if (cpu != NULL) { 351fc1f75e5SRui Paulo sysctlctx = device_get_sysctl_ctx(cpu); 352fc1f75e5SRui Paulo 353a4165bbaSJung-uk Kim sensor = sc->sc_ntemps > 1 ? 354a4165bbaSJung-uk Kim (i == 0 ? CORE0 : CORE1) : SENSOR0_CORE0; 355fc1f75e5SRui Paulo sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 356fc1f75e5SRui Paulo SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 357fc1f75e5SRui Paulo OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 358a4165bbaSJung-uk Kim dev, sensor, amdtemp_sysctl, "IK", 359a4165bbaSJung-uk Kim "Current temparature"); 360fc1f75e5SRui Paulo } 361fc1f75e5SRui Paulo } 362a4165bbaSJung-uk Kim if (sc->sc_ich.ich_arg != NULL) 363fc1f75e5SRui Paulo config_intrhook_disestablish(&sc->sc_ich); 364fc1f75e5SRui Paulo } 365fc1f75e5SRui Paulo 366fc1f75e5SRui Paulo int 367454e82d7SRui Paulo amdtemp_detach(device_t dev) 368fc1f75e5SRui Paulo { 369454e82d7SRui Paulo struct amdtemp_softc *sc = device_get_softc(dev); 370a4165bbaSJung-uk Kim int i; 371fc1f75e5SRui Paulo 372a4165bbaSJung-uk Kim for (i = 0; i < sc->sc_ncores; i++) 373a4165bbaSJung-uk Kim if (sc->sc_sysctl_cpu[i] != NULL) 374fc1f75e5SRui Paulo sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 375fc1f75e5SRui Paulo 376454e82d7SRui Paulo /* NewBus removes the dev.amdtemp.N tree by itself. */ 377fc1f75e5SRui Paulo 378fc1f75e5SRui Paulo return (0); 379fc1f75e5SRui Paulo } 380fc1f75e5SRui Paulo 381fc1f75e5SRui Paulo static int 382454e82d7SRui Paulo amdtemp_sysctl(SYSCTL_HANDLER_ARGS) 383fc1f75e5SRui Paulo { 384fc1f75e5SRui Paulo device_t dev = (device_t)arg1; 385454e82d7SRui Paulo struct amdtemp_softc *sc = device_get_softc(dev); 386a4165bbaSJung-uk Kim amdsensor_t sensor = (amdsensor_t)arg2; 387a4165bbaSJung-uk Kim int32_t auxtemp[2], temp; 388fc1f75e5SRui Paulo int error; 389fc1f75e5SRui Paulo 390a4165bbaSJung-uk Kim switch (sensor) { 391fc1f75e5SRui Paulo case CORE0: 392454e82d7SRui Paulo auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0); 393454e82d7SRui Paulo auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0); 394fc1f75e5SRui Paulo temp = imax(auxtemp[0], auxtemp[1]); 395fc1f75e5SRui Paulo break; 396fc1f75e5SRui Paulo case CORE1: 397454e82d7SRui Paulo auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1); 398454e82d7SRui Paulo auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1); 399fc1f75e5SRui Paulo temp = imax(auxtemp[0], auxtemp[1]); 400fc1f75e5SRui Paulo break; 401fc1f75e5SRui Paulo default: 402a4165bbaSJung-uk Kim temp = sc->sc_gettemp(dev, sensor); 403fc1f75e5SRui Paulo break; 404fc1f75e5SRui Paulo } 405fc1f75e5SRui Paulo error = sysctl_handle_int(oidp, &temp, 0, req); 406fc1f75e5SRui Paulo 407fc1f75e5SRui Paulo return (error); 408fc1f75e5SRui Paulo } 409fc1f75e5SRui Paulo 410a4165bbaSJung-uk Kim #define AMDTEMP_ZERO_C_TO_K 2732 411a4165bbaSJung-uk Kim 412fc1f75e5SRui Paulo static int32_t 413454e82d7SRui Paulo amdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 414fc1f75e5SRui Paulo { 415a4165bbaSJung-uk Kim struct amdtemp_softc *sc = device_get_softc(dev); 416fc1f75e5SRui Paulo uint32_t temp; 417a4165bbaSJung-uk Kim int32_t diode_offset, offset; 418a4165bbaSJung-uk Kim uint8_t cfg, sel; 419fc1f75e5SRui Paulo 420a4165bbaSJung-uk Kim /* Set Sensor/Core selector. */ 421a4165bbaSJung-uk Kim sel = 0; 422fc1f75e5SRui Paulo switch (sensor) { 423fc1f75e5SRui Paulo case SENSOR1_CORE0: 424a4165bbaSJung-uk Kim sel |= AMDTEMP_TTSR_SELSENSOR; 425a4165bbaSJung-uk Kim /* FALLTROUGH */ 426a4165bbaSJung-uk Kim case SENSOR0_CORE0: 427a4165bbaSJung-uk Kim case CORE0: 428a4165bbaSJung-uk Kim if (sc->sc_swap) 429a4165bbaSJung-uk Kim sel |= AMDTEMP_TTSR_SELCORE; 430fc1f75e5SRui Paulo break; 431fc1f75e5SRui Paulo case SENSOR1_CORE1: 432a4165bbaSJung-uk Kim sel |= AMDTEMP_TTSR_SELSENSOR; 433a4165bbaSJung-uk Kim /* FALLTROUGH */ 434a4165bbaSJung-uk Kim case SENSOR0_CORE1: 435a4165bbaSJung-uk Kim case CORE1: 436a4165bbaSJung-uk Kim if (!sc->sc_swap) 437a4165bbaSJung-uk Kim sel |= AMDTEMP_TTSR_SELCORE; 438fc1f75e5SRui Paulo break; 439fc1f75e5SRui Paulo } 440a4165bbaSJung-uk Kim cfg = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 1); 441a4165bbaSJung-uk Kim cfg &= ~(AMDTEMP_TTSR_SELSENSOR | AMDTEMP_TTSR_SELCORE); 442a4165bbaSJung-uk Kim pci_write_config(dev, AMDTEMP_THERMTP_STAT, cfg | sel, 1); 443a4165bbaSJung-uk Kim 444a4165bbaSJung-uk Kim /* CurTmp starts from -49C. */ 445a4165bbaSJung-uk Kim offset = AMDTEMP_ZERO_C_TO_K - 490; 446a4165bbaSJung-uk Kim 447a4165bbaSJung-uk Kim /* Adjust offset if DiodeOffset is set and valid. */ 448a4165bbaSJung-uk Kim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 449a4165bbaSJung-uk Kim diode_offset = (temp >> 8) & 0x3f; 450a4165bbaSJung-uk Kim if (diode_offset != 0) 451a4165bbaSJung-uk Kim offset += (diode_offset - 11) * 10; 452a4165bbaSJung-uk Kim 453a4165bbaSJung-uk Kim temp = ((temp & sc->sc_mask) >> 14) * 5 / 2 + offset; 454454e82d7SRui Paulo 455454e82d7SRui Paulo return (temp); 456454e82d7SRui Paulo } 457454e82d7SRui Paulo 458454e82d7SRui Paulo static int32_t 459454e82d7SRui Paulo amdtemp_gettemp(device_t dev, amdsensor_t sensor) 460454e82d7SRui Paulo { 461a4165bbaSJung-uk Kim struct amdtemp_softc *sc = device_get_softc(dev); 462454e82d7SRui Paulo uint32_t temp; 463a4165bbaSJung-uk Kim int32_t diode_offset, offset; 464454e82d7SRui Paulo 465a4165bbaSJung-uk Kim /* CurTmp starts from 0C. */ 466a4165bbaSJung-uk Kim offset = AMDTEMP_ZERO_C_TO_K; 467a4165bbaSJung-uk Kim 468a4165bbaSJung-uk Kim /* Adjust offset if DiodeOffset is set and valid. */ 469a4165bbaSJung-uk Kim temp = pci_read_config(dev, AMDTEMP_THERMTP_STAT, 4); 470a4165bbaSJung-uk Kim diode_offset = (temp >> 8) & 0x7f; 471a4165bbaSJung-uk Kim if (diode_offset > 0 && diode_offset < 0x40) 472a4165bbaSJung-uk Kim offset += (diode_offset - 11) * 10; 473a4165bbaSJung-uk Kim 474a4165bbaSJung-uk Kim temp = pci_read_config(dev, AMDTEMP_REPTMP_CTRL, 4); 475a4165bbaSJung-uk Kim temp = ((temp & sc->sc_mask) >> 21) * 5 / 4 + offset; 476fc1f75e5SRui Paulo 477fc1f75e5SRui Paulo return (temp); 478fc1f75e5SRui Paulo } 479