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

Cache object: e873889d4320fd908d8d13dc9f599e50


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