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


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