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/coretemp/coretemp.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2007, 2008 Rui Paulo <rpaulo@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * Device driver for Intel's On Die thermal sensor via MSR.
   31  * First introduced in Intel's Core line of processors.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/bus.h>
   39 #include <sys/systm.h>
   40 #include <sys/types.h>
   41 #include <sys/module.h>
   42 #include <sys/conf.h>
   43 #include <sys/kernel.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/proc.h>   /* for curthread */
   46 #include <sys/smp.h>
   47 
   48 #include <machine/specialreg.h>
   49 #include <machine/cpufunc.h>
   50 #include <machine/cputypes.h>
   51 #include <machine/md_var.h>
   52 
   53 #define TZ_ZEROC                        2731
   54 
   55 #define THERM_STATUS_LOG                0x02
   56 #define THERM_STATUS                    0x01
   57 #define THERM_STATUS_TEMP_SHIFT         16
   58 #define THERM_STATUS_TEMP_MASK          0x7f
   59 #define THERM_STATUS_RES_SHIFT          27
   60 #define THERM_STATUS_RES_MASK           0x0f
   61 #define THERM_STATUS_VALID_SHIFT        31
   62 #define THERM_STATUS_VALID_MASK         0x01
   63 
   64 struct coretemp_softc {
   65         device_t        sc_dev;
   66         int             sc_tjmax;
   67         unsigned int    sc_throttle_log;
   68 };
   69 
   70 /*
   71  * Device methods.
   72  */
   73 static void     coretemp_identify(driver_t *driver, device_t parent);
   74 static int      coretemp_probe(device_t dev);
   75 static int      coretemp_attach(device_t dev);
   76 static int      coretemp_detach(device_t dev);
   77 
   78 static uint64_t coretemp_get_thermal_msr(int cpu);
   79 static void     coretemp_clear_thermal_msr(int cpu);
   80 static int      coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS);
   81 static int      coretemp_throttle_log_sysctl(SYSCTL_HANDLER_ARGS);
   82 
   83 static device_method_t coretemp_methods[] = {
   84         /* Device interface */
   85         DEVMETHOD(device_identify,      coretemp_identify),
   86         DEVMETHOD(device_probe,         coretemp_probe),
   87         DEVMETHOD(device_attach,        coretemp_attach),
   88         DEVMETHOD(device_detach,        coretemp_detach),
   89 
   90         DEVMETHOD_END
   91 };
   92 
   93 static driver_t coretemp_driver = {
   94         "coretemp",
   95         coretemp_methods,
   96         sizeof(struct coretemp_softc),
   97 };
   98 
   99 enum therm_info {
  100         CORETEMP_TEMP,
  101         CORETEMP_DELTA,
  102         CORETEMP_RESOLUTION,
  103         CORETEMP_TJMAX,
  104 };
  105 
  106 static devclass_t coretemp_devclass;
  107 DRIVER_MODULE(coretemp, cpu, coretemp_driver, coretemp_devclass, NULL,
  108     NULL);
  109 
  110 static void
  111 coretemp_identify(driver_t *driver, device_t parent)
  112 {
  113         device_t child;
  114         u_int regs[4];
  115 
  116         /* Make sure we're not being doubly invoked. */
  117         if (device_find_child(parent, "coretemp", -1) != NULL)
  118                 return;
  119 
  120         /* Check that CPUID 0x06 is supported and the vendor is Intel.*/
  121         if (cpu_high < 6 || cpu_vendor_id != CPU_VENDOR_INTEL)
  122                 return;
  123         /*
  124          * CPUID 0x06 returns 1 if the processor has on-die thermal
  125          * sensors. EBX[0:3] contains the number of sensors.
  126          */
  127         do_cpuid(0x06, regs);
  128         if ((regs[0] & 0x1) != 1)
  129                 return;
  130 
  131         /*
  132          * We add a child for each CPU since settings must be performed
  133          * on each CPU in the SMP case.
  134          */
  135         child = device_add_child(parent, "coretemp", -1);
  136         if (child == NULL)
  137                 device_printf(parent, "add coretemp child failed\n");
  138 }
  139 
  140 static int
  141 coretemp_probe(device_t dev)
  142 {
  143         if (resource_disabled("coretemp", 0))
  144                 return (ENXIO);
  145 
  146         device_set_desc(dev, "CPU On-Die Thermal Sensors");
  147 
  148         if (!bootverbose && device_get_unit(dev) != 0)
  149                 device_quiet(dev);
  150 
  151         return (BUS_PROBE_GENERIC);
  152 }
  153 
  154 static int
  155 coretemp_attach(device_t dev)
  156 {
  157         struct coretemp_softc *sc = device_get_softc(dev);
  158         device_t pdev;
  159         uint64_t msr;
  160         int cpu_model, cpu_stepping;
  161         int ret, tjtarget;
  162         struct sysctl_oid *oid;
  163         struct sysctl_ctx_list *ctx;
  164 
  165         sc->sc_dev = dev;
  166         pdev = device_get_parent(dev);
  167         cpu_model = CPUID_TO_MODEL(cpu_id);
  168         cpu_stepping = CPUID_TO_STEPPING(cpu_id);
  169 
  170         /*
  171          * Some CPUs, namely the PIII, don't have thermal sensors, but
  172          * report them when the CPUID check is performed in
  173          * coretemp_identify(). This leads to a later GPF when the sensor
  174          * is queried via a MSR, so we stop here.
  175          */
  176         if (cpu_model < 0xe)
  177                 return (ENXIO);
  178 
  179 #if 0 /*
  180        * XXXrpaulo: I have this CPU model and when it returns from C3
  181        * coretemp continues to function properly.
  182        */
  183          
  184         /*
  185          * Check for errata AE18.
  186          * "Processor Digital Thermal Sensor (DTS) Readout stops
  187          *  updating upon returning from C3/C4 state."
  188          *
  189          * Adapted from the Linux coretemp driver.
  190          */
  191         if (cpu_model == 0xe && cpu_stepping < 0xc) {
  192                 msr = rdmsr(MSR_BIOS_SIGN);
  193                 msr = msr >> 32;
  194                 if (msr < 0x39) {
  195                         device_printf(dev, "not supported (Intel errata "
  196                             "AE18), try updating your BIOS\n");
  197                         return (ENXIO);
  198                 }
  199         }
  200 #endif
  201 
  202         /*
  203          * Use 100C as the initial value.
  204          */
  205         sc->sc_tjmax = 100;
  206 
  207         if ((cpu_model == 0xf && cpu_stepping >= 2) || cpu_model == 0xe) {
  208                 /*
  209                  * On some Core 2 CPUs, there's an undocumented MSR that
  210                  * can tell us if Tj(max) is 100 or 85.
  211                  *
  212                  * The if-clause for CPUs having the MSR_IA32_EXT_CONFIG was adapted
  213                  * from the Linux coretemp driver.
  214                  */
  215                 msr = rdmsr(MSR_IA32_EXT_CONFIG);
  216                 if (msr & (1 << 30))
  217                         sc->sc_tjmax = 85;
  218         } else if (cpu_model == 0x17) {
  219                 switch (cpu_stepping) {
  220                 case 0x6:       /* Mobile Core 2 Duo */
  221                         sc->sc_tjmax = 105;
  222                         break;
  223                 default:        /* Unknown stepping */
  224                         break;
  225                 }
  226         } else if (cpu_model == 0x1c) {
  227                 switch (cpu_stepping) {
  228                 case 0xa:       /* 45nm Atom D400, N400 and D500 series */
  229                         sc->sc_tjmax = 100;
  230                         break;
  231                 default:
  232                         sc->sc_tjmax = 90;
  233                         break;
  234                 }
  235         } else {
  236                 /*
  237                  * Attempt to get Tj(max) from MSR IA32_TEMPERATURE_TARGET.
  238                  *
  239                  * This method is described in Intel white paper "CPU
  240                  * Monitoring With DTS/PECI". (#322683)
  241                  */
  242                 ret = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &msr);
  243                 if (ret == 0) {
  244                         tjtarget = (msr >> 16) & 0xff;
  245 
  246                         /*
  247                          * On earlier generation of processors, the value
  248                          * obtained from IA32_TEMPERATURE_TARGET register is
  249                          * an offset that needs to be summed with a model
  250                          * specific base.  It is however not clear what
  251                          * these numbers are, with the publicly available
  252                          * documents from Intel.
  253                          *
  254                          * For now, we consider [70, 110]C range, as
  255                          * described in #322683, as "reasonable" and accept
  256                          * these values whenever the MSR is available for
  257                          * read, regardless the CPU model.
  258                          */
  259                         if (tjtarget >= 70 && tjtarget <= 110)
  260                                 sc->sc_tjmax = tjtarget;
  261                         else
  262                                 device_printf(dev, "Tj(target) value %d "
  263                                     "does not seem right.\n", tjtarget);
  264                 } else
  265                         device_printf(dev, "Can not get Tj(target) "
  266                             "from your CPU, using 100C.\n");
  267         }
  268 
  269         if (bootverbose)
  270                 device_printf(dev, "Setting TjMax=%d\n", sc->sc_tjmax);
  271 
  272         ctx = device_get_sysctl_ctx(dev);
  273 
  274         oid = SYSCTL_ADD_NODE(ctx,
  275             SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)), OID_AUTO,
  276             "coretemp", CTLFLAG_RD, NULL, "Per-CPU thermal information");
  277 
  278         /*
  279          * Add the MIBs to dev.cpu.N and dev.cpu.N.coretemp.
  280          */
  281         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(pdev)),
  282             OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
  283             dev, CORETEMP_TEMP, coretemp_get_val_sysctl, "IK",
  284             "Current temperature");
  285         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "delta",
  286             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_DELTA,
  287             coretemp_get_val_sysctl, "I",
  288             "Delta between TCC activation and current temperature");
  289         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "resolution",
  290             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_RESOLUTION,
  291             coretemp_get_val_sysctl, "I",
  292             "Resolution of CPU thermal sensor");
  293         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "tjmax",
  294             CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, CORETEMP_TJMAX,
  295             coretemp_get_val_sysctl, "IK",
  296             "TCC activation temperature");
  297         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  298             "throttle_log", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 0,
  299             coretemp_throttle_log_sysctl, "I",
  300             "Set to 1 if the thermal sensor has tripped");
  301 
  302         return (0);
  303 }
  304 
  305 static int
  306 coretemp_detach(device_t dev)
  307 {
  308         return (0);
  309 }
  310 
  311 struct coretemp_args {
  312         u_int           msr;
  313         uint64_t        val;
  314 };
  315 
  316 static void
  317 coretemp_rdmsr(void *arg)
  318 {
  319         struct coretemp_args *args = arg;
  320 
  321         args->val = rdmsr(args->msr);
  322 }
  323 
  324 static void
  325 coretemp_wrmsr(void *arg)
  326 {
  327         struct coretemp_args *args = arg;
  328 
  329         wrmsr(args->msr, args->val);
  330 }
  331 
  332 static uint64_t
  333 coretemp_get_thermal_msr(int cpu)
  334 {
  335         struct coretemp_args args;
  336         cpuset_t cpus;
  337 
  338         /*
  339          * The digital temperature reading is located at bit 16
  340          * of MSR_THERM_STATUS.
  341          *
  342          * There is a bit on that MSR that indicates whether the
  343          * temperature is valid or not.
  344          *
  345          * The temperature is computed by subtracting the temperature
  346          * reading by Tj(max).
  347          */
  348         args.msr = MSR_THERM_STATUS;
  349         CPU_SETOF(cpu, &cpus);
  350         smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, coretemp_rdmsr,
  351             smp_no_rendezvous_barrier, &args);
  352         return (args.val);
  353 }
  354 
  355 static void
  356 coretemp_clear_thermal_msr(int cpu)
  357 {
  358         struct coretemp_args args;
  359         cpuset_t cpus;
  360 
  361         args.msr = MSR_THERM_STATUS;
  362         args.val = 0;
  363         CPU_SETOF(cpu, &cpus);
  364         smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, coretemp_wrmsr,
  365             smp_no_rendezvous_barrier, &args);
  366 }
  367 
  368 static int
  369 coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS)
  370 {
  371         device_t dev;
  372         uint64_t msr;
  373         int val, tmp;
  374         struct coretemp_softc *sc;
  375         enum therm_info type;
  376         char stemp[16];
  377 
  378         dev = (device_t) arg1;
  379         msr = coretemp_get_thermal_msr(device_get_unit(dev));
  380         sc = device_get_softc(dev);
  381         type = arg2;
  382 
  383         if (((msr >> THERM_STATUS_VALID_SHIFT) & THERM_STATUS_VALID_MASK) != 1) {
  384                 val = -1;
  385         } else {
  386                 switch (type) {
  387                 case CORETEMP_TEMP:
  388                         tmp = (msr >> THERM_STATUS_TEMP_SHIFT) &
  389                             THERM_STATUS_TEMP_MASK;
  390                         val = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC;
  391                         break;
  392                 case CORETEMP_DELTA:
  393                         val = (msr >> THERM_STATUS_TEMP_SHIFT) &
  394                             THERM_STATUS_TEMP_MASK;
  395                         break;
  396                 case CORETEMP_RESOLUTION:
  397                         val = (msr >> THERM_STATUS_RES_SHIFT) &
  398                             THERM_STATUS_RES_MASK;
  399                         break;
  400                 case CORETEMP_TJMAX:
  401                         val = sc->sc_tjmax * 10 + TZ_ZEROC;
  402                         break;
  403                 }
  404         }
  405 
  406         if (msr & THERM_STATUS_LOG) {
  407                 coretemp_clear_thermal_msr(device_get_unit(dev));
  408                 sc->sc_throttle_log = 1;
  409 
  410                 /*
  411                  * Check for Critical Temperature Status and Critical
  412                  * Temperature Log.  It doesn't really matter if the
  413                  * current temperature is invalid because the "Critical
  414                  * Temperature Log" bit will tell us if the Critical
  415                  * Temperature has * been reached in past. It's not
  416                  * directly related to the current temperature.
  417                  *
  418                  * If we reach a critical level, allow devctl(4)
  419                  * to catch this and shutdown the system.
  420                  */
  421                 if (msr & THERM_STATUS) {
  422                         tmp = (msr >> THERM_STATUS_TEMP_SHIFT) &
  423                             THERM_STATUS_TEMP_MASK;
  424                         tmp = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC;
  425                         device_printf(dev, "critical temperature detected, "
  426                             "suggest system shutdown\n");
  427                         snprintf(stemp, sizeof(stemp), "%d", tmp);
  428                         devctl_notify("coretemp", "Thermal", stemp,
  429                             "notify=0xcc");
  430                 }
  431         }
  432 
  433         return (sysctl_handle_int(oidp, &val, 0, req));
  434 }
  435 
  436 static int
  437 coretemp_throttle_log_sysctl(SYSCTL_HANDLER_ARGS)
  438 {
  439         device_t dev;
  440         uint64_t msr;
  441         int error, val;
  442         struct coretemp_softc *sc;
  443 
  444         dev = (device_t) arg1;
  445         msr = coretemp_get_thermal_msr(device_get_unit(dev));
  446         sc = device_get_softc(dev);
  447 
  448         if (msr & THERM_STATUS_LOG) {
  449                 coretemp_clear_thermal_msr(device_get_unit(dev));
  450                 sc->sc_throttle_log = 1;
  451         }
  452 
  453         val = sc->sc_throttle_log;
  454 
  455         error = sysctl_handle_int(oidp, &val, 0, req);
  456 
  457         if (error || !req->newptr)
  458                 return (error);
  459         else if (val != 0)
  460                 return (EINVAL);
  461 
  462         coretemp_clear_thermal_msr(device_get_unit(dev));
  463         sc->sc_throttle_log = 0;
  464 
  465         return (0);
  466 }

Cache object: ffaac75bd64552d3c15f838f4be31f8b


[ 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.