The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/amdtemp/amdtemp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2008, 2009 Rui Paulo <rpaulo@FreeBSD.org>
    3  * Copyright (c) 2009 Norikatsu Shigemura <nork@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   25  * POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * Driver for the AMD K8/K10/K11 thermal sensors. Initially based on the
   30  * k8temp Linux driver.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/8.4/sys/dev/amdtemp/amdtemp.c 196405 2009-08-20 20:23:28Z jhb $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/bus.h>
   38 #include <sys/systm.h>
   39 #include <sys/types.h>
   40 #include <sys/module.h>
   41 #include <sys/conf.h>
   42 #include <sys/kernel.h>
   43 #include <sys/sysctl.h>
   44 
   45 #include <machine/specialreg.h>
   46 #include <machine/cpufunc.h>
   47 #include <machine/md_var.h>
   48 
   49 #include <dev/pci/pcireg.h>
   50 #include <dev/pci/pcivar.h>
   51 
   52 typedef enum {
   53         SENSOR0_CORE0,
   54         SENSOR0_CORE1,
   55         SENSOR1_CORE0,
   56         SENSOR1_CORE1,
   57         CORE0,
   58         CORE1
   59 } amdsensor_t;
   60 
   61 struct amdtemp_softc {
   62         device_t        sc_dev;
   63         int             sc_temps[4];
   64         int             sc_ntemps;
   65         struct sysctl_oid *sc_oid;
   66         struct sysctl_oid *sc_sysctl_cpu[2];
   67         struct intr_config_hook sc_ich;
   68         int32_t (*sc_gettemp)(device_t, amdsensor_t);
   69 };
   70 
   71 #define VENDORID_AMD            0x1022
   72 #define DEVICEID_AMD_MISC0F     0x1103
   73 #define DEVICEID_AMD_MISC10     0x1203
   74 #define DEVICEID_AMD_MISC11     0x1303
   75 
   76 static struct amdtemp_product {
   77         uint16_t        amdtemp_vendorid;
   78         uint16_t        amdtemp_deviceid;
   79 } amdtemp_products[] = {
   80         { VENDORID_AMD, DEVICEID_AMD_MISC0F },
   81         { VENDORID_AMD, DEVICEID_AMD_MISC10 },
   82         { VENDORID_AMD, DEVICEID_AMD_MISC11 },
   83         { 0, 0 }
   84 };
   85 
   86 /*
   87  * Register control (K8 family)
   88  */
   89 #define AMDTEMP_REG0F           0xe4
   90 #define AMDTEMP_REG_SELSENSOR   0x40
   91 #define AMDTEMP_REG_SELCORE     0x04
   92 
   93 /*
   94  * Register control (K10 & K11) family
   95  */
   96 #define AMDTEMP_REG             0xa4
   97 
   98 #define TZ_ZEROC                2732
   99 
  100                                         /* -49 C is the mininum temperature */
  101 #define AMDTEMP_OFFSET0F        (TZ_ZEROC-490)
  102 #define AMDTEMP_OFFSET          (TZ_ZEROC)
  103 
  104 /*
  105  * Device methods.
  106  */
  107 static void     amdtemp_identify(driver_t *driver, device_t parent);
  108 static int      amdtemp_probe(device_t dev);
  109 static int      amdtemp_attach(device_t dev);
  110 static void     amdtemp_intrhook(void *arg);
  111 static int      amdtemp_detach(device_t dev);
  112 static int      amdtemp_match(device_t dev);
  113 static int32_t  amdtemp_gettemp0f(device_t dev, amdsensor_t sensor);
  114 static int32_t  amdtemp_gettemp(device_t dev, amdsensor_t sensor);
  115 static int      amdtemp_sysctl(SYSCTL_HANDLER_ARGS);
  116 
  117 static device_method_t amdtemp_methods[] = {
  118         /* Device interface */
  119         DEVMETHOD(device_identify,      amdtemp_identify),
  120         DEVMETHOD(device_probe,         amdtemp_probe),
  121         DEVMETHOD(device_attach,        amdtemp_attach),
  122         DEVMETHOD(device_detach,        amdtemp_detach),
  123 
  124         {0, 0}
  125 };
  126 
  127 static driver_t amdtemp_driver = {
  128         "amdtemp",
  129         amdtemp_methods,
  130         sizeof(struct amdtemp_softc),
  131 };
  132 
  133 static devclass_t amdtemp_devclass;
  134 DRIVER_MODULE(amdtemp, hostb, amdtemp_driver, amdtemp_devclass, NULL, NULL);
  135 
  136 static int
  137 amdtemp_match(device_t dev)
  138 {
  139         int i;
  140         uint16_t vendor, devid;
  141         
  142         vendor = pci_get_vendor(dev);
  143         devid = pci_get_device(dev);
  144 
  145         for (i = 0; amdtemp_products[i].amdtemp_vendorid != 0; i++) {
  146                 if (vendor == amdtemp_products[i].amdtemp_vendorid &&
  147                     devid == amdtemp_products[i].amdtemp_deviceid)
  148                         return (1);
  149         }
  150 
  151         return (0);
  152 }
  153 
  154 static void
  155 amdtemp_identify(driver_t *driver, device_t parent)
  156 {
  157         device_t child;
  158 
  159         /* Make sure we're not being doubly invoked. */
  160         if (device_find_child(parent, "amdtemp", -1) != NULL)
  161                 return;
  162         
  163         if (amdtemp_match(parent)) {
  164                 child = device_add_child(parent, "amdtemp", -1);
  165                 if (child == NULL)
  166                         device_printf(parent, "add amdtemp child failed\n");
  167         }
  168     
  169 }
  170 
  171 static int
  172 amdtemp_probe(device_t dev)
  173 {
  174         uint32_t regs[4];
  175         
  176         if (resource_disabled("amdtemp", 0))
  177                 return (ENXIO);
  178 
  179         do_cpuid(1, regs);
  180         switch (regs[0]) {
  181         case 0xf40:
  182         case 0xf50:
  183         case 0xf51:
  184                 return (ENXIO);
  185         }
  186         device_set_desc(dev, "AMD K8 Thermal Sensors");
  187         
  188         return (BUS_PROBE_GENERIC);
  189 }
  190 
  191 static int
  192 amdtemp_attach(device_t dev)
  193 {
  194         struct amdtemp_softc *sc = device_get_softc(dev);
  195         struct sysctl_ctx_list *sysctlctx;
  196         struct sysctl_oid *sysctlnode;
  197 
  198 
  199         /*
  200          * Setup intrhook function to create dev.cpu sysctl entries. This is
  201          * needed because the cpu driver may be loaded late on boot, after
  202          * us.
  203          */
  204         sc->sc_ich.ich_func = amdtemp_intrhook;
  205         sc->sc_ich.ich_arg = dev;
  206         if (config_intrhook_establish(&sc->sc_ich) != 0) {
  207                 device_printf(dev, "config_intrhook_establish "
  208                     "failed!\n");
  209                 return (ENXIO);
  210         }
  211         
  212         if (pci_get_device(dev) == DEVICEID_AMD_MISC0F)
  213                 sc->sc_gettemp = amdtemp_gettemp0f;
  214         else {
  215                 sc->sc_gettemp = amdtemp_gettemp;
  216                 return (0);
  217         }
  218 
  219         /*
  220          * dev.amdtemp.N tree.
  221          */
  222         sysctlctx = device_get_sysctl_ctx(dev);
  223         sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
  224             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor0",
  225             CTLFLAG_RD, 0, "Sensor 0");
  226         
  227         SYSCTL_ADD_PROC(sysctlctx,
  228             SYSCTL_CHILDREN(sysctlnode),
  229             OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD,
  230             dev, SENSOR0_CORE0, amdtemp_sysctl, "IK",
  231             "Sensor 0 / Core 0 temperature");
  232         
  233         SYSCTL_ADD_PROC(sysctlctx,
  234             SYSCTL_CHILDREN(sysctlnode),
  235             OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD,
  236             dev, SENSOR0_CORE1, amdtemp_sysctl, "IK",
  237             "Sensor 0 / Core 1 temperature");
  238         
  239         sysctlnode = SYSCTL_ADD_NODE(sysctlctx,
  240             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor1",
  241             CTLFLAG_RD, 0, "Sensor 1");
  242         
  243         SYSCTL_ADD_PROC(sysctlctx,
  244             SYSCTL_CHILDREN(sysctlnode),
  245             OID_AUTO, "core0", CTLTYPE_INT | CTLFLAG_RD,
  246             dev, SENSOR1_CORE0, amdtemp_sysctl, "IK",
  247             "Sensor 1 / Core 0 temperature");
  248         
  249         SYSCTL_ADD_PROC(sysctlctx,
  250             SYSCTL_CHILDREN(sysctlnode),
  251             OID_AUTO, "core1", CTLTYPE_INT | CTLFLAG_RD,
  252             dev, SENSOR1_CORE1, amdtemp_sysctl, "IK",
  253             "Sensor 1 / Core 1 temperature");
  254 
  255         return (0);
  256 }
  257 
  258 void
  259 amdtemp_intrhook(void *arg)
  260 {
  261         int i;
  262         device_t nexus, acpi, cpu;
  263         device_t dev = (device_t) arg;
  264         struct amdtemp_softc *sc;
  265         struct sysctl_ctx_list *sysctlctx;
  266 
  267         sc = device_get_softc(dev);
  268         
  269         /*
  270          * dev.cpu.N.temperature.
  271          */
  272         nexus = device_find_child(root_bus, "nexus", 0);
  273         acpi = device_find_child(nexus, "acpi", 0);
  274 
  275         for (i = 0; i < 2; i++) {
  276                 cpu = device_find_child(acpi, "cpu",
  277                     device_get_unit(dev) * 2 + i);
  278                 if (cpu) {
  279                         sysctlctx = device_get_sysctl_ctx(cpu);
  280 
  281                         sc->sc_sysctl_cpu[i] = SYSCTL_ADD_PROC(sysctlctx,
  282                             SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)),
  283                             OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD,
  284                             dev, CORE0, amdtemp_sysctl, "IK",
  285                             "Max of sensor 0 / 1");
  286                 }
  287         }
  288         config_intrhook_disestablish(&sc->sc_ich);
  289 }
  290 
  291 int
  292 amdtemp_detach(device_t dev)
  293 {
  294         int i;
  295         struct amdtemp_softc *sc = device_get_softc(dev);
  296         
  297         for (i = 0; i < 2; i++) {
  298                 if (sc->sc_sysctl_cpu[i])
  299                         sysctl_remove_oid(sc->sc_sysctl_cpu[i], 1, 0);
  300         }
  301 
  302         /* NewBus removes the dev.amdtemp.N tree by itself. */
  303         
  304         return (0);
  305 }
  306 
  307 static int
  308 amdtemp_sysctl(SYSCTL_HANDLER_ARGS)
  309 {
  310         device_t dev = (device_t) arg1;
  311         struct amdtemp_softc *sc = device_get_softc(dev);
  312         int error;
  313         int32_t temp, auxtemp[2];
  314 
  315         switch (arg2) {
  316         case CORE0:
  317                 auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE0);
  318                 auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE0);
  319                 temp = imax(auxtemp[0], auxtemp[1]);
  320                 break;
  321         case CORE1:
  322                 auxtemp[0] = sc->sc_gettemp(dev, SENSOR0_CORE1);
  323                 auxtemp[1] = sc->sc_gettemp(dev, SENSOR1_CORE1);
  324                 temp = imax(auxtemp[0], auxtemp[1]);
  325                 break;
  326         default:
  327                 temp = sc->sc_gettemp(dev, arg2);
  328                 break;
  329         }
  330         error = sysctl_handle_int(oidp, &temp, 0, req);
  331         
  332         return (error);
  333 }
  334 
  335 static int32_t
  336 amdtemp_gettemp0f(device_t dev, amdsensor_t sensor)
  337 {
  338         uint8_t cfg;
  339         uint32_t temp;
  340         
  341         cfg = pci_read_config(dev, AMDTEMP_REG0F, 1);
  342         switch (sensor) {
  343         case SENSOR0_CORE0:
  344                 cfg &= ~(AMDTEMP_REG_SELSENSOR | AMDTEMP_REG_SELCORE);
  345                 break;
  346         case SENSOR0_CORE1:
  347                 cfg &= ~AMDTEMP_REG_SELSENSOR;
  348                 cfg |= AMDTEMP_REG_SELCORE;
  349                 break;
  350         case SENSOR1_CORE0:
  351                 cfg &= ~AMDTEMP_REG_SELCORE;
  352                 cfg |= AMDTEMP_REG_SELSENSOR;
  353                 break;
  354         case SENSOR1_CORE1:
  355                 cfg |= (AMDTEMP_REG_SELSENSOR | AMDTEMP_REG_SELCORE);
  356                 break;
  357         default:
  358                 cfg = 0;
  359                 break;
  360         }
  361         pci_write_config(dev, AMDTEMP_REG0F, cfg, 1);
  362         temp = pci_read_config(dev, AMDTEMP_REG0F, 4);
  363         temp = ((temp >> 16) & 0xff) * 10 + AMDTEMP_OFFSET0F;
  364         
  365         return (temp);
  366 }
  367 
  368 static int32_t
  369 amdtemp_gettemp(device_t dev, amdsensor_t sensor)
  370 {
  371         uint32_t temp;
  372 
  373         temp = pci_read_config(dev, AMDTEMP_REG, 4);
  374         temp = ((temp >> 21) & 0x3ff) * 10 / 8 + AMDTEMP_OFFSET;
  375 
  376         return (temp);
  377 }

Cache object: 2cb6cf74f791d93cf2d208894b3dda2d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.