void k7_powernow_setperf(int level) { unsigned int i; int cvid, cfid, vid = 0, fid = 0; uint64_t status, ctl; struct k7pnow_cpu_state * cstate; cstate = k7pnow_current_state; i = ((level * cstate->n_states) + 1) / 101; if (i >= cstate->n_states) i = cstate->n_states - 1; fid = cstate->state_table[i].fid; vid = cstate->state_table[i].vid; if (fid == 0 || vid == 0) return; status = rdmsr(MSR_AMDK7_FIDVID_STATUS); cfid = PN7_STA_CFID(status); cvid = PN7_STA_CVID(status); /* * We're already at the requested level. */ if (fid == cfid && vid == cvid) return; ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO; ctl |= PN7_CTR_FID(fid); ctl |= PN7_CTR_VID(vid); ctl |= PN7_CTR_SGTC(cstate->sgtc); if (cstate->flags & PN7_FLAG_ERRATA_A0) disable_intr(); if (k7pnow_fid_to_mult[fid] < k7pnow_fid_to_mult[cfid]) { wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); if (vid != cvid) wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); } else { wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC); if (fid != cfid) wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC); } if (cstate->flags & PN7_FLAG_ERRATA_A0) enable_intr(); status = rdmsr(MSR_AMDK7_FIDVID_STATUS); cfid = PN7_STA_CFID(status); cvid = PN7_STA_CVID(status); if (cfid == fid || cvid == vid) cpuspeed = cstate->state_table[i].freq; }
static int pn_probe(device_t dev) { struct pn_softc *sc; uint64_t status; uint64_t rate; struct pcpu *pc; u_int sfid, mfid, cfid; sc = device_get_softc(dev); sc->errata = 0; status = rdmsr(MSR_AMDK7_FIDVID_STATUS); pc = cpu_get_pcpu(dev); if (pc == NULL) return (ENODEV); cpu_est_clockrate(pc->pc_cpuid, &rate); switch (cpu_id & 0xf00) { case 0x600: sfid = PN7_STA_SFID(status); mfid = PN7_STA_MFID(status); cfid = PN7_STA_CFID(status); sc->pn_type = PN7_TYPE; sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid]; /* * If start FID is different to max FID, then it is a * mobile processor. If not, it is a low powered desktop * processor. */ if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) { sc->vid_to_volts = pn7_mobile_vid_to_volts; device_set_desc(dev, "PowerNow! K7"); } else { sc->vid_to_volts = pn7_desktop_vid_to_volts; device_set_desc(dev, "Cool`n'Quiet K7"); } break; case 0xf00: sfid = PN8_STA_SFID(status); mfid = PN8_STA_MFID(status); cfid = PN8_STA_CFID(status); sc->pn_type = PN8_TYPE; sc->vid_to_volts = pn8_vid_to_volts; sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid]; if (PN8_STA_SFID(status) != PN8_STA_MFID(status)) device_set_desc(dev, "PowerNow! K8"); else device_set_desc(dev, "Cool`n'Quiet K8"); break; default: return (ENODEV); } return (0); }
static int pn_get(device_t dev, struct cf_setting *cf) { struct pn_softc *sc; u_int cfid = 0, cvid = 0; int i; uint64_t status; if (cf == NULL) return (EINVAL); sc = device_get_softc(dev); if (sc->errata & PENDING_STUCK) return (ENXIO); status = rdmsr(MSR_AMDK7_FIDVID_STATUS); switch (sc->pn_type) { case PN7_TYPE: cfid = PN7_STA_CFID(status); cvid = PN7_STA_CVID(status); break; case PN8_TYPE: cfid = PN8_STA_CFID(status); cvid = PN8_STA_CVID(status); break; } for (i = 0; i < sc->powernow_max_states; ++i) if (cfid == sc->powernow_states[i].fid && cvid == sc->powernow_states[i].vid) break; if (i < sc->powernow_max_states) { cf->freq = sc->powernow_states[i].freq / 1000; cf->power = sc->powernow_states[i].power; cf->lat = 200; cf->volts = sc->vid_to_volts[cvid]; cf->dev = dev; } else { memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); cf->dev = NULL; } return (0); }
void k7_powernow_init(void) { u_int regs[4]; uint64_t status; u_int maxfid, startvid, currentfid; struct k7pnow_cpu_state *cstate; struct k7pnow_state *state; struct cpu_info *ci; char *techname = NULL; int i; if (setperf_prio > 1) return; ci = curcpu(); cpuid(0x80000000, regs); if (regs[0] < 0x80000007) return; cpuid(0x80000007, regs); if (!(regs[3] & AMD_PN_FID_VID)) return; /* Extended CPUID signature value */ cpuid(0x80000001, regs); cstate = malloc(sizeof(struct k7pnow_cpu_state), M_DEVBUF, M_NOWAIT); if (!cstate) return; cstate->flags = cstate->n_states = 0; if (ci->ci_signature == AMD_ERRATA_A0_CPUSIG) cstate->flags |= PN7_FLAG_ERRATA_A0; status = rdmsr(MSR_AMDK7_FIDVID_STATUS); maxfid = PN7_STA_MFID(status); startvid = PN7_STA_SVID(status); currentfid = PN7_STA_CFID(status); cstate->fsb = cpuspeed / (k7pnow_fid_to_mult[currentfid]/10); if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid)) if (!k7pnow_states(cstate, regs[0], maxfid, startvid)) { #if NACPICPU > 0 /* If we have it try ACPI */ k7pnow_acpi_init(cstate, status); #endif } if (cstate->n_states) { if (cstate->flags & PN7_FLAG_DESKTOP_VRM) techname = "Cool'n'Quiet K7"; else techname = "PowerNow! K7"; printf("%s: %s %d MHz: speeds:", ci->ci_dev.dv_xname, techname, cpuspeed); for (i = cstate->n_states; i > 0; i--) { state = &cstate->state_table[i-1]; printf(" %d", state->freq); } printf(" MHz\n"); k7pnow_current_state = cstate; cpu_setperf = k7_powernow_setperf; setperf_prio = 1; return; } free(cstate, M_DEVBUF, sizeof(*cstate)); }