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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: stable/12/sys/dev/coretemp/coretemp.c 335186 2018-06-15 02:28:36Z mmacy $");
   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/sched.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 = cpu_id & CPUID_STEPPING;
  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 static uint64_t
  312 coretemp_get_thermal_msr(int cpu)
  313 {
  314         uint64_t msr;
  315 
  316         thread_lock(curthread);
  317         sched_bind(curthread, cpu);
  318         thread_unlock(curthread);
  319 
  320         /*
  321          * The digital temperature reading is located at bit 16
  322          * of MSR_THERM_STATUS.
  323          *
  324          * There is a bit on that MSR that indicates whether the
  325          * temperature is valid or not.
  326          *
  327          * The temperature is computed by subtracting the temperature
  328          * reading by Tj(max).
  329          */
  330         msr = rdmsr(MSR_THERM_STATUS);
  331 
  332         thread_lock(curthread);
  333         sched_unbind(curthread);
  334         thread_unlock(curthread);
  335 
  336         return (msr);
  337 }
  338 
  339 static void
  340 coretemp_clear_thermal_msr(int cpu)
  341 {
  342         thread_lock(curthread);
  343         sched_bind(curthread, cpu);
  344         thread_unlock(curthread);
  345 
  346         wrmsr(MSR_THERM_STATUS, 0);
  347 
  348         thread_lock(curthread);
  349         sched_unbind(curthread);
  350         thread_unlock(curthread);
  351 }
  352 
  353 static int
  354 coretemp_get_val_sysctl(SYSCTL_HANDLER_ARGS)
  355 {
  356         device_t dev;
  357         uint64_t msr;
  358         int val, tmp;
  359         struct coretemp_softc *sc;
  360         enum therm_info type;
  361         char stemp[16];
  362 
  363         dev = (device_t) arg1;
  364         msr = coretemp_get_thermal_msr(device_get_unit(dev));
  365         sc = device_get_softc(dev);
  366         type = arg2;
  367 
  368         if (((msr >> THERM_STATUS_VALID_SHIFT) & THERM_STATUS_VALID_MASK) != 1) {
  369                 val = -1;
  370         } else {
  371                 switch (type) {
  372                 case CORETEMP_TEMP:
  373                         tmp = (msr >> THERM_STATUS_TEMP_SHIFT) &
  374                             THERM_STATUS_TEMP_MASK;
  375                         val = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC;
  376                         break;
  377                 case CORETEMP_DELTA:
  378                         val = (msr >> THERM_STATUS_TEMP_SHIFT) &
  379                             THERM_STATUS_TEMP_MASK;
  380                         break;
  381                 case CORETEMP_RESOLUTION:
  382                         val = (msr >> THERM_STATUS_RES_SHIFT) &
  383                             THERM_STATUS_RES_MASK;
  384                         break;
  385                 case CORETEMP_TJMAX:
  386                         val = sc->sc_tjmax * 10 + TZ_ZEROC;
  387                         break;
  388                 }
  389         }
  390 
  391         if (msr & THERM_STATUS_LOG) {
  392                 coretemp_clear_thermal_msr(device_get_unit(dev));
  393                 sc->sc_throttle_log = 1;
  394 
  395                 /*
  396                  * Check for Critical Temperature Status and Critical
  397                  * Temperature Log.  It doesn't really matter if the
  398                  * current temperature is invalid because the "Critical
  399                  * Temperature Log" bit will tell us if the Critical
  400                  * Temperature has * been reached in past. It's not
  401                  * directly related to the current temperature.
  402                  *
  403                  * If we reach a critical level, allow devctl(4)
  404                  * to catch this and shutdown the system.
  405                  */
  406                 if (msr & THERM_STATUS) {
  407                         tmp = (msr >> THERM_STATUS_TEMP_SHIFT) &
  408                             THERM_STATUS_TEMP_MASK;
  409                         tmp = (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC;
  410                         device_printf(dev, "critical temperature detected, "
  411                             "suggest system shutdown\n");
  412                         snprintf(stemp, sizeof(stemp), "%d", tmp);
  413                         devctl_notify("coretemp", "Thermal", stemp,
  414                             "notify=0xcc");
  415                 }
  416         }
  417 
  418         return (sysctl_handle_int(oidp, &val, 0, req));
  419 }
  420 
  421 static int
  422 coretemp_throttle_log_sysctl(SYSCTL_HANDLER_ARGS)
  423 {
  424         device_t dev;
  425         uint64_t msr;
  426         int error, val;
  427         struct coretemp_softc *sc;
  428 
  429         dev = (device_t) arg1;
  430         msr = coretemp_get_thermal_msr(device_get_unit(dev));
  431         sc = device_get_softc(dev);
  432 
  433         if (msr & THERM_STATUS_LOG) {
  434                 coretemp_clear_thermal_msr(device_get_unit(dev));
  435                 sc->sc_throttle_log = 1;
  436         }
  437 
  438         val = sc->sc_throttle_log;
  439 
  440         error = sysctl_handle_int(oidp, &val, 0, req);
  441 
  442         if (error || !req->newptr)
  443                 return (error);
  444         else if (val != 0)
  445                 return (EINVAL);
  446 
  447         coretemp_clear_thermal_msr(device_get_unit(dev));
  448         sc->sc_throttle_log = 0;
  449 
  450         return (0);
  451 }

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.