This source file includes following definitions.
- k7_powernow_setperf
 
- k7pnow_decode_pst
 
- k7pnow_states
 
- k7pnow_acpi_states
 
- k7pnow_acpi_pss_changed
 
- k7pnow_acpi_init
 
- k7_powernow_init
 
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
   10 
   11 
   12 
   13 
   14 
   15 
   16 
   17 
   18 
   19 
   20 
   21 
   22 
   23 
   24 
   25 
   26 
   27 
   28 
   29 
   30 
   31 #include <sys/types.h>
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/malloc.h>
   35 #include <sys/sysctl.h>
   36 
   37 #include <machine/cpu.h>
   38 #include <machine/cpufunc.h>
   39 #include <machine/bus.h>
   40 
   41 #include <dev/isa/isareg.h>
   42 #include <i386/isa/isa_machdep.h>
   43 
   44 #include "acpicpu.h"
   45 
   46 #if NACPICPU > 0
   47 #include <dev/acpi/acpidev.h>
   48 #include <dev/acpi/acpivar.h>
   49 #endif
   50 
   51 #define BIOS_START                      0xe0000
   52 #define BIOS_LEN                        0x20000
   53 #define BIOS_STEP                       16
   54 
   55 
   56 
   57 
   58 #define MSR_AMDK7_FIDVID_CTL            0xc0010041
   59 #define MSR_AMDK7_FIDVID_STATUS         0xc0010042
   60 #define AMD_PN_FID_VID                  0x06
   61 #define AMD_ERRATA_A0_CPUSIG            0x660
   62 
   63 #define PN7_FLAG_ERRATA_A0              0x01
   64 #define PN7_FLAG_DESKTOP_VRM            0x02
   65 
   66 
   67 #define PN7_PSB_VERSION                 0x12
   68 #define PN7_CTR_FID(x)                  ((x) & 0x1f)
   69 #define PN7_CTR_VID(x)                  (((x) & 0x1f) << 8)
   70 #define PN7_CTR_FIDC                    0x00010000
   71 #define PN7_CTR_VIDC                    0x00020000
   72 #define PN7_CTR_FIDCHRATIO              0x00100000
   73 #define PN7_CTR_SGTC(x)                 (((uint64_t)(x) & 0x000fffff) << 32)
   74 
   75 #define PN7_STA_CFID(x)                 ((x) & 0x1f)
   76 #define PN7_STA_SFID(x)                 (((x) >> 8) & 0x1f)
   77 #define PN7_STA_MFID(x)                 (((x) >> 16) & 0x1f)
   78 #define PN7_STA_CVID(x)                 (((x) >> 32) & 0x1f)
   79 #define PN7_STA_SVID(x)                 (((x) >> 40) & 0x1f)
   80 #define PN7_STA_MVID(x)                 (((x) >> 48) & 0x1f)
   81 
   82 
   83 
   84 
   85 #define PN7_ACPI_CTRL_TO_FID(x)         ((x) & 0x1f)
   86 #define PN7_ACPI_CTRL_TO_VID(x)         (((x) >> 5) & 0x1f)
   87 #define PN7_ACPI_CTRL_TO_SGTC(x)        (((x) >> 10) & 0xffff)
   88 
   89 #define WRITE_FIDVID(fid, vid, ctrl)    \
   90         wrmsr(MSR_AMDK7_FIDVID_CTL,     \
   91             (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
   92 
   93 
   94 
   95 
   96 
   97 static int k7pnow_fid_to_mult[32] = {
   98         110, 115, 120, 125, 50, 55, 60, 65,
   99         70, 75, 80, 85, 90, 95, 100, 105,
  100         30, 190, 40, 200, 130, 135, 140, 210,
  101         150, 225, 160, 165, 170, 180, -1, -1
  102 };
  103 
  104 #define POWERNOW_MAX_STATES             16
  105 
  106 struct k7pnow_state {
  107         int freq;
  108         int fid;
  109         int vid;
  110 };
  111 
  112 struct k7pnow_cpu_state {
  113         unsigned int fsb;
  114         unsigned int sgtc;
  115         struct k7pnow_state state_table[POWERNOW_MAX_STATES];
  116         unsigned int n_states;
  117         int flags;
  118 };
  119 
  120 struct psb_s {
  121         char signature[10];     
  122         uint8_t version;
  123         uint8_t flags;
  124         uint16_t ttime;         
  125         uint8_t reserved;
  126         uint8_t n_pst;
  127 };
  128 
  129 struct pst_s {
  130         uint32_t signature;
  131         uint8_t fsb;            
  132         uint8_t fid;            
  133         uint8_t vid;            
  134         uint8_t n_states;       
  135 };
  136 
  137 struct k7pnow_cpu_state *k7pnow_current_state;
  138 extern int setperf_prio;
  139 
  140 int k7pnow_decode_pst(struct k7pnow_cpu_state *, uint8_t *, int);
  141 int k7pnow_states(struct k7pnow_cpu_state *, uint32_t, unsigned int,
  142     unsigned int);
  143 
  144 #if NACPICPU > 0
  145 int k7pnow_acpi_init(struct k7pnow_cpu_state * cstate, uint64_t status);
  146 int k7pnow_acpi_states(struct k7pnow_cpu_state * cstate,
  147     struct acpicpu_pss *pss, int nstates, uint64_t status);
  148 void k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss);
  149 #endif
  150 
  151 void
  152 k7_powernow_setperf(int level)
  153 {
  154         unsigned int i;
  155         int cvid, cfid, vid = 0, fid = 0;
  156         uint64_t status, ctl;
  157         struct k7pnow_cpu_state * cstate;
  158 
  159         cstate = k7pnow_current_state;
  160 
  161         i = ((level * cstate->n_states) + 1) / 101;
  162         if (i >= cstate->n_states)
  163                 i = cstate->n_states - 1;
  164         fid = cstate->state_table[i].fid;
  165         vid = cstate->state_table[i].vid;
  166 
  167         if (fid == 0 || vid == 0)
  168                 return;
  169 
  170         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  171         cfid = PN7_STA_CFID(status);
  172         cvid = PN7_STA_CVID(status);
  173 
  174         
  175 
  176 
  177         if (fid == cfid && vid == cvid)
  178                 return;
  179 
  180         ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;
  181 
  182         ctl |= PN7_CTR_FID(fid);
  183         ctl |= PN7_CTR_VID(vid);
  184         ctl |= PN7_CTR_SGTC(cstate->sgtc);
  185 
  186         if (cstate->flags & PN7_FLAG_ERRATA_A0)
  187                 disable_intr();
  188 
  189         if (k7pnow_fid_to_mult[fid] < k7pnow_fid_to_mult[cfid]) {
  190                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  191                 if (vid != cvid)
  192                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  193         } else {
  194                 wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
  195                 if (fid != cfid)
  196                         wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
  197         }
  198 
  199         if (cstate->flags & PN7_FLAG_ERRATA_A0)
  200                 enable_intr();
  201 
  202         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  203         cfid = PN7_STA_CFID(status);
  204         cvid = PN7_STA_CVID(status);
  205         if (cfid == fid || cvid == vid)
  206                 cpuspeed = cstate->state_table[i].freq;
  207 }
  208 
  209 
  210 
  211 
  212 
  213 int
  214 k7pnow_decode_pst(struct k7pnow_cpu_state * cstate, uint8_t *p, int npst)
  215 {
  216         int i, j, n;
  217         struct k7pnow_state state;
  218 
  219         for (n = 0, i = 0; i < npst; ++i) {
  220                 state.fid = *p++;
  221                 state.vid = *p++;
  222                 state.freq = k7pnow_fid_to_mult[state.fid]/10 * cstate->fsb;
  223                 if ((cstate->flags & PN7_FLAG_ERRATA_A0) &&
  224                     (k7pnow_fid_to_mult[state.fid] % 10) == 5)
  225                         continue;
  226 
  227                 j = n;
  228                 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
  229                         memcpy(&cstate->state_table[j],
  230                             &cstate->state_table[j - 1],
  231                             sizeof(struct k7pnow_state));
  232                         --j;
  233                 }
  234                 memcpy(&cstate->state_table[j], &state,
  235                     sizeof(struct k7pnow_state));
  236                 ++n;
  237         }
  238         
  239 
  240 
  241 
  242         cstate->n_states = n;
  243         return 1;
  244 }
  245 
  246 int
  247 k7pnow_states(struct k7pnow_cpu_state *cstate, uint32_t cpusig,
  248     unsigned int fid, unsigned int vid)
  249 {
  250         int maxpst;
  251         struct psb_s *psb;
  252         struct pst_s *pst;
  253         uint8_t *p;
  254 
  255         
  256 
  257 
  258 
  259         for (p = (u_int8_t *)ISA_HOLE_VADDR(BIOS_START);
  260             p < (u_int8_t *)ISA_HOLE_VADDR(BIOS_START + BIOS_LEN); p+=
  261             BIOS_STEP) {
  262                 if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
  263                         psb = (struct psb_s *)p;
  264                         if (psb->version != PN7_PSB_VERSION)
  265                                 return 0;
  266 
  267                         cstate->sgtc = psb->ttime * cstate->fsb;
  268                         if (cstate->sgtc < 100 * cstate->fsb)
  269                                 cstate->sgtc = 100 * cstate->fsb;
  270                         if (psb->flags & 1)
  271                                 cstate->flags |= PN7_FLAG_DESKTOP_VRM;
  272                         p += sizeof(struct psb_s);
  273 
  274                         for (maxpst = 0; maxpst < psb->n_pst; maxpst++) {
  275                                 pst = (struct pst_s*) p;
  276 
  277                                 if (cpusig == pst->signature && fid == pst->fid
  278                                     && vid == pst->vid) {
  279 
  280                                         if (abs(cstate->fsb - pst->fsb) > 5)
  281                                                 continue;
  282                                         cstate->n_states = pst->n_states;
  283                                         return (k7pnow_decode_pst(cstate,
  284                                             p + sizeof(struct pst_s),
  285                                             cstate->n_states));
  286                                 }
  287                                 p += sizeof(struct pst_s) +
  288                                     (2 * pst->n_states);
  289                         }
  290                 }
  291         }
  292 
  293         return 0;
  294 }
  295 
  296 #if NACPICPU > 0
  297 
  298 int
  299 k7pnow_acpi_states(struct k7pnow_cpu_state * cstate, struct acpicpu_pss *pss,
  300     int nstates, uint64_t status)
  301 {
  302         struct k7pnow_state state;
  303         int j, k, n;
  304         uint32_t ctrl;
  305 
  306         k = -1;
  307         for (n = 0; n < cstate->n_states; n++) {
  308                 if (status == pss[n].pss_status)
  309                         k = n;
  310                 ctrl = pss[n].pss_ctrl;
  311                 state.fid = PN7_ACPI_CTRL_TO_FID(ctrl);
  312                 state.vid = PN7_ACPI_CTRL_TO_VID(ctrl);
  313 
  314                 state.freq = pss[n].pss_core_freq;
  315                 j = n;
  316                 while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
  317                         memcpy(&cstate->state_table[j],
  318                             &cstate->state_table[j - 1],
  319                         sizeof(struct k7pnow_state));
  320                         --j;
  321                 }
  322                 memcpy(&cstate->state_table[j], &state,
  323                     sizeof(struct k7pnow_state));
  324         }
  325         return k;
  326 }
  327 
  328 void
  329 k7pnow_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
  330 {
  331         int curs;
  332         struct k7pnow_cpu_state *cstate;
  333         uint32_t ctrl;
  334         uint64_t status;
  335 
  336         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  337         cstate = k7pnow_current_state;
  338 
  339         curs = k7pnow_acpi_states(cstate, pss, npss, status);
  340         ctrl = pss[curs].pss_ctrl;
  341         cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
  342         cstate->n_states = npss;
  343 }
  344 
  345 int
  346 k7pnow_acpi_init(struct k7pnow_cpu_state *cstate, uint64_t status)
  347 {
  348         int curs;
  349         uint32_t ctrl;
  350         struct acpicpu_pss *pss;
  351         int mfid;
  352 
  353         cstate->n_states = acpicpu_fetch_pss(&pss);
  354         if (cstate->n_states == 0)
  355                 return 0;
  356 
  357         
  358 
  359 
  360 
  361 
  362         mfid = PN7_STA_MFID(status);
  363         if (mfid != cstate->state_table[cstate->n_states - 1].fid) {
  364                 return 0;
  365         }
  366         curs = k7pnow_acpi_states(cstate, pss, cstate->n_states, status);
  367 
  368         acpicpu_set_notify(k7pnow_acpi_pss_changed);
  369         ctrl = pss[curs].pss_ctrl;
  370         cstate->sgtc = PN7_ACPI_CTRL_TO_SGTC(ctrl);
  371 
  372         return 1;
  373 }
  374 
  375 #endif 
  376 
  377 void
  378 k7_powernow_init(void)
  379 {
  380         u_int regs[4];
  381         uint64_t status;
  382         u_int maxfid, startvid, currentfid;
  383         struct k7pnow_cpu_state *cstate;
  384         struct k7pnow_state *state;
  385         struct cpu_info *ci;
  386         char *techname = NULL;
  387         int i;
  388 
  389         if (setperf_prio > 1)
  390                 return;
  391 
  392         ci = curcpu();
  393 
  394         cpuid(0x80000000, regs);
  395         if (regs[0] < 0x80000007)
  396                 return;
  397 
  398         cpuid(0x80000007, regs);
  399         if (!(regs[3] & AMD_PN_FID_VID))
  400                 return;
  401 
  402         
  403         cpuid(0x80000001, regs);
  404 
  405         cstate = malloc(sizeof(struct k7pnow_cpu_state), M_DEVBUF, M_NOWAIT);
  406         if (!cstate)
  407                 return;
  408 
  409         cstate->flags = cstate->n_states = 0;
  410         if (ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
  411                 cstate->flags |= PN7_FLAG_ERRATA_A0;
  412 
  413         status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
  414         maxfid = PN7_STA_MFID(status);
  415         startvid = PN7_STA_SVID(status);
  416         currentfid = PN7_STA_CFID(status);
  417 
  418         cstate->fsb = cpuspeed / (k7pnow_fid_to_mult[currentfid]/10);
  419 
  420 #if NACPICPU > 0
  421         
  422         if (!k7pnow_acpi_init(cstate, status))
  423 #endif
  424         {
  425                 
  426                 if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid))
  427                         k7pnow_states(cstate, regs[0], maxfid, startvid);
  428         }
  429 
  430         if (cstate->n_states) {
  431                 if (cstate->flags & PN7_FLAG_DESKTOP_VRM)
  432                         techname = "Cool'n'Quiet K7";
  433                 else
  434                         techname = "PowerNow! K7";
  435                 printf("%s: %s %d MHz: speeds:",
  436                     ci->ci_dev.dv_xname, techname, cpuspeed);
  437                 for (i = cstate->n_states; i > 0; i--) {
  438                         state = &cstate->state_table[i-1];
  439                         printf(" %d", state->freq);
  440                 }
  441                 printf(" MHz\n");
  442 
  443                 k7pnow_current_state = cstate;
  444                 cpu_setperf = k7_powernow_setperf;
  445                 setperf_prio = 1;
  446                 return;
  447         }
  448         free(cstate, M_DEVBUF);
  449 }