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/powermng/est/est.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 /*      $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka Exp $  */
    2 /*
    3  * Copyright (c) 2003 Michael Eriksson.
    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  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 /*-
   29  * Copyright (c) 2004 The NetBSD Foundation, Inc.
   30  * All rights reserved.
   31  *
   32  * Redistribution and use in source and binary forms, with or without
   33  * modification, are permitted provided that the following conditions
   34  * are met:
   35  * 1. Redistributions of source code must retain the above copyright
   36  *    notice, this list of conditions and the following disclaimer.
   37  * 2. Redistributions in binary form must reproduce the above copyright
   38  *    notice, this list of conditions and the following disclaimer in the
   39  *    documentation and/or other materials provided with the distribution.
   40  * 3. All advertising materials mentioning features or use of this software
   41  *    must display the following acknowledgement:
   42  *        This product includes software developed by the NetBSD
   43  *        Foundation, Inc. and its contributors.
   44  * 4. Neither the name of The NetBSD Foundation nor the names of its
   45  *    contributors may be used to endorse or promote products derived
   46  *    from this software without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   58  * POSSIBILITY OF SUCH DAMAGE.
   59  */
   60 
   61 /*
   62  * This is a driver for Intel's Enhanced SpeedStep Technology (EST),
   63  * as implemented in Pentium M processors.
   64  *
   65  * Reference documentation:
   66  *
   67  * - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
   68  *   System Programming Guide.
   69  *   Section 13.14, Enhanced Intel SpeedStep technology.
   70  *   Table B-2, MSRs in Pentium M Processors.
   71  *   http://www.intel.com/design/pentium4/manuals/253668.htm
   72  *
   73  * - Intel Pentium M Processor Datasheet.
   74  *   Table 5, Voltage and Current Specifications.
   75  *   http://www.intel.com/design/mobile/datashts/252612.htm
   76  *
   77  * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet
   78  *   Table 3-4, 3-5, 3-6, Voltage and Current Specifications.
   79  *   http://www.intel.com/design/mobile/datashts/302189.htm
   80  *
   81  * - Linux cpufreq patches, speedstep-centrino.c.
   82  *   Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
   83  *   http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
   84  *
   85  *   ACPI objects: _PCT is MSR location, _PSS is freq/voltage, _PPC is caps.
   86  *
   87  * $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka Exp $
   88  */
   89 
   90 #include <sys/param.h>
   91 #include <sys/systm.h>
   92 #include <sys/malloc.h>
   93 #include <sys/kernel.h>
   94 #include <sys/module.h>
   95 #include <sys/sysctl.h>
   96 
   97 #include <machine/cpu.h>
   98 #include <machine/md_var.h>
   99 #include <machine/specialreg.h>
  100 
  101 
  102 struct fq_info {
  103         int mhz;
  104         int mv;
  105 };
  106 
  107 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
  108 static const struct fq_info pentium_m_900[] = {
  109         {  900, 1004 },
  110         {  800,  988 },
  111         {  600,  844 },
  112 };
  113 
  114 /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
  115 static const struct fq_info pentium_m_1000[] = {
  116         { 1000, 1004 },
  117         {  900,  988 },
  118         {  800,  972 },
  119         {  600,  844 },
  120 };
  121 
  122 /* Low Voltage Intel Pentium M processor 1.10 GHz */
  123 static const struct fq_info pentium_m_1100[] = {
  124         { 1100, 1180 },
  125         { 1000, 1164 },
  126         {  900, 1100 },
  127         {  800, 1020 },
  128         {  600,  956 },
  129 };
  130 
  131 /* Low Voltage Intel Pentium M processor 1.20 GHz */
  132 static const struct fq_info pentium_m_1200[] = {
  133         { 1200, 1180 },
  134         { 1100, 1164 },
  135         { 1000, 1100 },
  136         {  900, 1020 },
  137         {  800, 1004 },
  138         {  600,  956 },
  139 };
  140 
  141 /* Low Voltage Intel Pentium M processor 1.30 GHz */
  142 static const struct fq_info pentium_m_1300_lv[] = {
  143         { 1300, 1180 },
  144         { 1200, 1164 },
  145         { 1100, 1100 },
  146         { 1000, 1020 },
  147         {  900, 1004 },
  148         {  800,  988 },
  149         {  600,  956 },
  150 };
  151 
  152 /* Intel Pentium M processor 1.30 GHz */
  153 static const struct fq_info pentium_m_1300[] = {
  154         { 1300, 1388 },
  155         { 1200, 1356 },
  156         { 1000, 1292 },
  157         {  800, 1260 },
  158         {  600,  956 },
  159 };
  160 
  161 /* Intel Pentium M processor 1.40 GHz */
  162 static const struct fq_info pentium_m_1400[] = {
  163         { 1400, 1484 },
  164         { 1200, 1436 },
  165         { 1000, 1308 },
  166         {  800, 1180 },
  167         {  600,  956 }
  168 };
  169 
  170 /* Intel Pentium M processor 1.50 GHz */
  171 static const struct fq_info pentium_m_1500[] = {
  172         { 1500, 1484 },
  173         { 1400, 1452 },
  174         { 1200, 1356 },
  175         { 1000, 1228 },
  176         {  800, 1116 },
  177         {  600,  956 }
  178 };
  179 
  180 /* Intel Pentium M processor 1.60 GHz */
  181 static const struct fq_info pentium_m_1600[] = {
  182         { 1600, 1484 },
  183         { 1400, 1420 },
  184         { 1200, 1276 },
  185         { 1000, 1164 },
  186         {  800, 1036 },
  187         {  600,  956 }
  188 };
  189 
  190 /* Intel Pentium M processor 1.70 GHz */
  191 static const struct fq_info pentium_m_1700[] = {
  192         { 1700, 1484 },
  193         { 1400, 1308 },
  194         { 1200, 1228 },
  195         { 1000, 1116 },
  196         {  800, 1004 },
  197         {  600,  956 }
  198 };
  199 
  200 /* Intel Pentium M processor 723 Ultra Low Voltage 1.0 GHz */
  201 static const struct fq_info pentium_m_n723[] = {
  202         { 1000,  940 },
  203         {  900,  908 },
  204         {  800,  876 },
  205         {  600,  812 }
  206 };
  207 
  208 /* Intel Pentium M processor 733 Ultra Low Voltage 1.1 GHz */
  209 static const struct fq_info pentium_m_n733[] = {
  210         { 1100,  940 },
  211         { 1000,  924 },
  212         {  900,  892 },
  213         {  800,  876 },
  214         {  600,  812 }
  215 };
  216 
  217 /* Intel Pentium M processor 753 Ultra Low Voltage 1.2 GHz */
  218 static const struct fq_info pentium_m_n753[] = {
  219         { 1200,  940 },
  220         { 1100,  924 },
  221         { 1000,  908 },
  222         {  900,  876 },
  223         {  800,  860 },
  224         {  600,  812 }
  225 };
  226 
  227 /* Intel Pentium M processor 773 Ultra Low Voltage 1.3 GHz */
  228 static const struct fq_info pentium_m_n773[] = {
  229         { 1300,  940 },
  230         { 1200,  924 },
  231         { 1100,  908 },
  232         { 1000,  892 },
  233         {  900,  876 },
  234         {  800,  860 },
  235         {  600,  812 }
  236 };
  237 
  238 /* Intel Pentium M processor 738 Low Voltage 1.4 GHz */
  239 static const struct fq_info pentium_m_n738[] = {
  240         { 1400, 1116 },
  241         { 1300, 1116 },
  242         { 1200, 1100 },
  243         { 1100, 1068 },
  244         { 1000, 1052 },
  245         {  900, 1036 },
  246         {  800, 1020 },
  247         {  600,  988 }
  248 };
  249 
  250 /* Intel Pentium M processor 758 Low Voltage 1.5 GHz */
  251 static const struct fq_info pentium_m_n758[] = {
  252         { 1500, 1116 },
  253         { 1400, 1116 },
  254         { 1300, 1100 },
  255         { 1200, 1084 },
  256         { 1100, 1068 },
  257         { 1000, 1052 },
  258         {  900, 1036 },
  259         {  800, 1020 },
  260         {  600,  988 }
  261 };
  262 
  263 /* Intel Pentium M processor 778 Low Voltage 1.6 GHz */
  264 static const struct fq_info pentium_m_n778[] = {
  265         { 1600, 1116 },
  266         { 1500, 1116 },
  267         { 1400, 1100 },
  268         { 1300, 1184 },
  269         { 1200, 1068 },
  270         { 1100, 1052 },
  271         { 1000, 1052 },
  272         {  900, 1036 },
  273         {  800, 1020 },
  274         {  600,  988 }
  275 };
  276 
  277 /* Intel Pentium M processor 710 1.4 GHz */
  278 static const struct fq_info pentium_m_n710[] = {
  279         { 1400, 1340 },
  280         { 1200, 1228 },
  281         { 1000, 1148 },
  282         {  800, 1068 },
  283         {  600,  998 }
  284 };
  285 
  286 /* Intel Pentium M processor 715 1.5 GHz */
  287 static const struct fq_info pentium_m_n715[] = {
  288         { 1500, 1340 },
  289         { 1200, 1228 },
  290         { 1000, 1148 },
  291         {  800, 1068 },
  292         {  600,  988 }
  293 };
  294 
  295 /* Intel Pentium M processor 725 1.6 GHz */
  296 static const struct fq_info pentium_m_n725[] = {
  297         { 1600, 1340 },
  298         { 1400, 1276 },
  299         { 1200, 1212 },
  300         { 1000, 1132 },
  301         {  800, 1068 },
  302         {  600,  988 }
  303 };
  304 
  305 /* Intel Pentium M processor 730 1.6 GHz */
  306 static const struct fq_info pentium_m_n730[] = {
  307        { 1600, 1308 },
  308        { 1333, 1260 },
  309        { 1200, 1212 },
  310        { 1067, 1180 },
  311        {  800,  988 }
  312 };
  313 
  314 /* Intel Pentium M processor 735 1.7 GHz */
  315 static const struct fq_info pentium_m_n735[] = {
  316         { 1700, 1340 },
  317         { 1400, 1244 },
  318         { 1200, 1180 },
  319         { 1000, 1116 },
  320         {  800, 1052 },
  321         {  600,  988 }
  322 };
  323 
  324 /* Intel Pentium M processor 740 1.73 GHz */
  325 static const struct fq_info pentium_m_n740[] = {
  326        { 1733, 1356 },
  327        { 1333, 1212 },
  328        { 1067, 1100 },
  329        {  800,  988 },
  330 };
  331 
  332 /* Intel Pentium M processor 740 1.73 GHz (988-1308mV version?) */
  333 static const struct fq_info pentium_m_n740_2[] = {
  334         { 1733, 1308 },
  335         { 1333, 1148 },
  336         { 1067, 1068 },
  337         {  800,  988 }
  338 };
  339 
  340 /* Intel Pentium M processor 745 1.8 GHz */
  341 static const struct fq_info pentium_m_n745[] = {
  342         { 1800, 1340 },
  343         { 1600, 1292 },
  344         { 1400, 1228 },
  345         { 1200, 1164 },
  346         { 1000, 1116 },
  347         {  800, 1052 },
  348         {  600,  988 }
  349 };
  350 
  351 /* Intel Pentium M processor 750 1.86 GHz */
  352 /* values extracted from \_PR\NPSS (via _PSS) SDST ACPI table */
  353 static const struct fq_info pentium_m_n750[] = {
  354         { 1867, 1308 },
  355         { 1600, 1228 },
  356         { 1333, 1148 },
  357         { 1067, 1068 },
  358         {  800,  988 }
  359 };
  360 
  361 static const struct fq_info pentium_m_n750_2[] = {
  362         { 1867, 1356 },
  363         { 1600, 1228 },
  364         { 1333, 1148 },
  365         { 1067, 1068 },
  366         {  800,  988 }
  367 };
  368 
  369 /* Intel Pentium M processor 755 2.0 GHz */
  370 static const struct fq_info pentium_m_n755[] = {
  371         { 2000, 1340 },
  372         { 1800, 1292 },
  373         { 1600, 1244 },
  374         { 1400, 1196 },
  375         { 1200, 1148 },
  376         { 1000, 1100 },
  377         {  800, 1052 },
  378         {  600,  988 }
  379 };
  380 
  381 /* Intel Pentium M processor 760 2.0 GHz */
  382 static const struct fq_info pentium_m_n760[] = {
  383         { 2000, 1356 },
  384         { 1600, 1244 },
  385         { 1333, 1164 },
  386         { 1067, 1084 },
  387         {  800,  988 }
  388 };
  389 
  390 /* Intel Pentium M processor 760 2.0 GHz */
  391 static const struct fq_info pentium_m_n760_2[] = {
  392         { 2000, 1308 },
  393         { 1600, 1244 },
  394         { 1333, 1164 },
  395         { 1067, 1084 },
  396         {  800,  988 }
  397 };
  398 
  399 /* Intel Pentium M processor 765 2.1 GHz */
  400 static const struct fq_info pentium_m_n765[] = {
  401         { 2100, 1340 },
  402         { 1800, 1276 },
  403         { 1600, 1228 },
  404         { 1400, 1180 },
  405         { 1200, 1132 },
  406         { 1000, 1084 },
  407         {  800, 1036 },
  408         {  600,  988 }
  409 };
  410 
  411 /* Intel Pentium M processor 770 2.13 GHz */
  412 static const struct fq_info pentium_m_n770[] = {
  413         { 2133, 1551 },
  414         { 1800, 1429 },
  415         { 1600, 1356 },
  416         { 1400, 1180 },
  417         { 1200, 1132 },
  418         { 1000, 1084 },
  419         {  800, 1036 },
  420         {  600,  988 }
  421 };
  422 
  423 /* Intel Pentium M processor 770 2.13 GHz */
  424 static const struct fq_info pentium_m_n770_2[] = {
  425         { 2133, 1356 },
  426         { 1867, 1292 },
  427         { 1600, 1212 },
  428         { 1333, 1148 },
  429         { 1067, 1068 },
  430         {  800,  988 }
  431 };
  432 
  433 /* Intel Pentium Core Duo T2300 */
  434 static const struct fq_info pentium_core_duo_t2300[] = {
  435         { 1666, 1404 },
  436         { 1500, 1404 },
  437         { 1333, 1404 },
  438         { 1167, 1404 },
  439         { 1000, 1004 },
  440         {  667, 1004 },
  441         {  333, 1004 },
  442         {  167, 1004 },
  443 };
  444 
  445 static const struct fq_info pentium_core2_duo_t7500[] = {
  446         { 2200, 1420 },
  447         { 1600, 1212 },
  448         { 1200, 1068 },
  449         {  800,  988 },
  450 };
  451 
  452 struct fqlist {
  453         const char *brand_tag;
  454         const u_int cpu_id;
  455         size_t tablec;
  456         const struct fq_info *table;
  457         const int fsbmult; /* in multiples of 133 MHz */
  458 };
  459 
  460 #define ENTRY(s, i, v, f)       { s, i, sizeof(v) / sizeof((v)[0]), v, f }
  461 static const struct fqlist pentium_m[] = { /* Banias */
  462         ENTRY(" 900", 0x0695, pentium_m_900,  3),
  463         ENTRY("1000", 0x0695, pentium_m_1000, 3),
  464         ENTRY("1100", 0x0695, pentium_m_1100, 3),
  465         ENTRY("1200", 0x0695, pentium_m_1200, 3),
  466         ENTRY("1300", 0x0695, pentium_m_1300, 3),
  467         ENTRY("1300", 0x0695, pentium_m_1300_lv, 3),
  468         ENTRY("1400", 0x0695, pentium_m_1400, 3),
  469         ENTRY("1500", 0x0695, pentium_m_1500, 3),
  470         ENTRY("1600", 0x0695, pentium_m_1600, 3),
  471         ENTRY("1700", 0x0695, pentium_m_1700, 3),
  472 };
  473 
  474 static const struct fqlist pentium_m_dothan[] = {
  475 
  476         /* low voltage CPUs */
  477         ENTRY("1.00", 0x06d8, pentium_m_n723, 3),
  478         ENTRY("1.10", 0x06d6, pentium_m_n733, 3),
  479         ENTRY("1.20", 0x06d8, pentium_m_n753, 3),
  480         ENTRY("1.30", 0, pentium_m_n773, 3), /* does this exist? */
  481 
  482         /* ultra low voltage CPUs */
  483         ENTRY("1.40", 0x06d6, pentium_m_n738, 3),
  484         ENTRY("1.50", 0x06d8, pentium_m_n758, 3),
  485         ENTRY("1.60", 0x06d8, pentium_m_n778, 3),
  486 
  487         /* 'regular' 400 MHz FSB CPUs */
  488         ENTRY("1.40", 0x06d6, pentium_m_n710, 3),
  489         ENTRY("1.50", 0x06d6, pentium_m_n715, 3),
  490         ENTRY("1.50", 0x06d8, pentium_m_n715, 3),
  491         ENTRY("1.60", 0x06d6, pentium_m_n725, 3),
  492         ENTRY("1.70", 0x06d6, pentium_m_n735, 3),
  493         ENTRY("1.80", 0x06d6, pentium_m_n745, 3),
  494         ENTRY("2.00", 0x06d6, pentium_m_n755, 3),
  495         ENTRY("2.10", 0x06d6, pentium_m_n765, 3),
  496 
  497         /* 533 MHz FSB CPUs */
  498         ENTRY("1.60", 0x06d8, pentium_m_n730, 4),
  499         ENTRY("1.73", 0x06d8, pentium_m_n740, 4),
  500         ENTRY("1.73", 0x06d8, pentium_m_n740_2, 4),
  501         ENTRY("1.86", 0x06d8, pentium_m_n750, 4),
  502         ENTRY("1.86", 0x06d8, pentium_m_n750_2, 4),
  503         ENTRY("2.00", 0x06d8, pentium_m_n760, 4),
  504         ENTRY("2.00", 0x06d8, pentium_m_n760_2, 4),
  505         ENTRY("2.13", 0x06d8, pentium_m_n770, 4),
  506         ENTRY("2.13", 0x06d8, pentium_m_n770_2, 4),
  507 
  508 
  509 };
  510 
  511 static const struct fqlist pentium_yonah[] = {
  512 
  513         /* 666 MHz FSB CPUs */
  514         ENTRY("1.66", 0x06e8, pentium_core_duo_t2300, 5 ),
  515 };
  516 
  517 static const struct fqlist pentium_merom[] = {
  518 
  519         /* 800 MHz FSB CPUs */
  520         ENTRY("2.20", 0x06fa, pentium_core2_duo_t7500, 6 ),
  521 };
  522 
  523 #undef ENTRY
  524 
  525 struct est_cpu {
  526         const char *brand_prefix;
  527         const char *brand_suffix;
  528         size_t listc;
  529         const struct fqlist *list;
  530 };
  531 
  532 static const struct est_cpu est_cpus[] = {
  533         {
  534                 "Intel(R) Pentium(R) M processor ", "MHz",
  535                 NELEM(pentium_m),
  536                 pentium_m
  537         },
  538         {
  539                 "Intel(R) Pentium(R) M processor ", "GHz",
  540                 NELEM(pentium_m_dothan),
  541                 pentium_m_dothan
  542         },
  543         {
  544                 "Genuine Intel(R) CPU           T2300  @ ", "GHz",
  545                 NELEM(pentium_yonah),
  546                 pentium_yonah
  547         },
  548         {
  549                 "Intel(R) Core(TM)2 Duo CPU     T7500  @ ", "GHz",
  550                 NELEM(pentium_merom),
  551                 pentium_merom
  552         },
  553 };
  554 
  555 #define NESTCPUS  (NELEM(est_cpus))
  556 
  557 #define MSR2MV(msr)     (((int) (msr) & 0xff) * 16 + 700)
  558 #define MSR2MHZ(msr)    (((((int) (msr) >> 8) & 0xff) * 100 * fsbmult + 1)/ 3)
  559 #define MV2MSR(mv)      ((((int) (mv) - 700) >> 4) & 0xff)
  560 #define MHZ2MSR(mhz)    (((3 * (mhz + 30) / (100 * fsbmult)) & 0xff) << 8)
  561 /* XXX 30 is slop to deal with the 33.333 MHz roundoff values */
  562 
  563 /*
  564  * Names and numbers from IA-32 System Programming Guide
  565  * (not found in <machine/specialregs.h>
  566  */
  567 #define MSR_PERF_STATUS         0x198
  568 #define MSR_PERF_CTL            0x199
  569 
  570 static const struct fqlist *est_fqlist; /* not NULL if functional */
  571 static int      fsbmult;
  572 
  573 static const char est_desc[] = "Enhanced SpeedStep";
  574 
  575 static char freqs_available[80];
  576 
  577 static int
  578 est_sysctl_helper(SYSCTL_HANDLER_ARGS)
  579 {
  580         uint64_t msr;
  581         int      fq, oldfq, err = 0;
  582         int      i;
  583 
  584         if (est_fqlist == NULL)
  585                 return (EOPNOTSUPP);
  586 
  587         oldfq = MSR2MHZ(rdmsr(MSR_PERF_CTL));
  588 
  589         if (req->newptr != NULL) {
  590                 err = SYSCTL_IN(req, &fq, sizeof(fq));
  591                 if (err)
  592                         return err;
  593 
  594                 if (fq != oldfq) {
  595                         for (i = est_fqlist->tablec - 1; i > 0; i--) {
  596                                 if (est_fqlist->table[i].mhz >= fq)
  597                                         break;
  598                         }
  599                         fq = est_fqlist->table[i].mhz;
  600                         msr = (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
  601                             MV2MSR(est_fqlist->table[i].mv) |
  602                             MHZ2MSR(est_fqlist->table[i].mhz);
  603                         wrmsr(MSR_PERF_CTL, msr);
  604                 }
  605         } else {
  606                 err = SYSCTL_OUT(req, &oldfq, sizeof(oldfq));
  607         }
  608 
  609         return err;
  610 }
  611 
  612 /*
  613  * Look for a CPU matching hw.model
  614  */
  615 static const struct fqlist *
  616 findcpu(const char *hwmodel, int mv)
  617 {
  618         const struct est_cpu    *ccpu;
  619         const struct fqlist     *fql;
  620         const char              *tag;
  621         size_t                  len;
  622         size_t                  i;
  623         int k;
  624 
  625         for (ccpu = est_cpus; ccpu < est_cpus + NESTCPUS; ++ccpu) {
  626                 len = strlen(ccpu->brand_prefix);
  627                 if (strncmp(ccpu->brand_prefix, hwmodel, len) != 0)
  628                         continue;
  629                 tag = hwmodel + len;
  630                 for (i = 0; i < ccpu->listc; i++) {
  631                         fql = &ccpu->list[i];
  632                         len = strlen(fql->brand_tag);
  633                         if (strncmp(fql->brand_tag, tag, len) != 0 ||
  634                             strcmp(ccpu->brand_suffix, tag + len))
  635                                 continue;
  636 
  637                         if (fql->cpu_id == 0 || fql->cpu_id == cpu_id) {
  638                                 /* verify operating point is in table, because
  639                                    CPUID + brand_tag still isn't unique. */
  640                                 for (k = fql->tablec - 1; k >= 0; k--) {
  641                                         if (fql->table[k].mv == mv)
  642                                                 return fql;
  643                                 }
  644                         }
  645                 }
  646         }
  647         return(NULL);
  648 }
  649 
  650 
  651 static struct sysctl_ctx_list   machdep_est_ctx;
  652 
  653 static int
  654 est_init(void)
  655 {
  656         char                    hwmodel[128];
  657         int                     mib[] = { CTL_HW, HW_MODEL };
  658         size_t                  modellen = sizeof(hwmodel);
  659         struct sysctl_oid       *oid, *leaf;
  660         uint64_t                msr;
  661         int                     mv;
  662         size_t                  len, freq_len;
  663         int                     err;
  664         size_t                  i;
  665 
  666         if ((cpu_feature2 & CPUID2_EST) == 0) {
  667                 kprintf("Enhanced SpeedStep unsupported on this hardware.\n");
  668                 return(EOPNOTSUPP);
  669         }
  670 
  671         modellen = sizeof(hwmodel);
  672         err = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
  673         if (err) {
  674                 kprintf("kernel_sysctl hw.model failed\n");
  675                 return(err);
  676         }
  677 
  678         msr = rdmsr(MSR_PERF_STATUS);
  679         mv = MSR2MV(msr);
  680         kprintf("%s (%d mV) ", est_desc, mv);
  681 
  682         est_fqlist = findcpu(hwmodel, mv);
  683         if (est_fqlist == NULL) {
  684                 kprintf(" - unknown CPU or operating point"
  685                        "(cpu_id:%#x, msr:%#jx).\n", cpu_id, (uintmax_t)msr);
  686                 return(EOPNOTSUPP);
  687         }
  688 
  689         /*
  690          * OK, tell the user the available frequencies.
  691          */
  692         fsbmult = est_fqlist->fsbmult;
  693         kprintf("%d MHz\n", MSR2MHZ(msr));
  694 
  695         freq_len = est_fqlist->tablec * (sizeof("9999 ")-1) + 1;
  696         if (freq_len >= sizeof(freqs_available)) {
  697                 kprintf("increase the size of freqs_available[]\n");
  698                 return(ENOMEM);
  699         }
  700         freqs_available[0] = '\0';
  701         len = 0;
  702         for (i = 0; i < est_fqlist->tablec; i++) {
  703                 len += ksnprintf(freqs_available + len, freq_len - len, "%d%s",
  704                     est_fqlist->table[i].mhz,
  705                     i < est_fqlist->tablec - 1 ? " " : "");
  706         }
  707         kprintf("%s frequencies available (MHz): %s\n", est_desc,
  708                freqs_available);
  709 
  710         /*
  711          * Setup the sysctl sub-tree machdep.est.*
  712          */
  713         oid = SYSCTL_ADD_NODE(&machdep_est_ctx,
  714             SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, "est",
  715             CTLFLAG_RD, NULL, "");
  716         if (oid == NULL)
  717                 return(EOPNOTSUPP);
  718         oid = SYSCTL_ADD_NODE(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
  719             OID_AUTO, "frequency", CTLFLAG_RD, NULL, "");
  720         if (oid == NULL)
  721                 return(EOPNOTSUPP);
  722         leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
  723             OID_AUTO, "target", CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
  724             est_sysctl_helper, "I",
  725             "Target CPU frequency for Enhanced SpeedStep");
  726         if (leaf == NULL)
  727                 return(EOPNOTSUPP);
  728         leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
  729             OID_AUTO, "current", CTLTYPE_INT | CTLFLAG_RD, NULL, 0,
  730             est_sysctl_helper, "I",
  731             "Current CPU frequency for Enhanced SpeedStep");
  732         if (leaf == NULL)
  733                 return(EOPNOTSUPP);
  734         leaf = SYSCTL_ADD_STRING(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
  735             OID_AUTO, "available", CTLFLAG_RD, freqs_available,
  736             sizeof(freqs_available),
  737             "CPU frequencies supported by Enhanced SpeedStep");
  738         if (leaf == NULL)
  739                 return(EOPNOTSUPP);
  740 
  741         return(0);
  742 }
  743 
  744 static int
  745 est_modevh(struct module *m __unused, int what, void *arg __unused)
  746 {
  747         int error;
  748 
  749         switch (what) {
  750         case MOD_LOAD:
  751                 error = sysctl_ctx_init(&machdep_est_ctx);
  752                 if (error != 0)
  753                         break;
  754                 error = est_init();
  755                 break;
  756         case MOD_UNLOAD:
  757                 error = sysctl_ctx_free(&machdep_est_ctx);
  758                 break;
  759         default:
  760                 error = EINVAL;
  761                 break;
  762         }
  763         return(error);
  764 }
  765 
  766 static moduledata_t est_mod = {
  767         "est",
  768         est_modevh,
  769         NULL,
  770 };
  771 
  772 DECLARE_MODULE(est, est_mod, SI_BOOT2_KLD, SI_ORDER_ANY);

Cache object: 110c1acdb71109e01fb9bca86fa0f957


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