DF-5623 / fix.diff
--- a/sys/platform/pc64/x86_64/cpufreq_machdep.c +++ b/sys/platform/pc64/x86_64/cpufreq_machdep.c @@ -50,10 +50,12 @@ wrmsr(AMD0F_MSR_FIDVID_CTL, \ (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid))) -#define AMD0F_WAIT_FIDVID_CHG(status) \ -do { \ - (status) = rdmsr(AMD0F_MSR_FIDVID_STATUS); \ -} while (AMD0F_STA_PENDING(status)) +#define AMD0F_WAIT_FIDVID_CHG(status) do { \ + int _chg_n = 80000000; \ + do { \ + (status) = rdmsr(AMD0F_MSR_FIDVID_STATUS); \ + } while (AMD0F_STA_PENDING(status) && --_chg_n > 0); \ +} while (0) #define AMD0F_FID2VCO(fid) \ (((fid) < 8) ? (8 + ((fid) << 1)) : (fid)) @@ -68,7 +70,7 @@ amd0f_set_fidvid(const struct amd0f_fidvid *fv, const struct amd0f_xsit *xsit) { uint32_t val, cfid, cvid; - int rvo; + int rvo, nloop; uint64_t status; /* @@ -100,6 +102,8 @@ val = 0; AMD0F_WRITE_FIDVID(cfid, val, 0ULL); AMD0F_WAIT_FIDVID_CHG(status); + if (AMD0F_STA_PENDING(status)) + return ETIMEDOUT; cvid = AMD0F_STA_CVID(status); AMD0F_DELAY_VST(xsit->vst); } @@ -110,6 +114,8 @@ * under Linux */ AMD0F_WRITE_FIDVID(cfid, cvid - 1, 0ULL); AMD0F_WAIT_FIDVID_CHG(status); + if (AMD0F_STA_PENDING(status)) + return ETIMEDOUT; cvid = AMD0F_STA_CVID(status); AMD0F_DELAY_VST(xsit->vst); } @@ -123,7 +129,9 @@ vco_fid = AMD0F_FID2VCO(fv->fid); vco_cfid = AMD0F_FID2VCO(cfid); - while (abs(vco_fid - vco_cfid) > 2) { + for (nloop = 0; abs(vco_fid - vco_cfid) > 2; ++nloop) { + if (nloop >= 64) + return ETIMEDOUT; if (fv->fid > cfid) { if (cfid > 6) val = cfid + 2; @@ -136,6 +144,8 @@ AMD0F_WRITE_FIDVID(val, cvid, (uint64_t)xsit->pll_time * 1000 / 5); AMD0F_WAIT_FIDVID_CHG(status); + if (AMD0F_STA_PENDING(status)) + return ETIMEDOUT; cfid = AMD0F_STA_CFID(status); AMD0F_DELAY_IRT(xsit->irt); vco_cfid = AMD0F_FID2VCO(cfid); @@ -144,6 +154,8 @@ AMD0F_WRITE_FIDVID(fv->fid, cvid, (uint64_t)xsit->pll_time * 1000 / 5); AMD0F_WAIT_FIDVID_CHG(status); + if (AMD0F_STA_PENDING(status)) + return ETIMEDOUT; cfid = AMD0F_STA_CFID(status); AMD0F_DELAY_IRT(xsit->irt); } @@ -155,9 +167,15 @@ if (cvid != fv->vid) { AMD0F_WRITE_FIDVID(cfid, fv->vid, 0ULL); AMD0F_WAIT_FIDVID_CHG(status); + if (AMD0F_STA_PENDING(status)) + return ETIMEDOUT; cvid = AMD0F_STA_CVID(status); AMD0F_DELAY_VST(xsit->vst); } + if (cfid != fv->fid || cvid != fv->vid) + kprintf("amd0f: FID/VID transition did not converge " + "(fid %u/%u, vid %u/%u)\n", + cfid, fv->fid, cvid, fv->vid); return 0; } |