Avoiding an infinite loop during P-state adjustment on the HP6715s notebook.
authorImre Vadasz <imre@vdsz.com>
Sun, 23 Feb 2014 00:08:12 +0000 (01:08 +0100)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 24 Feb 2014 08:40:00 +0000 (16:40 +0800)
The code is taken from the OpenBSD counterpart to amd0f_set_fidvid.
The infinite loop probably occurs on my HP6715s because the rvo adjustment
doesn't get applied by the hardware when entering the highest P-state
(maybe because of some kind of overvolting protection).

sys/platform/pc64/x86_64/cpufreq_machdep.c

index 21a48ec..40db2e6 100644 (file)
@@ -67,7 +67,8 @@ do { \
 int
 amd0f_set_fidvid(const struct amd0f_fidvid *fv, const struct amd0f_xsit *xsit)
 {
-       uint32_t val, cfid, cvid, tvid;
+       uint32_t val, cfid, cvid;
+       int rvo;
        uint64_t status;
 
        /*
@@ -84,16 +85,15 @@ amd0f_set_fidvid(const struct amd0f_fidvid *fv, const struct amd0f_xsit *xsit)
                return 0;
 
        /*
-        * Phase 1: Raise core voltage to the TargetVID
+        * Phase 1: Raise core voltage to requested VID if frequency is
+        * going up.
         */
        if ((fv->fid & ~0x1) > (cfid & ~0x1) || cvid > fv->vid) {
                KKASSERT(fv->vid >= xsit->rvo);
-               tvid = fv->vid - xsit->rvo;
        } else {
                KKASSERT(cvid >= xsit->rvo);
-               tvid = cvid - xsit->rvo;
        }
-       while (cvid > tvid) {
+       while (cvid > fv->vid) {
                if (cvid > (1 << xsit->mvs))
                        val = cvid - (1 << xsit->mvs);
                else
@@ -103,6 +103,16 @@ amd0f_set_fidvid(const struct amd0f_fidvid *fv, const struct amd0f_xsit *xsit)
                cvid = AMD0F_STA_CVID(status);
                AMD0F_DELAY_VST(xsit->vst);
        }
+       /* ... then raise to voltage + RVO (if required) */
+       for (rvo = xsit->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 */
+               AMD0F_WRITE_FIDVID(cfid, cvid - 1, 0ULL);
+               AMD0F_WAIT_FIDVID_CHG(status);
+               cvid = AMD0F_STA_CVID(status);
+               AMD0F_DELAY_VST(xsit->vst);
+       }
 
        /*
         * Phase 2: Change to requested core frequency