amdtemp.c revision 196403
167754Smsmith/*- 267754Smsmith * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org> 367754Smsmith * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org> 467754Smsmith * All rights reserved. 567754Smsmith * 667754Smsmith * Redistribution and use in source and binary forms, with or without 7316303Sjkim * modification, are permitted provided that the following conditions 8316303Sjkim * are met: 9316303Sjkim * 1. Redistributions of source code must retain the above copyright 10316303Sjkim * notice, this list of conditions and the following disclaimer. 11316303Sjkim * 2. Redistributions in binary form must reproduce the above copyright 1270243Smsmith * notice, this list of conditions and the following disclaimer in the 1367754Smsmith * documentation and/or other materials provided with the distribution. 14316303Sjkim * 15316303Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16316303Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17316303Sjkim * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18316303Sjkim * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19316303Sjkim * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20316303Sjkim * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21316303Sjkim * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22316303Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23316303Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24316303Sjkim * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25316303Sjkim * POSSIBILITY OF SUCH DAMAGE. 26316303Sjkim */ 27316303Sjkim 28316303Sjkim/* 29316303Sjkim * Driver for the AMD K8/K10/K11 thermal sensors. Initially based on the 30316303Sjkim * k8temp Linux driver. 31316303Sjkim */ 32316303Sjkim 33316303Sjkim#include <sys/cdefs.h> 34316303Sjkim__FBSDID("$FreeBSD: head/sys/dev/amdtemp/amdtemp.c 196403 2009-08-20 19:17:53Z jhb $"); 35316303Sjkim 36316303Sjkim#include <sys/param.h> 37316303Sjkim#include <sys/bus.h> 38316303Sjkim#include <sys/systm.h> 39316303Sjkim#include <sys/types.h> 40316303Sjkim#include <sys/module.h> 41316303Sjkim#include <sys/conf.h> 42316303Sjkim#include <sys/kernel.h> 43316303Sjkim#include <sys/sysctl.h> 44316303Sjkim 45316303Sjkim#include <machine/specialreg.h> 46316303Sjkim#include <machine/cpufunc.h> 47316303Sjkim#include <machine/md_var.h> 48316303Sjkim 49316303Sjkim#include <dev/pci/pcireg.h> 50316303Sjkim#include <dev/pci/pcivar.h> 51316303Sjkim 52316303Sjkimtypedef enum { 53316303Sjkim SENSOR0_CORE0, 54316303Sjkim SENSOR0_CORE1, 55316303Sjkim SENSOR1_CORE0, 56316303Sjkim SENSOR1_CORE1, 57316303Sjkim CORE0, 58316303Sjkim CORE1 59316303Sjkim} amdsensor_t; 60316303Sjkim 61316303Sjkimstruct amdtemp_softc { 62316303Sjkim device_t sc_dev; 63316303Sjkim int sc_temps[4]; 64316303Sjkim int sc_ntemps; 65316303Sjkim struct sysctl_oid *sc_oid; 66316303Sjkim struct sysctl_oid *sc_sysctl_cpu[2]; 67316303Sjkim struct intr_config_hook sc_ich; 68316303Sjkim int32_t (*sc_gettemp)(device_t, amdsensor_t); 69316303Sjkim}; 70316303Sjkim 71316303Sjkim#define VENDORID_AMD 0x1022 72316303Sjkim#define DEVICEID_AMD_MISC0F 0x1103 73316303Sjkim#define DEVICEID_AMD_MISC10 0x1203 74316303Sjkim#define DEVICEID_AMD_MISC11 0x1303 75316303Sjkim 76316303Sjkimstatic struct amdtemp_product { 77316303Sjkim uint16_t amdtemp_vendorid; 78316303Sjkim uint16_t amdtemp_deviceid; 79316303Sjkim} amdtemp_products[] = { 80316303Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC0F }, 81316303Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC10 }, 82316303Sjkim { VENDORID_AMD, DEVICEID_AMD_MISC11 }, 83316303Sjkim { 0, 0 } 84316303Sjkim}; 85316303Sjkim 86316303Sjkim/* 87316303Sjkim * Register control (K8 family) 88316303Sjkim */ 89316303Sjkim#define AMDTEMP_REG0F 0xe4 90316303Sjkim#define AMDTEMP_REG_SELSENSOR 0x40 91316303Sjkim#define AMDTEMP_REG_SELCORE 0x04 92316303Sjkim 93316303Sjkim/* 94316303Sjkim * Register control (K10 & K11) family 95316303Sjkim */ 96316303Sjkim#define AMDTEMP_REG 0xa4 97316303Sjkim 98316303Sjkim#define TZ_ZEROC 2732 99316303Sjkim 100316303Sjkim /* -49 C is the mininum temperature */ 101316303Sjkim#define AMDTEMP_OFFSET0F (TZ_ZEROC-490) 102316303Sjkim#define AMDTEMP_OFFSET (TZ_ZEROC) 103316303Sjkim 104316303Sjkim/* 105316303Sjkim * Device methods. 106316303Sjkim */ 107316303Sjkimstatic void amdtemp_identify(driver_t *driver, device_t parent); 108316303Sjkimstatic int amdtemp_probe(device_t dev); 109316303Sjkimstatic int amdtemp_attach(device_t dev); 110316303Sjkimstatic void amdtemp_intrhook(void *arg); 111316303Sjkimstatic int amdtemp_detach(device_t dev); 112316303Sjkimstatic int amdtemp_match(device_t dev); 113316303Sjkimstatic int32_t amdtemp_gettemp0f(device_t dev, amdsensor_t sensor); 114316303Sjkimstatic int32_t amdtemp_gettemp(device_t dev, amdsensor_t sensor); 115316303Sjkimstatic int amdtemp_sysctl(SYSCTL_HANDLER_ARGS); 116316303Sjkim 117316303Sjkimstatic device_method_t amdtemp_methods[] = { 118316303Sjkim /* Device interface */ 119217365Sjkim DEVMETHOD(device_identify, amdtemp_identify), 120217365Sjkim DEVMETHOD(device_probe, amdtemp_probe), 121217365Sjkim DEVMETHOD(device_attach, amdtemp_attach), 122217365Sjkim DEVMETHOD(device_detach, amdtemp_detach), 123217365Sjkim 124217365Sjkim {0, 0} 125217365Sjkim}; 126217365Sjkim 127217365Sjkimstatic driver_t amdtemp_driver = { 128217365Sjkim "amdtemp", 129217365Sjkim amdtemp_methods, 130217365Sjkim sizeof(struct amdtemp_softc), 131217365Sjkim}; 132217365Sjkim 13367754Smsmithstatic devclass_t amdtemp_devclass; 134316303SjkimDRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL); 135316303Sjkim 136316303Sjkimstatic int 137316303Sjkimamdtemp_match(device_t dev) 138316303Sjkim{ 139316303Sjkim int i; 140316303Sjkim uint16_t vendor, devid; 141316303Sjkim 142316303Sjkim vendor = pci_get_vendor(dev); 143316303Sjkim devid = pci_get_device(dev); 144316303Sjkim 145316303Sjkim for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) { 146316303Sjkim if (vendor == amdtemp_products[i].amdtemp_vendorid && 147217365Sjkim devid == amdtemp_products[i].amdtemp_deviceid) 148217365Sjkim return (1); 14967754Smsmith } 150316303Sjkim 15167754Smsmith return (0); 15267754Smsmith} 15367754Smsmith 15467754Smsmithstatic void 15567754Smsmithamdtemp_identify(driver_t *driver, device_t parent) 156193267Sjkim{ 157193267Sjkim device_t child; 158193267Sjkim 15967754Smsmith /* Make sure we're not being doubly invoked. */ 16067754Smsmith if (device_find_child(parent, "amdtemp", -1) != NULL) 16182367Smsmith return; 16267754Smsmith 16377424Smsmith if (amdtemp_match(parent)) { 16477424Smsmith child = device_add_child(parent, "amdtemp", -1); 16577424Smsmith if (child == NULL) 16677424Smsmith device_printf(parent, "add amdtemp child failed\n"); 16777424Smsmith } 16877424Smsmith 16977424Smsmith} 17077424Smsmith 17177424Smsmithstatic int 172102550Siwasakiamdtemp_probe(device_t dev) 17378986Smsmith{ 174102550Siwasaki uint32_t regs[4]; 17567754Smsmith 17691116Smsmith if (resource_disabled("amdtemp", 0)) 17767754Smsmith return (ENXIO); 17891116Smsmith 17991116Smsmith do_cpuid(1, regs); 180193267Sjkim switch (regs[0]) { 181193267Sjkim case 0xf40: 182209746Sjkim case 0xf50: 183233250Sjkim case 0xf51: 18467754Smsmith return (ENXIO); 185209746Sjkim } 186102550Siwasaki device_set_desc(dev, "AMD K8 Thermal Sensors"); 187102550Siwasaki 18891116Smsmith return (BUS_PROBE_GENERIC); 18977424Smsmith} 19091116Smsmith 19191116Smsmithstatic int 192114237Snjlamdtemp_attach(device_t dev) 19382367Smsmith{ 194193267Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 19582367Smsmith struct sysctl_ctx_list *sysctlctx; 196193267Sjkim struct sysctl_oid *sysctlnode; 197193267Sjkim 198193267Sjkim 199200553Sjkim /* 200285797Sjkim * Setup intrhook function to create dev.cpu sysctl entries. This is 201285797Sjkim * needed because the cpu driver may be loaded late on boot, after 20282367Smsmith * us. 20383174Smsmith */ 20482367Smsmith sc->sc_ich.ich_func = amdtemp_intrhook; 205114237Snjl sc->sc_ich.ich_arg = dev; 20683174Smsmith if (config_intrhook_establish(&sc->sc_ich) != 0) { 20783174Smsmith device_printf(dev, "config_intrhook_establish " 20883174Smsmith "failed!\n"); 20983174Smsmith return (ENXIO); 21083174Smsmith } 21183174Smsmith 21283174Smsmith if (pci_get_device(dev) == DEVICEID_AMD_MISC0F) 21383174Smsmith sc->sc_gettemp = amdtemp_gettemp0f; 21483174Smsmith else { 21583174Smsmith sc->sc_gettemp = amdtemp_gettemp; 21683174Smsmith return (0); 21783174Smsmith } 21883174Smsmith 219114237Snjl /* 22083174Smsmith * dev.amdtemp.N tree. 22183174Smsmith */ 22283174Smsmith sysctlctx = device_get_sysctl_ctx(dev); 22382367Smsmith sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 22483174Smsmith SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor0", 225102550Siwasaki CTLFLAG_RD, 0, "Sensor 0"); 226102550Siwasaki 22783174Smsmith SYSCTL_ADD_PROC(sysctlctx, 22882367Smsmith SYSCTL_CHILDREN(sysctlnode), 22983174Smsmith OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 23082367Smsmith dev, SENSOR0_CORE0, amdtemp_sysctl, "IK", 23183174Smsmith "Sensor 0 / Core 0 temperature"); 23283174Smsmith 23383174Smsmith SYSCTL_ADD_PROC(sysctlctx, 23483174Smsmith SYSCTL_CHILDREN(sysctlnode), 23583174Smsmith OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 23683174Smsmith dev, SENSOR0_CORE1, amdtemp_sysctl, "IK", 23799679Siwasaki "Sensor 0 / Core 1 temperature"); 23899679Siwasaki 23999679Siwasaki sysctlnode = SYSCTL_ADD_NODE(sysctlctx, 24099679Siwasaki SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor1", 24199679Siwasaki CTLFLAG_RD, 0, "Sensor 1"); 24299679Siwasaki 24399679Siwasaki SYSCTL_ADD_PROC(sysctlctx, 24499679Siwasaki SYSCTL_CHILDREN(sysctlnode), 24599679Siwasaki OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD, 24682367Smsmith dev, SENSOR1_CORE0, amdtemp_sysctl, "IK", 24782367Smsmith "Sensor 1 / Core 0 temperature"); 24882367Smsmith 249151937Sjkim SYSCTL_ADD_PROC(sysctlctx, 25082367Smsmith SYSCTL_CHILDREN(sysctlnode), 251193267Sjkim OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD, 252193267Sjkim dev, SENSOR1_CORE1, amdtemp_sysctl, "IK", 253193267Sjkim "Sensor 1 / Core 1 temperature"); 254193267Sjkim 255193267Sjkim return (0); 256193267Sjkim} 257114237Snjl 25882367Smsmithvoid 259114237Snjlamdtemp_intrhook(void *arg) 260200553Sjkim{ 261285797Sjkim int i; 26282367Smsmith device_t nexus, acpi, cpu; 26367754Smsmith device_t dev = (device_t) arg; 26467754Smsmith struct amdtemp_softc *sc; 26567754Smsmith struct sysctl_ctx_list *sysctlctx; 266114237Snjl 26782367Smsmith sc = device_get_softc(dev); 26882367Smsmith 26982367Smsmith /* 27082367Smsmith * dev.cpu.N.temperature. 27182367Smsmith */ 27282367Smsmith nexus = device_find_child(root_bus, "nexus", 0); 27382367Smsmith acpi = device_find_child(nexus, "acpi", 0); 27482367Smsmith 27582367Smsmith for (i = 0; i < 2; i++) { 27682367Smsmith cpu = device_find_child(acpi, "cpu", 277102550Siwasaki device_get_unit(dev) * 2 + i); 27882367Smsmith if (cpu) { 27982367Smsmith sysctlctx = device_get_sysctl_ctx(cpu); 28082367Smsmith 28182367Smsmith sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx, 28282367Smsmith SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), 28382367Smsmith OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, 28482367Smsmith dev, CORE0, amdtemp_sysctl, "IK", 28582367Smsmith "Max of sensor 0 / 1"); 28682367Smsmith } 287193267Sjkim } 28867754Smsmith config_intrhook_disestablish(&sc->sc_ich); 28999679Siwasaki} 29067754Smsmith 29167754Smsmithint 29267754Smsmithamdtemp_detach(device_t dev) 293200553Sjkim{ 294200553Sjkim int i; 295114237Snjl struct amdtemp_softc *sc = device_get_softc(dev); 29667754Smsmith 29767754Smsmith for (i = 0; i < 2; i++) { 298285797Sjkim if (sc->sc_sysctl_cpu[i]) 299285797Sjkim sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0); 300285797Sjkim } 301285797Sjkim 302285797Sjkim /* NewBus removes the dev.amdtemp.N tree by itself. */ 303285797Sjkim 304285797Sjkim return (0); 305285797Sjkim} 306285797Sjkim 307285797Sjkimstatic int 308285797Sjkimamdtemp_sysctl(SYSCTL_HANDLER_ARGS) 309285797Sjkim{ 310285797Sjkim device_t dev = (device_t) arg1; 311285797Sjkim struct amdtemp_softc *sc = device_get_softc(dev); 312285797Sjkim int error; 313193267Sjkim int32_t temp, auxtemp[2]; 314193267Sjkim 315218590Sjkim switch (arg2) { 316218590Sjkim case CORE0: 317218590Sjkim auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0); 318218590Sjkim auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0); 319193267Sjkim temp = imax(auxtemp[0], auxtemp[1]); 320193267Sjkim break; 321193267Sjkim case CORE1: 322218590Sjkim auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1); 323218590Sjkim auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1); 324218590Sjkim temp = imax(auxtemp[0], auxtemp[1]); 325218590Sjkim break; 326193267Sjkim default: 327218590Sjkim temp = sc->sc_gettemp(dev, arg2); 328193267Sjkim break; 329193267Sjkim } 330193267Sjkim error = sysctl_handle_int(oidp, &temp, 0, req); 331193267Sjkim 332193267Sjkim return (error); 333193267Sjkim} 334193267Sjkim 335193267Sjkimstatic int32_t 336193267Sjkimamdtemp_gettemp0f(device_t dev, amdsensor_t sensor) 337193267Sjkim{ 338193267Sjkim uint8_t cfg; 339193267Sjkim uint32_t temp; 340193267Sjkim 341193267Sjkim cfg = pci_read_config(dev, AMDTEMP_REG0F, 1); 342193267Sjkim switch (sensor) { 343193267Sjkim case SENSOR0_CORE0: 344193267Sjkim cfg &= ~(AMDTEMP_REG_SELSENSOR | AMDTEMP_REG_SELCORE); 345238381Sjkim break; 346238381Sjkim case SENSOR0_CORE1: 347204773Sjkim cfg &= ~AMDTEMP_REG_SELSENSOR; 348193267Sjkim cfg |= AMDTEMP_REG_SELCORE; 349193267Sjkim break; 350193267Sjkim case SENSOR1_CORE0: 351193267Sjkim cfg &= ~AMDTEMP_REG_SELCORE; 352193267Sjkim cfg |= AMDTEMP_REG_SELSENSOR; 353193267Sjkim break; 354193267Sjkim case SENSOR1_CORE1: 355193267Sjkim cfg |= (AMDTEMP_REG_SELSENSOR | AMDTEMP_REG_SELCORE); 356193267Sjkim break; 357238381Sjkim default: 358238381Sjkim cfg = 0; 359204773Sjkim break; 360193267Sjkim } 361193267Sjkim pci_write_config(dev, AMDTEMP_REG0F, cfg, 1); 362193267Sjkim temp = pci_read_config(dev, AMDTEMP_REG0F, 4); 363193267Sjkim temp = ((temp >> 16) & 0xff) * 10 + AMDTEMP_OFFSET0F; 364193267Sjkim 365193267Sjkim return (temp); 366193267Sjkim} 367193267Sjkim 368193267Sjkimstatic int32_t 369193267Sjkimamdtemp_gettemp(device_t dev, amdsensor_t sensor) 370193267Sjkim{ 371193267Sjkim uint32_t temp; 372193267Sjkim 373193267Sjkim temp = pci_read_config(dev, AMDTEMP_REG, 4); 374193267Sjkim temp = ((temp >> 21) & 0x3ff) * 10 / 8 + AMDTEMP_OFFSET; 375193267Sjkim 376193267Sjkim return (temp); 377193267Sjkim} 378298714Sjkim