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/i386/i386/p4tcc.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 /*      $OpenBSD: p4tcc.c,v 1.1 2003/12/20 18:23:18 tedu Exp $ */
    2 /*
    3  * Copyright (c) 2003 Ted Unangst
    4  * Copyright (c) 2004 Maxim Sobolev <sobomax@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 WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*
   29  * Restrict power consumption by using thermal control circuit.
   30  * This operates independently of speedstep.
   31  * Found on Pentium 4 and later models (feature TM).
   32  *
   33  * References:
   34  * Intel Developer's manual v.3 #245472-012
   35  *
   36  * On some models, the cpu can hang if it's running at a slow speed.
   37  * Workarounds included below.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __FBSDID("$FreeBSD: releng/5.3/sys/i386/i386/p4tcc.c 126412 2004-02-29 18:30:35Z maxim $");
   42 
   43 #include "opt_cpu.h"
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/conf.h>
   48 #include <sys/power.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/types.h>
   51 
   52 #include <machine/md_var.h>
   53 #include <machine/specialreg.h>
   54 
   55 static u_int                    p4tcc_percentage;
   56 static u_int                    p4tcc_economy;
   57 static u_int                    p4tcc_performance;
   58 static struct sysctl_ctx_list   p4tcc_sysctl_ctx;
   59 static struct sysctl_oid        *p4tcc_sysctl_tree;
   60 
   61 static struct {
   62         u_short level;
   63         u_short rlevel;
   64         u_short reg;
   65 } tcc[] = {
   66         { 88, 100, 0 },
   67         { 75, 88,  7 },
   68         { 63, 75,  6 },
   69         { 50, 63,  5 },
   70         { 38, 50,  4 },
   71         { 25, 38,  3 },
   72         { 13, 25,  2 },
   73         { 0,  13,  1 }
   74 };
   75 
   76 #define TCC_LEVELS      sizeof(tcc) / sizeof(tcc[0])
   77 
   78 static u_short
   79 p4tcc_getperf(void)
   80 {
   81         u_int64_t msreg;
   82         int i;
   83 
   84         msreg = rdmsr(MSR_THERM_CONTROL);
   85         msreg = (msreg >> 1) & 0x07;
   86         for (i = 0; i < TCC_LEVELS; i++) {
   87                 if (msreg == tcc[i].reg)
   88                         break;
   89         }
   90 
   91         return (tcc[i].rlevel);
   92 }
   93 
   94 static void
   95 p4tcc_setperf(u_int percentage)
   96 {
   97         int i;
   98         u_int64_t msreg;
   99 
  100         if (percentage > tcc[0].rlevel)
  101                 percentage = tcc[0].rlevel;
  102         for (i = 0; i < TCC_LEVELS - 1; i++) {
  103                 if (percentage > tcc[i].level)
  104                         break;
  105         }
  106 
  107         msreg = rdmsr(MSR_THERM_CONTROL);
  108         msreg &= ~0x1e; /* bit 0 reserved */
  109         if (tcc[i].reg != 0)
  110                 msreg |= tcc[i].reg << 1 | 1 << 4;
  111         wrmsr(MSR_THERM_CONTROL, msreg);
  112 }
  113 
  114 static int
  115 p4tcc_perf_sysctl(SYSCTL_HANDLER_ARGS)
  116 {
  117         u_int percentage;
  118         int error;
  119 
  120         p4tcc_percentage = p4tcc_getperf();
  121         percentage = p4tcc_percentage;
  122         error = sysctl_handle_int(oidp, &percentage, 0, req);
  123         if (error || !req->newptr) {
  124                 return (error);
  125         }
  126         if (p4tcc_percentage != percentage) {
  127                 p4tcc_setperf(percentage);
  128         }
  129 
  130         return (error);
  131 }
  132 
  133 static void
  134 p4tcc_power_profile(void *arg)
  135 {
  136         int state;
  137         u_int new;
  138 
  139         state = power_profile_get_state();
  140         if (state != POWER_PROFILE_PERFORMANCE &&
  141             state != POWER_PROFILE_ECONOMY) {
  142                 return;
  143         }
  144 
  145         switch (state) {
  146         case POWER_PROFILE_PERFORMANCE:
  147                 new = p4tcc_performance;
  148                 break;
  149         case POWER_PROFILE_ECONOMY:
  150                 new = p4tcc_economy;
  151                 break;
  152         default:
  153                 new = p4tcc_getperf();
  154                 break;
  155         }
  156 
  157         if (p4tcc_getperf() != new) {
  158                 p4tcc_setperf(new);
  159         }
  160 }
  161 
  162 static int
  163 p4tcc_profile_sysctl(SYSCTL_HANDLER_ARGS)
  164 {
  165         u_int32_t *argp;
  166         u_int32_t arg;
  167         int error;
  168 
  169         argp = (u_int32_t *)oidp->oid_arg1;
  170         arg = *argp;
  171         error = sysctl_handle_int(oidp, &arg, 0, req);
  172 
  173         /* error or no new value */
  174         if ((error != 0) || (req->newptr == NULL))
  175                 return (error);
  176 
  177         /* range check */
  178         if (arg > tcc[0].rlevel)
  179                 arg = tcc[0].rlevel;
  180 
  181         /* set new value and possibly switch */
  182         *argp = arg;
  183 
  184         p4tcc_power_profile(NULL);
  185 
  186         *argp = p4tcc_getperf();
  187 
  188         return (0);
  189 }
  190 
  191 static void
  192 setup_p4tcc(void *dummy __unused)
  193 {
  194 
  195         if ((cpu_feature & (CPUID_ACPI | CPUID_TM)) !=
  196             (CPUID_ACPI | CPUID_TM))
  197                 return;
  198 
  199         switch (cpu_id & 0xf) {
  200         case 0x22:      /* errata O50 P44 and Z21 */
  201         case 0x24:
  202         case 0x25:
  203         case 0x27:
  204         case 0x29:
  205                 /* hang with 12.5 */
  206                 tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2];
  207                 break;
  208         case 0x07:      /* errata N44 and P18 */
  209         case 0x0a:
  210         case 0x12:
  211         case 0x13:
  212                 /* hang at 12.5 and 25 */
  213                 tcc[TCC_LEVELS - 1] = tcc[TCC_LEVELS - 2] = tcc[TCC_LEVELS - 3];
  214                 break;
  215         default:
  216                 break;
  217         }
  218 
  219         p4tcc_economy = tcc[TCC_LEVELS - 1].rlevel;
  220         p4tcc_performance = tcc[0].rlevel;
  221 
  222         p4tcc_percentage = p4tcc_getperf();
  223         printf("Pentium 4 TCC support enabled, current performance %u%%\n",
  224             p4tcc_percentage);
  225 
  226         sysctl_ctx_init(&p4tcc_sysctl_ctx);
  227         p4tcc_sysctl_tree = SYSCTL_ADD_NODE(&p4tcc_sysctl_ctx,
  228             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "p4tcc", CTLFLAG_RD, 0,
  229             "Pentium 4 Thermal Control Circuitry support");
  230         SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx,
  231             SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO,
  232             "cpuperf", CTLTYPE_INT | CTLFLAG_RW,
  233             &p4tcc_percentage, 0, p4tcc_perf_sysctl, "I",
  234             "CPU performance in % of maximum");
  235         SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx,
  236             SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO,
  237             "cpuperf_performance", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW,
  238             &p4tcc_performance, 0, p4tcc_profile_sysctl, "I",
  239             "CPU performance in % of maximum in Performance mode");
  240         SYSCTL_ADD_PROC(&p4tcc_sysctl_ctx,
  241             SYSCTL_CHILDREN(p4tcc_sysctl_tree), OID_AUTO,
  242             "cpuperf_economy", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_RW,
  243             &p4tcc_economy, 0, p4tcc_profile_sysctl, "I",
  244             "CPU performance in % of maximum in Economy mode");
  245 
  246         /* register performance profile change handler */
  247         EVENTHANDLER_REGISTER(power_profile_change, p4tcc_power_profile, NULL, 0);
  248 }
  249 SYSINIT(setup_p4tcc, SI_SUB_CPU, SI_ORDER_ANY, setup_p4tcc, NULL);

Cache object: 2614e0b534258996682893635092ffa2


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