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 #define WRITE_FIDVID(fid, vid, ctrl)    \
  150         wrmsr(MSR_AMDK7_FIDVID_CTL,     \
  151             (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
  152 
  153 #define COUNT_OFF_IRT(irt)      DELAY(10 * (1 << (irt)))
  154 #define COUNT_OFF_VST(vst)      DELAY(20 * (vst))
  155 
  156 #define FID_TO_VCO_FID(fid)     \
  157         (((fid) < 8) ? (8 + ((fid) << 1)) : (fid))
  158 
  159 /*
  160  * Divide each value by 10 to get the processor multiplier.
  161  * Some of those tables are the same as the Linux powernow-k7
  162  * implementation by Dave Jones.
  163  */
  164 static int pn7_fid_to_mult[32] = {
  165         110, 115, 120, 125, 50, 55, 60, 65,
  166         70, 75, 80, 85, 90, 95, 100, 105,
  167         30, 190, 40, 200, 130, 135, 140, 210,
  168         150, 225, 160, 165, 170, 180, 0, 0,
  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         {0, 0}
  264 };
  265 
  266 static driver_t pn_driver = {
  267         "powernow",
  268         pn_methods,
  269         sizeof(struct pn_softc),
  270 };
  271 
  272 DRIVER_MODULE(powernow, cpu, pn_driver, 0, 0);
  273 
  274 static int
  275 pn7_setfidvid(struct pn_softc *sc, int fid, int vid)
  276 {
  277         int cfid, cvid;
  278         uint64_t status, ctl;
  279 
  280         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  281         cfid = PN7_STA_CFID(status);
  282         cvid = PN7_STA_CVID(status);
  283 
  284         /* We're already at the requested level. */
  285         if (fid == cfid && vid == cvid)
  286                 return (0);
  287 
  288         ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
  289 
  290         ctl |= PN7_CTR_FID(fid);
  291         ctl |= PN7_CTR_VID(vid);
  292         ctl |= PN7_CTR_SGTC(sc->sgtc);
  293 
  294         if (sc->errata & A0_ERRATA)
  295                 disable_intr();
  296 
  297         if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) {
  298                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  299                 if (vid != cvid)
  300                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  301         } else {
  302                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  303                 if (fid != cfid)
  304                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  305         }
  306 
  307         if (sc->errata & A0_ERRATA)
  308                 enable_intr();
  309 
  310         return (0);
  311 }
  312 
  313 static int
  314 pn8_read_pending_wait(uint64_t *status)
  315 {
  316         int i = 10000;
  317 
  318         do
  319                 *status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  320         while (PN8_STA_PENDING(*status) && --i);
  321 
  322         return (i == 0 ? ENXIO : 0);
  323 }
  324 
  325 static int
  326 pn8_write_fidvid(u_int fid, u_int vid, uint64_t ctrl, uint64_t *status)
  327 {
  328         int i = 100;
  329 
  330         do
  331                 WRITE_FIDVID(fid, vid, ctrl);
  332         while (pn8_read_pending_wait(status) && --i);
  333 
  334         return (i == 0 ? ENXIO : 0);
  335 }
  336 
  337 static int
  338 pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
  339 {
  340         uint64_t status;
  341         int cfid, cvid;
  342         int rvo;
  343         int rv;
  344         u_int val;
  345 
  346         rv = pn8_read_pending_wait(&status);
  347         if (rv)
  348                 return (rv);
  349 
  350         cfid = PN8_STA_CFID(status);
  351         cvid = PN8_STA_CVID(status);
  352 
  353         if (fid == cfid && vid == cvid)
  354                 return (0);
  355 
  356         /*
  357          * Phase 1: Raise core voltage to requested VID if frequency is
  358          * going up.
  359          */
  360         while (cvid > vid) {
  361                 val = cvid - (1 << sc->mvs);
  362                 rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
  363                 if (rv) {
  364                         sc->errata |= PENDING_STUCK;
  365                         return (rv);
  366                 }
  367                 cvid = PN8_STA_CVID(status);
  368                 COUNT_OFF_VST(sc->vst);
  369         }
  370 
  371         /* ... then raise to voltage + RVO (if required) */
  372         for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) {
  373                 /* XXX It's not clear from spec if we have to do that
  374                  * in 0.25 step or in MVS.  Therefore do it as it's done
  375                  * under Linux */
  376                 rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
  377                 if (rv) {
  378                         sc->errata |= PENDING_STUCK;
  379                         return (rv);
  380                 }
  381                 cvid = PN8_STA_CVID(status);
  382                 COUNT_OFF_VST(sc->vst);
  383         }
  384 
  385         /* Phase 2: change to requested core frequency */
  386         if (cfid != fid) {
  387                 u_int vco_fid, vco_cfid, fid_delta;
  388 
  389                 vco_fid = FID_TO_VCO_FID(fid);
  390                 vco_cfid = FID_TO_VCO_FID(cfid);
  391 
  392                 while (abs(vco_fid - vco_cfid) > 2) {
  393                         fid_delta = (vco_cfid & 1) ? 1 : 2;
  394                         if (fid > cfid) {
  395                                 if (cfid > 7)
  396                                         val = cfid + fid_delta;
  397                                 else
  398                                         val = FID_TO_VCO_FID(cfid) + fid_delta;
  399                         } else
  400                                 val = cfid - fid_delta;
  401                         rv = pn8_write_fidvid(val, cvid,
  402                             sc->pll * (uint64_t) sc->fsb,
  403                             &status);
  404                         if (rv) {
  405                                 sc->errata |= PENDING_STUCK;
  406                                 return (rv);
  407                         }
  408                         cfid = PN8_STA_CFID(status);
  409                         COUNT_OFF_IRT(sc->irt);
  410 
  411                         vco_cfid = FID_TO_VCO_FID(cfid);
  412                 }
  413 
  414                 rv = pn8_write_fidvid(fid, cvid,
  415                     sc->pll * (uint64_t) sc->fsb,
  416                     &status);
  417                 if (rv) {
  418                         sc->errata |= PENDING_STUCK;
  419                         return (rv);
  420                 }
  421                 cfid = PN8_STA_CFID(status);
  422                 COUNT_OFF_IRT(sc->irt);
  423         }
  424 
  425         /* Phase 3: change to requested voltage */
  426         if (cvid != vid) {
  427                 rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
  428                 cvid = PN8_STA_CVID(status);
  429                 COUNT_OFF_VST(sc->vst);
  430         }
  431 
  432         /* Check if transition failed. */
  433         if (cfid != fid || cvid != vid)
  434                 rv = ENXIO;
  435 
  436         return (rv);
  437 }
  438 
  439 static int
  440 pn_set(device_t dev, const struct cf_setting *cf)
  441 {
  442         struct pn_softc *sc;
  443         int fid, vid;
  444         int i;
  445         int rv;
  446 
  447         if (cf == NULL)
  448                 return (EINVAL);
  449         sc = device_get_softc(dev);
  450 
  451         if (sc->errata & PENDING_STUCK)
  452                 return (ENXIO);
  453 
  454         for (i = 0; i < sc->powernow_max_states; ++i)
  455                 if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
  456                         break;
  457 
  458         fid = sc->powernow_states[i].fid;
  459         vid = sc->powernow_states[i].vid;
  460 
  461         rv = ENODEV;
  462 
  463         switch (sc->pn_type) {
  464         case PN7_TYPE:
  465                 rv = pn7_setfidvid(sc, fid, vid);
  466                 break;
  467         case PN8_TYPE:
  468                 rv = pn8_setfidvid(sc, fid, vid);
  469                 break;
  470         }
  471 
  472         return (rv);
  473 }
  474 
  475 static int
  476 pn_get(device_t dev, struct cf_setting *cf)
  477 {
  478         struct pn_softc *sc;
  479         u_int cfid = 0, cvid = 0;
  480         int i;
  481         uint64_t status;
  482 
  483         if (cf == NULL)
  484                 return (EINVAL);
  485         sc = device_get_softc(dev);
  486         if (sc->errata & PENDING_STUCK)
  487                 return (ENXIO);
  488 
  489         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  490 
  491         switch (sc->pn_type) {
  492         case PN7_TYPE:
  493                 cfid = PN7_STA_CFID(status);
  494                 cvid = PN7_STA_CVID(status);
  495                 break;
  496         case PN8_TYPE:
  497                 cfid = PN8_STA_CFID(status);
  498                 cvid = PN8_STA_CVID(status);
  499                 break;
  500         }
  501         for (i = 0; i < sc->powernow_max_states; ++i)
  502                 if (cfid == sc->powernow_states[i].fid &&
  503                     cvid == sc->powernow_states[i].vid)
  504                         break;
  505 
  506         if (i < sc->powernow_max_states) {
  507                 cf->freq = sc->powernow_states[i].freq / 1000;
  508                 cf->power = sc->powernow_states[i].power;
  509                 cf->lat = 200;
  510                 cf->volts = sc->vid_to_volts[cvid];
  511                 cf->dev = dev;
  512         } else {
  513                 memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
  514                 cf->dev = NULL;
  515         }
  516 
  517         return (0);
  518 }
  519 
  520 static int
  521 pn_settings(device_t dev, struct cf_setting *sets, int *count)
  522 {
  523         struct pn_softc *sc;
  524         int i;
  525 
  526         if (sets == NULL|| count == NULL)
  527                 return (EINVAL);
  528         sc = device_get_softc(dev);
  529         if (*count < sc->powernow_max_states)
  530                 return (E2BIG);
  531         for (i = 0; i < sc->powernow_max_states; ++i) {
  532                 sets[i].freq = sc->powernow_states[i].freq / 1000;
  533                 sets[i].power = sc->powernow_states[i].power;
  534                 sets[i].lat = 200;
  535                 sets[i].volts = sc->vid_to_volts[sc->powernow_states[i].vid];
  536                 sets[i].dev = dev;
  537         }
  538         *count = sc->powernow_max_states;
  539 
  540         return (0);
  541 }
  542 
  543 static int
  544 pn_type(device_t dev, int *type)
  545 {
  546         if (type == NULL)
  547                 return (EINVAL);
  548 
  549         *type = CPUFREQ_TYPE_ABSOLUTE;
  550 
  551         return (0);
  552 }
  553 
  554 /*
  555  * Given a set of pair of fid/vid, and number of performance states,
  556  * compute powernow_states via an insertion sort.
  557  */
  558 static int
  559 decode_pst(struct pn_softc *sc, uint8_t *p, int npstates)
  560 {
  561         int i, j, n;
  562         struct powernow_state state;
  563 
  564         for (i = 0; i < POWERNOW_MAX_STATES; ++i)
  565                 sc->powernow_states[i].freq = CPUFREQ_VAL_UNKNOWN;
  566 
  567         for (n = 0, i = 0; i < npstates; ++i) {
  568                 state.fid = *p++;
  569                 state.vid = *p++;
  570                 state.power = CPUFREQ_VAL_UNKNOWN;
  571 
  572                 switch (sc->pn_type) {
  573                 case PN7_TYPE:
  574                         state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
  575                         if ((sc->errata & A0_ERRATA) &&
  576                             (pn7_fid_to_mult[state.fid] % 10) == 5)
  577                                 continue;
  578                         break;
  579                 case PN8_TYPE:
  580                         state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
  581                         break;
  582                 }
  583 
  584                 j = n;
  585                 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
  586                         memcpy(&sc->powernow_states[j],
  587                             &sc->powernow_states[j - 1],
  588                             sizeof(struct powernow_state));
  589                         --j;
  590                 }
  591                 memcpy(&sc->powernow_states[j], &state,
  592                     sizeof(struct powernow_state));
  593                 ++n;
  594         }
  595 
  596         /*
  597          * Fix powernow_max_states, if errata a0 give us less states
  598          * than expected.
  599          */
  600         sc->powernow_max_states = n;
  601 
  602         if (bootverbose)
  603                 for (i = 0; i < sc->powernow_max_states; ++i) {
  604                         int fid = sc->powernow_states[i].fid;
  605                         int vid = sc->powernow_states[i].vid;
  606 
  607                         printf("powernow: %2i %8dkHz FID %02x VID %02x\n",
  608                             i,
  609                             sc->powernow_states[i].freq,
  610                             fid,
  611                             vid);
  612                 }
  613 
  614         return (0);
  615 }
  616 
  617 static int
  618 cpuid_is_k7(u_int cpuid)
  619 {
  620 
  621         switch (cpuid) {
  622         case 0x760:
  623         case 0x761:
  624         case 0x762:
  625         case 0x770:
  626         case 0x771:
  627         case 0x780:
  628         case 0x781:
  629         case 0x7a0:
  630                 return (TRUE);
  631         }
  632         return (FALSE);
  633 }
  634 
  635 static int
  636 pn_decode_pst(device_t dev)
  637 {
  638         int maxpst;
  639         struct pn_softc *sc;
  640         u_int cpuid, maxfid, startvid;
  641         u_long sig;
  642         struct psb_header *psb;
  643         uint8_t *p;
  644         u_int regs[4];
  645         uint64_t status;
  646 
  647         sc = device_get_softc(dev);
  648 
  649         do_cpuid(0x80000001, regs);
  650         cpuid = regs[0];
  651 
  652         if ((cpuid & 0xfff) == 0x760)
  653                 sc->errata |= A0_ERRATA;
  654 
  655         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  656 
  657         switch (sc->pn_type) {
  658         case PN7_TYPE:
  659                 maxfid = PN7_STA_MFID(status);
  660                 startvid = PN7_STA_SVID(status);
  661                 break;
  662         case PN8_TYPE:
  663                 maxfid = PN8_STA_MFID(status);
  664                 /*
  665                  * we should actually use a variable named 'maxvid' if K8,
  666                  * but why introducing a new variable for that?
  667                  */
  668                 startvid = PN8_STA_MVID(status);
  669                 break;
  670         default:
  671                 return (ENODEV);
  672         }
  673 
  674         if (bootverbose) {
  675                 device_printf(dev, "STATUS: 0x%jx\n", status);
  676                 device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid);
  677                 device_printf(dev, "STATUS: %s: 0x%02x\n",
  678                     sc->pn_type == PN7_TYPE ? "startvid" : "maxvid",
  679                     startvid);
  680         }
  681 
  682         sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF);
  683         if (sig) {
  684                 struct pst_header *pst;
  685 
  686                 psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig);
  687 
  688                 switch (psb->version) {
  689                 default:
  690                         return (ENODEV);
  691                 case 0x14:
  692                         /*
  693                          * We can't be picky about numpst since at least
  694                          * some systems have a value of 1 and some have 2.
  695                          * We trust that cpuid_is_k7() will be better at
  696                          * catching that we're on a K8 anyway.
  697                          */
  698                         if (sc->pn_type != PN8_TYPE)
  699                                 return (EINVAL);
  700                         sc->vst = psb->settlingtime;
  701                         sc->rvo = PN8_PSB_TO_RVO(psb->res1);
  702                         sc->irt = PN8_PSB_TO_IRT(psb->res1);
  703                         sc->mvs = PN8_PSB_TO_MVS(psb->res1);
  704                         sc->low = PN8_PSB_TO_BATT(psb->res1);
  705                         if (bootverbose) {
  706                                 device_printf(dev, "PSB: VST: %d\n",
  707                                     psb->settlingtime);
  708                                 device_printf(dev, "PSB: RVO %x IRT %d "
  709                                     "MVS %d BATT %d\n",
  710                                     sc->rvo,
  711                                     sc->irt,
  712                                     sc->mvs,
  713                                     sc->low);
  714                         }
  715                         break;
  716                 case 0x12:
  717                         if (sc->pn_type != PN7_TYPE)
  718                                 return (EINVAL);
  719                         sc->sgtc = psb->settlingtime * sc->fsb;
  720                         if (sc->sgtc < 100 * sc->fsb)
  721                                 sc->sgtc = 100 * sc->fsb;
  722                         break;
  723                 }
  724 
  725                 p = ((uint8_t *) psb) + sizeof(struct psb_header);
  726                 pst = (struct pst_header*) p;
  727 
  728                 maxpst = 200;
  729 
  730                 do {
  731                         struct pst_header *pst = (struct pst_header*) p;
  732 
  733                         if (cpuid == pst->cpuid &&
  734                             maxfid == pst->maxfid &&
  735                             startvid == pst->startvid) {
  736                                 sc->powernow_max_states = pst->numpstates;
  737                                 switch (sc->pn_type) {
  738                                 case PN7_TYPE:
  739                                         if (abs(sc->fsb - pst->fsb) > 5)
  740                                                 continue;
  741                                         break;
  742                                 case PN8_TYPE:
  743                                         break;
  744                                 }
  745                                 return (decode_pst(sc,
  746                                     p + sizeof(struct pst_header),
  747                                     sc->powernow_max_states));
  748                         }
  749 
  750                         p += sizeof(struct pst_header) + (2 * pst->numpstates);
  751                 } while (cpuid_is_k7(pst->cpuid) && maxpst--);
  752 
  753                 device_printf(dev, "no match for extended cpuid %.3x\n", cpuid);
  754         }
  755 
  756         return (ENODEV);
  757 }
  758 
  759 static int
  760 pn_decode_acpi(device_t dev, device_t perf_dev)
  761 {
  762         int i, j, n;
  763         uint64_t status;
  764         uint32_t ctrl;
  765         u_int cpuid;
  766         u_int regs[4];
  767         struct pn_softc *sc;
  768         struct powernow_state state;
  769         struct cf_setting sets[POWERNOW_MAX_STATES];
  770         int count = POWERNOW_MAX_STATES;
  771         int type;
  772         int rv;
  773 
  774         if (perf_dev == NULL)
  775                 return (ENXIO);
  776 
  777         rv = CPUFREQ_DRV_SETTINGS(perf_dev, sets, &count);
  778         if (rv)
  779                 return (ENXIO);
  780         rv = CPUFREQ_DRV_TYPE(perf_dev, &type);
  781         if (rv || (type & CPUFREQ_FLAG_INFO_ONLY) == 0)
  782                 return (ENXIO);
  783 
  784         sc = device_get_softc(dev);
  785 
  786         do_cpuid(0x80000001, regs);
  787         cpuid = regs[0];
  788         if ((cpuid & 0xfff) == 0x760)
  789                 sc->errata |= A0_ERRATA;
  790 
  791         ctrl = 0;
  792         sc->sgtc = 0;
  793         for (n = 0, i = 0; i < count; ++i) {
  794                 ctrl = sets[i].spec[PX_SPEC_CONTROL];
  795                 switch (sc->pn_type) {
  796                 case PN7_TYPE:
  797                         state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
  798                         state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
  799                         if ((sc->errata & A0_ERRATA) &&
  800                             (pn7_fid_to_mult[state.fid] % 10) == 5)
  801                                 continue;
  802                         break;
  803                 case PN8_TYPE:
  804                         state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
  805                         state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
  806                         break;
  807                 }
  808                 state.freq = sets[i].freq * 1000;
  809                 state.power = sets[i].power;
  810 
  811                 j = n;
  812                 while (j > 0 && sc->powernow_states[j - 1].freq < state.freq) {
  813                         memcpy(&sc->powernow_states[j],
  814                             &sc->powernow_states[j - 1],
  815                             sizeof(struct powernow_state));
  816                         --j;
  817                 }
  818                 memcpy(&sc->powernow_states[j], &state,
  819                     sizeof(struct powernow_state));
  820                 ++n;
  821         }
  822 
  823         sc->powernow_max_states = n;
  824         state = sc->powernow_states[0];
  825         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  826 
  827         switch (sc->pn_type) {
  828         case PN7_TYPE:
  829                 sc->sgtc = ACPI_PN7_CTRL_TO_SGTC(ctrl);
  830                 /*
  831                  * XXX Some bios forget the max frequency!
  832                  * This maybe indicates we have the wrong tables.  Therefore,
  833                  * don't implement a quirk, but fallback to BIOS legacy
  834                  * tables instead.
  835                  */
  836                 if (PN7_STA_MFID(status) != state.fid) {
  837                         device_printf(dev, "ACPI MAX frequency not found\n");
  838                         return (EINVAL);
  839                 }
  840                 sc->fsb = state.freq / 100 / pn7_fid_to_mult[state.fid];
  841                 break;
  842         case PN8_TYPE:
  843                 sc->vst = ACPI_PN8_CTRL_TO_VST(ctrl),
  844                 sc->mvs = ACPI_PN8_CTRL_TO_MVS(ctrl),
  845                 sc->pll = ACPI_PN8_CTRL_TO_PLL(ctrl),
  846                 sc->rvo = ACPI_PN8_CTRL_TO_RVO(ctrl),
  847                 sc->irt = ACPI_PN8_CTRL_TO_IRT(ctrl);
  848                 sc->low = 0; /* XXX */
  849 
  850                 /*
  851                  * powernow k8 supports only one low frequency.
  852                  */
  853                 if (sc->powernow_max_states >= 2 &&
  854                     (sc->powernow_states[sc->powernow_max_states - 2].fid < 8))
  855                         return (EINVAL);
  856                 sc->fsb = state.freq / 100 / pn8_fid_to_mult[state.fid];
  857                 break;
  858         }
  859 
  860         return (0);
  861 }
  862 
  863 static void
  864 pn_identify(driver_t *driver, device_t parent)
  865 {
  866 
  867         if ((amd_pminfo & AMDPM_FID) == 0 || (amd_pminfo & AMDPM_VID) == 0)
  868                 return;
  869         switch (cpu_id & 0xf00) {
  870         case 0x600:
  871         case 0xf00:
  872                 break;
  873         default:
  874                 return;
  875         }
  876         if (device_find_child(parent, "powernow", -1) != NULL)
  877                 return;
  878         if (BUS_ADD_CHILD(parent, 10, "powernow", device_get_unit(parent))
  879             == NULL)
  880                 device_printf(parent, "powernow: add child failed\n");
  881 }
  882 
  883 static int
  884 pn_probe(device_t dev)
  885 {
  886         struct pn_softc *sc;
  887         uint64_t status;
  888         uint64_t rate;
  889         struct pcpu *pc;
  890         u_int sfid, mfid, cfid;
  891 
  892         sc = device_get_softc(dev);
  893         sc->errata = 0;
  894         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  895 
  896         pc = cpu_get_pcpu(dev);
  897         if (pc == NULL)
  898                 return (ENODEV);
  899 
  900         cpu_est_clockrate(pc->pc_cpuid, &rate);
  901 
  902         switch (cpu_id & 0xf00) {
  903         case 0x600:
  904                 sfid = PN7_STA_SFID(status);
  905                 mfid = PN7_STA_MFID(status);
  906                 cfid = PN7_STA_CFID(status);
  907                 sc->pn_type = PN7_TYPE;
  908                 sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];
  909 
  910                 /*
  911                  * If start FID is different to max FID, then it is a
  912                  * mobile processor.  If not, it is a low powered desktop
  913                  * processor.
  914                  */
  915                 if (sfid != mfid) {
  916                         sc->vid_to_volts = pn7_mobile_vid_to_volts;
  917                         device_set_desc(dev, "PowerNow! K7");
  918                 } else {
  919                         sc->vid_to_volts = pn7_desktop_vid_to_volts;
  920                         device_set_desc(dev, "Cool`n'Quiet K7");
  921                 }
  922                 break;
  923 
  924         case 0xf00:
  925                 sfid = PN8_STA_SFID(status);
  926                 mfid = PN8_STA_MFID(status);
  927                 cfid = PN8_STA_CFID(status);
  928                 sc->pn_type = PN8_TYPE;
  929                 sc->vid_to_volts = pn8_vid_to_volts;
  930                 sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
  931 
  932                 if (sfid != mfid)
  933                         device_set_desc(dev, "PowerNow! K8");
  934                 else
  935                         device_set_desc(dev, "Cool`n'Quiet K8");
  936                 break;
  937         default:
  938                 return (ENODEV);
  939         }
  940 
  941         return (0);
  942 }
  943 
  944 static int
  945 pn_attach(device_t dev)
  946 {
  947         int rv;
  948         device_t child;
  949 
  950         child = device_find_child(device_get_parent(dev), "acpi_perf", -1);
  951         if (child) {
  952                 rv = pn_decode_acpi(dev, child);
  953                 if (rv)
  954                         rv = pn_decode_pst(dev);
  955         } else
  956                 rv = pn_decode_pst(dev);
  957 
  958         if (rv != 0)
  959                 return (ENXIO);
  960         cpufreq_register(dev);
  961         return (0);
  962 }
  963 
  964 static int
  965 pn_detach(device_t dev)
  966 {
  967 
  968         return (cpufreq_unregister(dev));
  969 }

Cache object: 16f572218dc99113264db6bb07450341


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