Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Sep 2015 12:58:18 -0400
From:      Anthony Jenkins <Scoobi_doo@yahoo.com>
To:        "freebsd-mobile@freebsd.org" <freebsd-mobile@freebsd.org>
Subject:   PATCH: cpufreq(4) support for modern AMD processors (git format)
Message-ID:  <56057D2A.9090505@yahoo.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------020102020707080202060604
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

sys/x86/cpufreq/hwpstate.c provides support for AMD CPUs, but only
supports families up to 0x11.  The latest AMD CPU family is 0x16.  This
patch adds support for newer AMD CPUs.  (The patch to
sys/x86/cpufreq/powernow.c is cosmetic/superfluous.)  Sources: BIOS and
Kernel Developer's Guide for AMD Family (10h|11h|12h|14h Models *|15h
Models *|16h Models *) Processors

I'm still looking into the occasional 'hwpstate0: set freq failed, err
6' error.  hwpstate0 reports "error: loop is not enough" when attempting
to set the P-state on my cores.

        CPU_FOREACH(i) {
                /* Bind to each cpu. */
                thread_lock(curthread);
                sched_bind(curthread, i);
                thread_unlock(curthread);
                /* wait loop (100*100 usec is enough ?) */
                for(j =3D 0; j < 100; j++){
                        /* get the result. not assure msr=3Did */
                        msr =3D rdmsr(MSR_AMD_10H_11H_STATUS);
                        if(msr =3D=3D id){
                                break;
                        }
                        DELAY(100);
                }
                HWPSTATE_DEBUG(dev, "result  P%d-state on cpu%d\n",
                    (int)msr, PCPU_GET(cpuid));
                if (msr !=3D id) {
                        HWPSTATE_DEBUG(dev, "error: loop is not enough.\n=
");
                        error =3D ENXIO;
                }
        }

I haven't figured out a more deterministic way of knowing when to read
the MSR after requesting the new P-state...still wading through the AMD
CPU manuals.

--=20
Anthony Jenkins
Software Engineer
Zenterio, Inc. USA


--------------020102020707080202060604
Content-Type: text/x-patch;
 name="amd_hwpstate_support.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
 filename="amd_hwpstate_support.patch"

diff --git a/sys/x86/cpufreq/hwpstate.c b/sys/x86/cpufreq/hwpstate.c
index d4c70b7..326d967 100644
--- a/sys/x86/cpufreq/hwpstate.c
+++ b/sys/x86/cpufreq/hwpstate.c
@@ -408,25 +408,27 @@ hwpstate_get_info_from_msr(device_t dev)
 	hwpstate_set =3D sc->hwpstate_settings;
 	for (i =3D 0; i < sc->cfnum; i++) {
 		msr =3D rdmsr(MSR_AMD_10H_11H_CONFIG + i);
-		if ((msr & ((uint64_t)1 << 63)) !=3D ((uint64_t)1 << 63)) {
+		if ((msr & ((uint64_t)1 << 63)) =3D=3D 0) {
 			HWPSTATE_DEBUG(dev, "msr is not valid.\n");
 			return (ENXIO);
 		}
 		did =3D AMD_10H_11H_CUR_DID(msr);
 		fid =3D AMD_10H_11H_CUR_FID(msr);
+		/* fid/did to frequency */
 		switch(family) {
 		case 0x11:
-			/* fid/did to frequency */
-			hwpstate_set[i].freq =3D 100 * (fid + 0x08) / (1 << did);
+			hwpstate_set[i].freq =3D (100 * (fid + 0x08)) >> did;
 			break;
 		case 0x10:
-			/* fid/did to frequency */
-			hwpstate_set[i].freq =3D 100 * (fid + 0x10) / (1 << did);
+		case 0x12:
+		case 0x14:
+		case 0x15:
+		case 0x16:
+			hwpstate_set[i].freq =3D (100 * (fid + 0x10)) >> did;
 			break;
 		default:
-			HWPSTATE_DEBUG(dev, "get_info_from_msr: AMD family %d CPU's are not i=
mplemented yet. sorry.\n", family);
+			HWPSTATE_DEBUG(dev, "get_info_from_msr: AMD family 0x%02x CPU's are n=
ot implemented yet. sorry.\n", family);
 			return (ENXIO);
-			break;
 		}
 		hwpstate_set[i].pstate_id =3D i;
 		/* There was volts calculation, but deleted it. */
diff --git a/sys/x86/cpufreq/powernow.c b/sys/x86/cpufreq/powernow.c
index cc62e87..355bde8 100644
--- a/sys/x86/cpufreq/powernow.c
+++ b/sys/x86/cpufreq/powernow.c
@@ -866,17 +866,22 @@ static void
 pn_identify(driver_t *driver, device_t parent)
 {
=20
-	if ((amd_pminfo & AMDPM_FID) =3D=3D 0 || (amd_pminfo & AMDPM_VID) =3D=3D=
 0)
+	if ((amd_pminfo & AMDPM_FID) =3D=3D 0 || (amd_pminfo & AMDPM_VID) =3D=3D=
 0) {
+		printf("powernow: pn_identify: amd_pminfo=3D0x%04x .\n", amd_pminfo);
 		return;
+	}
 	switch (cpu_id & 0xf00) {
 	case 0x600:
 	case 0xf00:
 		break;
 	default:
+		printf("powernow: pn_identify: cpu_id=3D0x%04x.\n", cpu_id);
 		return;
 	}
-	if (device_find_child(parent, "powernow", -1) !=3D NULL)
+	if (device_find_child(parent, "powernow", -1) !=3D NULL) {
+		printf("powernow: pn_identify: No \"powernow\"device found.\n");
 		return;
+	}
 	if (BUS_ADD_CHILD(parent, 10, "powernow", -1) =3D=3D NULL)
 		device_printf(parent, "powernow: add child failed\n");
 }
@@ -895,8 +900,10 @@ pn_probe(device_t dev)
 	status =3D rdmsr(MSR_AMDK7_FIDVID_STATUS);
=20
 	pc =3D cpu_get_pcpu(dev);
-	if (pc =3D=3D NULL)
+	if (pc =3D=3D NULL) {
+		printf("powernow: cpu_get_pcpu() returned NULL.\n");
 		return (ENODEV);
+	}
=20
 	cpu_est_clockrate(pc->pc_cpuid, &rate);
=20
@@ -936,6 +943,7 @@ pn_probe(device_t dev)
 			device_set_desc(dev, "Cool`n'Quiet K8");
 		break;
 	default:
+		printf("powernow: cpuid 0x%04x & 0xf00 not matched.\n", cpu_id);
 		return (ENODEV);
 	}
=20

--------------020102020707080202060604--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?56057D2A.9090505>