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/cpufreq/powernow.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) 2004-2005 Bruno Ducrot
    3  * Copyright (c) 2004 FUKUDA Nobuhiko <nfukuda@spa.is.uec.ac.jp>
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 /*
   27  * Many thanks to Nate Lawson for his helpful comments on this driver and
   28  * to Jung-uk Kim for testing.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/bus.h>
   36 #include <sys/cpu.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/module.h>
   40 #include <sys/pcpu.h>
   41 #include <sys/systm.h>
   42 
   43 #include <machine/pc/bios.h>
   44 #include <machine/md_var.h>
   45 #include <machine/specialreg.h>
   46 #include <machine/cputypes.h>
   47 #include <machine/vmparam.h>
   48 #include <sys/rman.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/pmap.h>
   52 
   53 #include "cpufreq_if.h"
   54 
   55 #define PN7_TYPE        0
   56 #define PN8_TYPE        1
   57 
   58 /* Flags for some hardware bugs. */
   59 #define A0_ERRATA       0x1     /* Bugs for the rev. A0 of Athlon (K7):
   60                                  * Interrupts must be disabled and no half
   61                                  * multipliers are allowed */
   62 #define PENDING_STUCK   0x2     /* With some buggy chipset and some newer AMD64
   63                                  * processor (Rev. G?):
   64                                  * the pending bit from the msr FIDVID_STATUS
   65                                  * is set forever.  No workaround :( */
   66 
   67 /* Legacy configuration via BIOS table PSB. */
   68 #define PSB_START       0
   69 #define PSB_STEP        0x10
   70 #define PSB_SIG         "AMDK7PNOW!"
   71 #define PSB_LEN         10
   72 #define PSB_OFF         0
   73 
   74 struct psb_header {
   75         char             signature[10];
   76         uint8_t          version;
   77         uint8_t          flags;
   78         uint16_t         settlingtime;
   79         uint8_t          res1;
   80         uint8_t          numpst;
   81 } __packed;
   82 
   83 struct pst_header {
   84         uint32_t         cpuid;
   85         uint8_t          fsb;
   86         uint8_t          maxfid;
   87         uint8_t          startvid;
   88         uint8_t          numpstates;
   89 } __packed;
   90 
   91 /*
   92  * MSRs and bits used by Powernow technology
   93  */
   94 #define MSR_AMDK7_FIDVID_CTL            0xc0010041
   95 #define MSR_AMDK7_FIDVID_STATUS         0xc0010042
   96 
   97 /* Bitfields used by K7 */
   98 
   99 #define PN7_CTR_FID(x)                  ((x) & 0x1f)
  100 #define PN7_CTR_VID(x)                  (((x) & 0x1f) << 8)
  101 #define PN7_CTR_FIDC                    0x00010000
  102 #define PN7_CTR_VIDC                    0x00020000
  103 #define PN7_CTR_FIDCHRATIO              0x00100000
  104 #define PN7_CTR_SGTC(x)                 (((uint64_t)(x) & 0x000fffff) << 32)
  105 
  106 #define PN7_STA_CFID(x)                 ((x) & 0x1f)
  107 #define PN7_STA_SFID(x)                 (((x) >> 8) & 0x1f)
  108 #define PN7_STA_MFID(x)                 (((x) >> 16) & 0x1f)
  109 #define PN7_STA_CVID(x)                 (((x) >> 32) & 0x1f)
  110 #define PN7_STA_SVID(x)                 (((x) >> 40) & 0x1f)
  111 #define PN7_STA_MVID(x)                 (((x) >> 48) & 0x1f)
  112 
  113 /* ACPI ctr_val status register to powernow k7 configuration */
  114 #define ACPI_PN7_CTRL_TO_FID(x)         ((x) & 0x1f)
  115 #define ACPI_PN7_CTRL_TO_VID(x)         (((x) >> 5) & 0x1f)
  116 #define ACPI_PN7_CTRL_TO_SGTC(x)        (((x) >> 10) & 0xffff)
  117 
  118 /* Bitfields used by K8 */
  119 
  120 #define PN8_CTR_FID(x)                  ((x) & 0x3f)
  121 #define PN8_CTR_VID(x)                  (((x) & 0x1f) << 8)
  122 #define PN8_CTR_PENDING(x)              (((x) & 1) << 32)
  123 
  124 #define PN8_STA_CFID(x)                 ((x) & 0x3f)
  125 #define PN8_STA_SFID(x)                 (((x) >> 8) & 0x3f)
  126 #define PN8_STA_MFID(x)                 (((x) >> 16) & 0x3f)
  127 #define PN8_STA_PENDING(x)              (((x) >> 31) & 0x01)
  128 #define PN8_STA_CVID(x)                 (((x) >> 32) & 0x1f)
  129 #define PN8_STA_SVID(x)                 (((x) >> 40) & 0x1f)
  130 #define PN8_STA_MVID(x)                 (((x) >> 48) & 0x1f)
  131 
  132 /* Reserved1 to powernow k8 configuration */
  133 #define PN8_PSB_TO_RVO(x)               ((x) & 0x03)
  134 #define PN8_PSB_TO_IRT(x)               (((x) >> 2) & 0x03)
  135 #define PN8_PSB_TO_MVS(x)               (((x) >> 4) & 0x03)
  136 #define PN8_PSB_TO_BATT(x)              (((x) >> 6) & 0x03)
  137 
  138 /* ACPI ctr_val status register to powernow k8 configuration */
  139 #define ACPI_PN8_CTRL_TO_FID(x)         ((x) & 0x3f)
  140 #define ACPI_PN8_CTRL_TO_VID(x)         (((x) >> 6) & 0x1f)
  141 #define ACPI_PN8_CTRL_TO_VST(x)         (((x) >> 11) & 0x1f)
  142 #define ACPI_PN8_CTRL_TO_MVS(x)         (((x) >> 18) & 0x03)
  143 #define ACPI_PN8_CTRL_TO_PLL(x)         (((x) >> 20) & 0x7f)
  144 #define ACPI_PN8_CTRL_TO_RVO(x)         (((x) >> 28) & 0x03)
  145 #define ACPI_PN8_CTRL_TO_IRT(x)         (((x) >> 30) & 0x03)
  146 
  147 
  148 #define WRITE_FIDVID(fid, vid, ctrl)    \
  149         wrmsr(MSR_AMDK7_FIDVID_CTL,     \
  150             (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
  151 
  152 #define COUNT_OFF_IRT(irt)      DELAY(10 * (1 << (irt)))
  153 #define COUNT_OFF_VST(vst)      DELAY(20 * (vst))
  154 
  155 #define FID_TO_VCO_FID(fid)     \
  156         (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
  157 
  158 /*
  159  * Divide each value by 10 to get the processor multiplier.
  160  * Some of those tables are the same as the Linux powernow-k7
  161  * implementation by Dave Jones.
  162  */
  163 static int pn7_fid_to_mult[32] = {
  164         110, 115, 120, 125, 50, 55, 60, 65,
  165         70, 75, 80, 85, 90, 95, 100, 105,
  166         30, 190, 40, 200, 130, 135, 140, 210,
  167         150, 225, 160, 165, 170, 180, 0, 0,
  168 };
  169 
  170 
  171 static int pn8_fid_to_mult[64] = {
  172         40, 45, 50, 55, 60, 65, 70, 75,
  173         80, 85, 90, 95, 100, 105, 110, 115,
  174         120, 125, 130, 135, 140, 145, 150, 155,
  175         160, 165, 170, 175, 180, 185, 190, 195,
  176         200, 205, 210, 215, 220, 225, 230, 235,
  177         240, 245, 250, 255, 260, 265, 270, 275,
  178         280, 285, 290, 295, 300, 305, 310, 315,
  179         320, 325, 330, 335, 340, 345, 350, 355,
  180 };
  181 
  182 /*
  183  * Units are in mV.
  184  */
  185 /* Mobile VRM (K7) */
  186 static int pn7_mobile_vid_to_volts[] = {
  187         2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
  188         1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
  189         1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
  190         1075, 1050, 1025, 1000, 975, 950, 925, 0,
  191 };
  192 /* Desktop VRM (K7) */
  193 static int pn7_desktop_vid_to_volts[] = {
  194         2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
  195         1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
  196         1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
  197         1075, 1050, 1025, 1000, 975, 950, 925, 0,
  198 };
  199 /* Desktop and Mobile VRM (K8) */
  200 static int pn8_vid_to_volts[] = {
  201         1550, 1525, 1500, 1475, 1450, 1425, 1400, 1375,
  202         1350, 1325, 1300, 1275, 1250, 1225, 1200, 1175,
  203         1150, 1125, 1100, 1075, 1050, 1025, 1000, 975,
  204         950, 925, 900, 875, 850, 825, 800, 0,
  205 };
  206 
  207 #define POWERNOW_MAX_STATES             16
  208 
  209 struct powernow_state {
  210         int freq;
  211         int power;
  212         int fid;
  213         int vid;
  214 };
  215 
  216 struct pn_softc {
  217         device_t                 dev;
  218         int                      pn_type;
  219         struct powernow_state    powernow_states[POWERNOW_MAX_STATES];
  220         u_int                    fsb;
  221         u_int                    sgtc;
  222         u_int                    vst;
  223         u_int                    mvs;
  224         u_int                    pll;
  225         u_int                    rvo;
  226         u_int                    irt;
  227         int                      low;
  228         int                      powernow_max_states;
  229         u_int                    powernow_state;
  230         u_int                    errata;
  231         int                     *vid_to_volts;
  232 };
  233 
  234 /*
  235  * Offsets in struct cf_setting array for private values given by
  236  * acpi_perf driver.
  237  */
  238 #define PX_SPEC_CONTROL         0
  239 #define PX_SPEC_STATUS          1
  240 
  241 static void     pn_identify(driver_t *driver, device_t parent);
  242 static int      pn_probe(device_t dev);
  243 static int      pn_attach(device_t dev);
  244 static int      pn_detach(device_t dev);
  245 static int      pn_set(device_t dev, const struct cf_setting *cf);
  246 static int      pn_get(device_t dev, struct cf_setting *cf);
  247 static int      pn_settings(device_t dev, struct cf_setting *sets,
  248                     int *count);
  249 static int      pn_type(device_t dev, int *type);
  250 
  251 static device_method_t pn_methods[] = {
  252         /* Device interface */
  253         DEVMETHOD(device_identify, pn_identify),
  254         DEVMETHOD(device_probe, pn_probe),
  255         DEVMETHOD(device_attach, pn_attach),
  256         DEVMETHOD(device_detach, pn_detach),
  257 
  258         /* cpufreq interface */
  259         DEVMETHOD(cpufreq_drv_set, pn_set),
  260         DEVMETHOD(cpufreq_drv_get, pn_get),
  261         DEVMETHOD(cpufreq_drv_settings, pn_settings),
  262         DEVMETHOD(cpufreq_drv_type, pn_type),
  263 
  264         {0, 0}
  265 };
  266 
  267 static devclass_t pn_devclass;
  268 static driver_t pn_driver = {
  269         "powernow",
  270         pn_methods,
  271         sizeof(struct pn_softc),
  272 };
  273 
  274 DRIVER_MODULE(powernow, cpu, pn_driver, pn_devclass, 0, 0);
  275 
  276 static int
  277 pn7_setfidvid(struct pn_softc *sc, int fid, int vid)
  278 {
  279         int cfid, cvid;
  280         uint64_t status, ctl;
  281 
  282         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  283         cfid = PN7_STA_CFID(status);
  284         cvid = PN7_STA_CVID(status);
  285 
  286         /* We're already at the requested level. */
  287         if (fid == cfid && vid == cvid)
  288                 return (0);
  289 
  290         ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
  291 
  292         ctl |= PN7_CTR_FID(fid);
  293         ctl |= PN7_CTR_VID(vid);
  294         ctl |= PN7_CTR_SGTC(sc->sgtc);
  295 
  296         if (sc->errata & A0_ERRATA)
  297                 disable_intr();
  298 
  299         if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) {
  300                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  301                 if (vid != cvid)
  302                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  303         } else {
  304                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  305                 if (fid != cfid)
  306                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  307         }
  308 
  309         if (sc->errata & A0_ERRATA)
  310                 enable_intr();
  311 
  312         return (0);
  313 }
  314 
  315 static int
  316 pn8_read_pending_wait(uint64_t *status)
  317 {
  318         int i = 10000;
  319 
  320         do
  321                 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  322         while (PN8_STA_PENDING(*status) && --i);
  323 
  324         return (i == 0 ? ENXIO : 0);
  325 }
  326 
  327 static int
  328 pn8_write_fidvid(u_int fid, u_int vid, uint64_t ctrl, uint64_t *status)
  329 {
  330         int i = 100;
  331 
  332         do
  333                 WRITE_FIDVID(fid, vid, ctrl);
  334         while (pn8_read_pending_wait(status) && --i);
  335 
  336         return (i == 0 ? ENXIO : 0);
  337 }
  338 
  339 static int
  340 pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
  341 {
  342         uint64_t status;
  343         int cfid, cvid;
  344         int rvo;
  345         int rv;
  346         u_int val;
  347 
  348         rv = pn8_read_pending_wait(&status);
  349         if (rv)
  350                 return (rv);
  351 
  352         cfid = PN8_STA_CFID(status);
  353         cvid = PN8_STA_CVID(status);
  354 
  355         if (fid == cfid && vid == cvid)
  356                 return (0);
  357 
  358         /*
  359          * Phase 1: Raise core voltage to requested VID if frequency is
  360          * going up.
  361          */
  362         while (cvid > vid) {
  363                 val = cvid - (1 << sc->mvs);
  364                 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
  365                 if (rv) {
  366                         sc->errata |= PENDING_STUCK;
  367                         return (rv);
  368                 }
  369                 cvid = PN8_STA_CVID(status);
  370                 COUNT_OFF_VST(sc->vst);
  371         }
  372 
  373         /* ... then raise to voltage + RVO (if required) */
  374         for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) {
  375                 /* XXX It's not clear from spec if we have to do that
  376                  * in 0.25 step or in MVS.  Therefore do it as it's done
  377                  * under Linux */
  378                 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
  379                 if (rv) {
  380                         sc->errata |= PENDING_STUCK;
  381                         return (rv);
  382                 }
  383                 cvid = PN8_STA_CVID(status);
  384                 COUNT_OFF_VST(sc->vst);
  385         }
  386 
  387         /* Phase 2: change to requested core frequency */
  388         if (cfid != fid) {
  389                 u_int vco_fid, vco_cfid, fid_delta;
  390 
  391                 vco_fid = FID_TO_VCO_FID(fid);
  392                 vco_cfid = FID_TO_VCO_FID(cfid);
  393 
  394                 while (abs(vco_fid - vco_cfid) > 2) {
  395                         fid_delta = (vco_cfid & 1) ? 1 : 2;
  396                         if (fid > cfid) {
  397                                 if (cfid > 7)
  398                                         val = cfid + fid_delta;
  399                                 else
  400                                         val = FID_TO_VCO_FID(cfid) + fid_delta;
  401                         } else
  402                                 val = cfid - fid_delta;
  403                         rv = pn8_write_fidvid(val, cvid,
  404                             sc->pll * (uint64_t) sc->fsb,
  405                             &status);
  406                         if (rv) {
  407                                 sc->errata |= PENDING_STUCK;
  408                                 return (rv);
  409                         }
  410                         cfid = PN8_STA_CFID(status);
  411                         COUNT_OFF_IRT(sc->irt);
  412 
  413                         vco_cfid = FID_TO_VCO_FID(cfid);
  414                 }
  415 
  416                 rv = pn8_write_fidvid(fid, cvid,
  417                     sc->pll * (uint64_t) sc->fsb,
  418                     &status);
  419                 if (rv) {
  420                         sc->errata |= PENDING_STUCK;
  421                         return (rv);
  422                 }
  423                 cfid = PN8_STA_CFID(status);
  424                 COUNT_OFF_IRT(sc->irt);
  425         }
  426 
  427         /* Phase 3: change to requested voltage */
  428         if (cvid != vid) {
  429                 rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
  430                 cvid = PN8_STA_CVID(status);
  431                 COUNT_OFF_VST(sc->vst);
  432         }
  433 
  434         /* Check if transition failed. */
  435         if (cfid != fid || cvid != vid)
  436                 rv = ENXIO;
  437 
  438         return (rv);
  439 }
  440 
  441 static int
  442 pn_set(device_t dev, const struct cf_setting *cf)
  443 {
  444         struct pn_softc *sc;
  445         int fid, vid;
  446         int i;
  447         int rv;
  448 
  449         if (cf == NULL)
  450                 return (EINVAL);
  451         sc = device_get_softc(dev);
  452 
  453         if (sc->errata & PENDING_STUCK)
  454                 return (ENXIO);
  455 
  456         for (i = 0; i < sc->powernow_max_states; ++i)
  457                 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
  458                         break;
  459 
  460         fid = sc->powernow_states[i].fid;
  461         vid = sc->powernow_states[i].vid;
  462 
  463         rv = ENODEV;
  464 
  465         switch (sc->pn_type) {
  466         case PN7_TYPE:
  467                 rv = pn7_setfidvid(sc, fid, vid);
  468                 break;
  469         case PN8_TYPE:
  470                 rv = pn8_setfidvid(sc, fid, vid);
  471                 break;
  472         }
  473 
  474         return (rv);
  475 }
  476 
  477 static int
  478 pn_get(device_t dev, struct cf_setting *cf)
  479 {
  480         struct pn_softc *sc;
  481         u_int cfid = 0, cvid = 0;
  482         int i;
  483         uint64_t status;
  484 
  485         if (cf == NULL)
  486                 return (EINVAL);
  487         sc = device_get_softc(dev);
  488         if (sc->errata & PENDING_STUCK)
  489                 return (ENXIO);
  490 
  491         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  492 
  493         switch (sc->pn_type) {
  494         case PN7_TYPE:
  495                 cfid = PN7_STA_CFID(status);
  496                 cvid = PN7_STA_CVID(status);
  497                 break;
  498         case PN8_TYPE:
  499                 cfid = PN8_STA_CFID(status);
  500                 cvid = PN8_STA_CVID(status);
  501                 break;
  502         }
  503         for (i = 0; i < sc->powernow_max_states; ++i)
  504                 if (cfid == sc->powernow_states[i].fid &&
  505                     cvid == sc->powernow_states[i].vid)
  506                         break;
  507 
  508         if (i < sc->powernow_max_states) {
  509                 cf->freq = sc->powernow_states[i].freq / 1000;
  510                 cf->power = sc->powernow_states[i].power;
  511                 cf->lat = 200;
  512                 cf->volts = sc->vid_to_volts[cvid];
  513                 cf->dev = dev;
  514         } else {
  515                 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
  516                 cf->dev = NULL;
  517         }
  518 
  519         return (0);
  520 }
  521 
  522 static int
  523 pn_settings(device_t dev, struct cf_setting *sets, int *count)
  524 {
  525         struct pn_softc *sc;
  526         int i;
  527 
  528         if (sets == NULL|| count == NULL)
  529                 return (EINVAL);
  530         sc = device_get_softc(dev);
  531         if (*count < sc->powernow_max_states)
  532                 return (E2BIG);
  533         for (i = 0; i < sc->powernow_max_states; ++i) {
  534                 sets[i].freq = sc->powernow_states[i].freq / 1000;
  535                 sets[i].power = sc->powernow_states[i].power;
  536                 sets[i].lat = 200;
  537                 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid];
  538                 sets[i].dev = dev;
  539         }
  540         *count = sc->powernow_max_states;
  541 
  542         return (0);
  543 }
  544 
  545 static int
  546 pn_type(device_t dev, int *type)
  547 {
  548         if (type == NULL)
  549                 return (EINVAL);
  550 
  551         *type = CPUFREQ_TYPE_ABSOLUTE;
  552 
  553         return (0);
  554 }
  555 
  556 /*
  557  * Given a set of pair of fid/vid, and number of performance states,
  558  * compute powernow_states via an insertion sort.
  559  */
  560 static int
  561 decode_pst(struct pn_softc *sc, uint8_t *p, int npstates)
  562 {
  563         int i, j, n;
  564         struct powernow_state state;
  565 
  566         for (i = 0; i < POWERNOW_MAX_STATES; ++i)
  567                 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN;
  568 
  569         for (n = 0, i = 0; i < npstates; ++i) {
  570                 state.fid = *p++;
  571                 state.vid = *p++;
  572                 state.power = CPUFREQ_VAL_UNKNOWN;
  573 
  574                 switch (sc->pn_type) {
  575                 case PN7_TYPE:
  576                         state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
  577                         if ((sc->errata & A0_ERRATA) &&
  578                             (pn7_fid_to_mult[state.fid] % 10) == 5)
  579                                 continue;
  580                         break;
  581                 case PN8_TYPE:
  582                         state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
  583                         break;
  584                 }
  585 
  586                 j = n;
  587                 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
  588                         memcpy(&sc->powernow_states[j],
  589                             &sc->powernow_states[j - 1],
  590                             sizeof(struct powernow_state));
  591                         --j;
  592                 }
  593                 memcpy(&sc->powernow_states[j], &state,
  594                     sizeof(struct powernow_state));
  595                 ++n;
  596         }
  597 
  598         /*
  599          * Fix powernow_max_states, if errata a0 give us less states
  600          * than expected.
  601          */
  602         sc->powernow_max_states = n;
  603 
  604         if (bootverbose)
  605                 for (i = 0; i < sc->powernow_max_states; ++i) {
  606                         int fid = sc->powernow_states[i].fid;
  607                         int vid = sc->powernow_states[i].vid;
  608 
  609                         printf("powernow: %2i %8dkHz FID %02x VID %02x\n",
  610                             i,
  611                             sc->powernow_states[i].freq,
  612                             fid,
  613                             vid);
  614                 }
  615 
  616         return (0);
  617 }
  618 
  619 static int
  620 cpuid_is_k7(u_int cpuid)
  621 {
  622 
  623         switch (cpuid) {
  624         case 0x760:
  625         case 0x761:
  626         case 0x762:
  627         case 0x770:
  628         case 0x771:
  629         case 0x780:
  630         case 0x781:
  631         case 0x7a0:
  632                 return (TRUE);
  633         }
  634         return (FALSE);
  635 }
  636 
  637 static int
  638 pn_decode_pst(device_t dev)
  639 {
  640         int maxpst;
  641         struct pn_softc *sc;
  642         u_int cpuid, maxfid, startvid;
  643         u_long sig;
  644         struct psb_header *psb;
  645         uint8_t *p;
  646         u_int regs[4];
  647         uint64_t status;
  648 
  649         sc = device_get_softc(dev);
  650 
  651         do_cpuid(0x80000001, regs);
  652         cpuid = regs[0];
  653 
  654         if ((cpuid & 0xfff) == 0x760)
  655                 sc->errata |= A0_ERRATA;
  656 
  657         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  658 
  659         switch (sc->pn_type) {
  660         case PN7_TYPE:
  661                 maxfid = PN7_STA_MFID(status);
  662                 startvid = PN7_STA_SVID(status);
  663                 break;
  664         case PN8_TYPE:
  665                 maxfid = PN8_STA_MFID(status);
  666                 /*
  667                  * we should actually use a variable named 'maxvid' if K8,
  668                  * but why introducing a new variable for that?
  669                  */
  670                 startvid = PN8_STA_MVID(status);
  671                 break;
  672         default:
  673                 return (ENODEV);
  674         }
  675 
  676         if (bootverbose) {
  677                 device_printf(dev, "STATUS: 0x%jx\n", status);
  678                 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid);
  679                 device_printf(dev, "STATUS: %s: 0x%02x\n",
  680                     sc->pn_type == PN7_TYPE ? "startvid" : "maxvid",
  681                     startvid);
  682         }
  683 
  684         sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF);
  685         if (sig) {
  686                 struct pst_header *pst;
  687 
  688                 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig);
  689 
  690                 switch (psb->version) {
  691                 default:
  692                         return (ENODEV);
  693                 case 0x14:
  694                         /*
  695                          * We can't be picky about numpst since at least
  696                          * some systems have a value of 1 and some have 2.
  697                          * We trust that cpuid_is_k7() will be better at
  698                          * catching that we're on a K8 anyway.
  699                          */
  700                         if (sc->pn_type != PN8_TYPE)
  701                                 return (EINVAL);
  702                         sc->vst = psb->settlingtime;
  703                         sc->rvo = PN8_PSB_TO_RVO(psb->res1),
  704                         sc->irt = PN8_PSB_TO_IRT(psb->res1),
  705                         sc->mvs = PN8_PSB_TO_MVS(psb->res1),
  706                         sc->low = PN8_PSB_TO_BATT(psb->res1);
  707                         if (bootverbose) {
  708                                 device_printf(dev, "PSB: VST: %d\n",
  709                                     psb->settlingtime);
  710                                 device_printf(dev, "PSB: RVO %x IRT %d "
  711                                     "MVS %d BATT %d\n",
  712                                     sc->rvo,
  713                                     sc->irt,
  714                                     sc->mvs,
  715                                     sc->low);
  716                         }
  717                         break;
  718                 case 0x12:
  719                         if (sc->pn_type != PN7_TYPE)
  720                                 return (EINVAL);
  721                         sc->sgtc = psb->settlingtime * sc->fsb;
  722                         if (sc->sgtc < 100 * sc->fsb)
  723                                 sc->sgtc = 100 * sc->fsb;
  724                         break;
  725                 }
  726 
  727                 p = ((uint8_t *) psb) + sizeof(struct psb_header);
  728                 pst = (struct pst_header*) p;
  729 
  730                 maxpst = 200;
  731 
  732                 do {
  733                         struct pst_header *pst = (struct pst_header*) p;
  734 
  735                         if (cpuid == pst->cpuid &&
  736                             maxfid == pst->maxfid &&
  737                             startvid == pst->startvid) {
  738                                 sc->powernow_max_states = pst->numpstates;
  739                                 switch (sc->pn_type) {
  740                                 case PN7_TYPE:
  741                                         if (abs(sc->fsb - pst->fsb) > 5)
  742                                                 continue;
  743                                         break;
  744                                 case PN8_TYPE:
  745                                         break;
  746                                 }
  747                                 return (decode_pst(sc,
  748                                     p + sizeof(struct pst_header),
  749                                     sc->powernow_max_states));
  750                         }
  751 
  752                         p += sizeof(struct pst_header) + (2 * pst->numpstates);
  753                 } while (cpuid_is_k7(pst->cpuid) && maxpst--);
  754 
  755                 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid);
  756         }
  757 
  758         return (ENODEV);
  759 }
  760 
  761 /*
  762  * TODO: this should be done in sys/ARCH/ARCH/identcpu.c
  763  */
  764 static int
  765 cpu_is_powernow_capable(void)
  766 {
  767         u_int regs[4];
  768 
  769         if (strcmp(cpu_vendor, "AuthenticAMD") != 0 ||
  770             cpu_exthigh < 0x80000007)
  771                 return (FALSE);
  772 
  773         do_cpuid(0x80000007, regs);
  774         return (regs[3] & 0x6);
  775 }
  776 
  777 static int
  778 pn_decode_acpi(device_t dev, device_t perf_dev)
  779 {
  780         int i, j, n;
  781         uint64_t status;
  782         uint32_t ctrl;
  783         u_int cpuid;
  784         u_int regs[4];
  785         struct pn_softc *sc;
  786         struct powernow_state state;
  787         struct cf_setting sets[POWERNOW_MAX_STATES];
  788         int count = POWERNOW_MAX_STATES;
  789         int type;
  790         int rv;
  791 
  792         if (perf_dev == NULL)
  793                 return (ENXIO);
  794 
  795         rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count);
  796         if (rv)
  797                 return (ENXIO);
  798         rv = CPUFREQ_DRV_TYPE(perf_dev, &type);
  799         if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
  800                 return (ENXIO);
  801 
  802         sc = device_get_softc(dev);
  803 
  804         do_cpuid(0x80000001, regs);
  805         cpuid = regs[0];
  806         if ((cpuid & 0xfff) == 0x760)
  807                 sc->errata |= A0_ERRATA;
  808 
  809         ctrl = 0;
  810         sc->sgtc = 0;
  811         for (n = 0, i = 0; i < count; ++i) {
  812                 ctrl = sets[i].spec[PX_SPEC_CONTROL];
  813                 switch (sc->pn_type) {
  814                 case PN7_TYPE:
  815                         state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
  816                         state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
  817                         if ((sc->errata & A0_ERRATA) &&
  818                             (pn7_fid_to_mult[state.fid] % 10) == 5)
  819                                 continue;
  820                         state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
  821                         break;
  822                 case PN8_TYPE:
  823                         state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
  824                         state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
  825                         state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
  826                         break;
  827                 }
  828 
  829                 state.power = sets[i].power;
  830 
  831                 j = n;
  832                 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
  833                         memcpy(&sc->powernow_states[j],
  834                             &sc->powernow_states[j - 1],
  835                             sizeof(struct powernow_state));
  836                         --j;
  837                 }
  838                 memcpy(&sc->powernow_states[j], &state,
  839                     sizeof(struct powernow_state));
  840                 ++n;
  841         }
  842 
  843         sc->powernow_max_states = n;
  844         state = sc->powernow_states[0];
  845         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  846 
  847         switch (sc->pn_type) {
  848         case PN7_TYPE:
  849                 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl);
  850                 /*
  851                  * XXX Some bios forget the max frequency!
  852                  * This maybe indicates we have the wrong tables.  Therefore,
  853                  * don't implement a quirk, but fallback to BIOS legacy
  854                  * tables instead.
  855                  */
  856                 if (PN7_STA_MFID(status) != state.fid) {
  857                         device_printf(dev, "ACPI MAX frequency not found\n");
  858                         return (EINVAL);
  859                 }
  860                 break;
  861         case PN8_TYPE:
  862                 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl),
  863                 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl),
  864                 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl),
  865                 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl),
  866                 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl);
  867                 sc->low = 0; /* XXX */
  868 
  869                 /*
  870                  * powernow k8 supports only one low frequency.
  871                  */
  872                 if (sc->powernow_max_states >= 2 &&
  873                     (sc->powernow_states[sc->powernow_max_states - 2].fid < 8))
  874                         return (EINVAL);
  875                 break;
  876         }
  877 
  878         return (0);
  879 }
  880 
  881 static void
  882 pn_identify(driver_t *driver, device_t parent)
  883 {
  884         device_t child;
  885 
  886         if (cpu_is_powernow_capable() == 0)
  887                 return;
  888         switch (cpu_id & 0xf00) {
  889         case 0x600:
  890         case 0xf00:
  891                 break;
  892         default:
  893                 return;
  894         }
  895         if (device_find_child(parent, "powernow", -1) != NULL)
  896                 return;
  897         if ((child = BUS_ADD_CHILD(parent, 0, "powernow", -1)) == NULL)
  898                 device_printf(parent, "powernow: add child failed\n");
  899 }
  900 
  901 static int
  902 pn_probe(device_t dev)
  903 {
  904         struct pn_softc *sc;
  905         uint64_t status;
  906         uint64_t rate;
  907         struct pcpu *pc;
  908         u_int sfid, mfid, cfid;
  909 
  910         sc = device_get_softc(dev);
  911         sc->errata = 0;
  912         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  913 
  914         pc = cpu_get_pcpu(dev);
  915         if (pc == NULL)
  916                 return (ENODEV);
  917 
  918         cpu_est_clockrate(pc->pc_cpuid, &rate);
  919 
  920         switch (cpu_id & 0xf00) {
  921         case 0x600:
  922                 sfid = PN7_STA_SFID(status);
  923                 mfid = PN7_STA_MFID(status);
  924                 cfid = PN7_STA_CFID(status);
  925                 sc->pn_type = PN7_TYPE;
  926                 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];
  927 
  928                 /*
  929                  * If start FID is different to max FID, then it is a
  930                  * mobile processor.  If not, it is a low powered desktop
  931                  * processor.
  932                  */
  933                 if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) {
  934                         sc->vid_to_volts = pn7_mobile_vid_to_volts;
  935                         device_set_desc(dev, "PowerNow! K7");
  936                 } else {
  937                         sc->vid_to_volts = pn7_desktop_vid_to_volts;
  938                         device_set_desc(dev, "Cool`n'Quiet K7");
  939                 }
  940                 break;
  941 
  942         case 0xf00:
  943                 sfid = PN8_STA_SFID(status);
  944                 mfid = PN8_STA_MFID(status);
  945                 cfid = PN8_STA_CFID(status);
  946                 sc->pn_type = PN8_TYPE;
  947                 sc->vid_to_volts = pn8_vid_to_volts;
  948                 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
  949 
  950                 if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
  951                         device_set_desc(dev, "PowerNow! K8");
  952                 else
  953                         device_set_desc(dev, "Cool`n'Quiet K8");
  954                 break;
  955         default:
  956                 return (ENODEV);
  957         }
  958 
  959         return (0);
  960 }
  961 
  962 static int
  963 pn_attach(device_t dev)
  964 {
  965         int rv;
  966         device_t child;
  967 
  968         child = device_find_child(device_get_parent(dev), "acpi_perf", -1);
  969         if (child) {
  970                 rv = pn_decode_acpi(dev, child);
  971                 if (rv)
  972                         rv = pn_decode_pst(dev);
  973         } else
  974                 rv = pn_decode_pst(dev);
  975 
  976         if (rv != 0)
  977                 return (ENXIO);
  978         cpufreq_register(dev);
  979         return (0);
  980 }
  981 
  982 static int
  983 pn_detach(device_t dev)
  984 {
  985 
  986         cpufreq_unregister(dev);
  987         return (0);
  988 }

Cache object: 9897846cc90152057ee298c09ba77efe


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