static int pn8_write_fidvid(u_int fid, u_int vid, uint64_t ctrl, uint64_t *status) { int i = 100; do WRITE_FIDVID(fid, vid, ctrl); while (pn8_read_pending_wait(status) && --i); return (i == 0 ? ENXIO : 0); }
void k8pnow_transition(struct k8pnow_cpu_state *cstate, int level) { uint64_t status; int cfid, cvid, fid = 0, vid = 0; int rvo; u_int val; /* * We dont do a k8pnow_read_pending_wait here, need to ensure that the * change pending bit isn't stuck, */ status = rdmsr(MSR_AMDK7_FIDVID_STATUS); if (PN8_STA_PENDING(status)) return; cfid = PN8_STA_CFID(status); cvid = PN8_STA_CVID(status); fid = cstate->state_table[level].fid; vid = cstate->state_table[level].vid; if (fid == cfid && vid == cvid) return; /* * Phase 1: Raise core voltage to requested VID if frequency is * going up. */ while (cvid > vid) { val = cvid - (1 << cstate->mvs); WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL); if (k8pnow_read_pending_wait(&status)) return; cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } /* ... then raise to voltage + RVO (if required) */ for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) { /* XXX It's not clear from spec if we have to do that * in 0.25 step or in MVS. Therefore do it as it's done * under Linux */ WRITE_FIDVID(cfid, cvid - 1, 1ULL); if (k8pnow_read_pending_wait(&status)) return; cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } /* Phase 2: change to requested core frequency */ if (cfid != fid) { u_int vco_fid, vco_cfid; vco_fid = FID_TO_VCO_FID(fid); vco_cfid = FID_TO_VCO_FID(cfid); while (abs(vco_fid - vco_cfid) > 2) { if (fid > cfid) { if (cfid > 6) val = cfid + 2; else val = FID_TO_VCO_FID(cfid) + 2; } else val = cfid - 2; WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5); if (k8pnow_read_pending_wait(&status)) return; cfid = PN8_STA_CFID(status); COUNT_OFF_IRT(cstate->irt); vco_cfid = FID_TO_VCO_FID(cfid); } WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5); if (k8pnow_read_pending_wait(&status)) return; cfid = PN8_STA_CFID(status); COUNT_OFF_IRT(cstate->irt); } /* Phase 3: change to requested voltage */ if (cvid != vid) { WRITE_FIDVID(cfid, vid, 1ULL); if (k8pnow_read_pending_wait(&status)) return; cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } if (cfid == fid || cvid == vid) cpuspeed = cstate->state_table[level].freq; }
static int k8_powernow_setperf(unsigned int freq) { unsigned int i; uint64_t status; uint32_t val; int cfid , cvid, fid = 0, vid = 0; int rvo; struct k8pnow_cpu_state *cstate; /* * We dont do a k8pnow_read_pending_wait here, need to ensure that * the change pending bit isn't stuck, */ status = rdmsr(MSR_AMDK7_FIDVID_STATUS); if (PN8_STA_PENDING(status)) return 1; cfid = PN8_STA_CFID(status); cvid = PN8_STA_CVID(status); cstate = k8pnow_current_state; for (i = 0; i < cstate->n_states; i++) { if (cstate->state_table[i].freq >= freq) { fid = cstate->state_table[i].fid; vid = cstate->state_table[i].vid; break; } } if (fid == cfid && vid == cvid) { cpuspeed = freq; return 0; } /* * Phase 1: Raise core voltage to requested VID if frequency is going * up. */ while (cvid > vid) { val = cvid - (1 << cstate->mvs); WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL); READ_PENDING_WAIT(status); cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } /* ... then raise to voltage + RVO (if required) */ for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) { /* * XXX It's not clear from spec if we have to do that in 0.25 * step or in MVS. Therefore do it as it's done under Linux */ WRITE_FIDVID(cfid, cvid - 1, 1ULL); READ_PENDING_WAIT(status); cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } /* Phase 2: change to requested core frequency */ if (cfid != fid) { uint32_t vco_fid, vco_cfid; vco_fid = FID_TO_VCO_FID(fid); vco_cfid = FID_TO_VCO_FID(cfid); while (abs(vco_fid - vco_cfid) > 2) { if (fid > cfid) { if (cfid > 6) val = cfid + 2; else val = FID_TO_VCO_FID(cfid) + 2; } else val = cfid - 2; WRITE_FIDVID(val, cvid, (uint64_t) cstate->pll * 1000 / 5); READ_PENDING_WAIT(status); cfid = PN8_STA_CFID(status); COUNT_OFF_IRT(cstate->irt); vco_cfid = FID_TO_VCO_FID(cfid); } WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5); READ_PENDING_WAIT(status); cfid = PN8_STA_CFID(status); COUNT_OFF_IRT(cstate->irt); } /* Phase 3: change to requested voltage */ if (cvid != vid) { WRITE_FIDVID(cfid, vid, 1ULL); READ_PENDING_WAIT(status); cvid = PN8_STA_CVID(status); COUNT_OFF_VST(cstate->vst); } if (cfid == fid || cvid == vid) cpuspeed = cstate->state_table[i].freq; return 0; }