[Midnightbsd-cvs] src: i386/cpufreq: $MidnightBSD$ Add some k8 errata hacks to powernow.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat May 17 00:45:52 EDT 2008


Log Message:
-----------
$MidnightBSD$

Add some k8 errata hacks to powernow.

smist:
Use bus_dma to get a page in the first 4 GB.  Since the physical address
of the magic string is passed in a 32-bit register, we can't use high
memory in the PAE case.  This also eliminates a use of vtophys().

Obtained from: FreeBSD.

Modified Files:
--------------
    src/sys/i386/cpufreq:
        est.c (r1.2 -> r1.3)
        p4tcc.c (r1.1.1.1 -> r1.2)
        powernow.c (r1.1.1.1 -> r1.2)
        smist.c (r1.1.1.1 -> r1.2)

-------------- next part --------------
Index: est.c
===================================================================
RCS file: /home/cvs/src/sys/i386/cpufreq/est.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/i386/cpufreq/est.c -L sys/i386/cpufreq/est.c -u -r1.2 -r1.3
--- sys/i386/cpufreq/est.c
+++ sys/i386/cpufreq/est.c
@@ -26,7 +26,8 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/i386/cpufreq/est.c,v 1.7.2.1 2006/05/29 22:40:03 njl Exp $");
+/* $FreeBSD: /repoman/r/ncvs/src/sys/i386/cpufreq/est.c,v 1.7.2.1 2006/05/29 22:40:03 njl Exp $ */
+__MBSDID("$MidnightBSD$");
 
 #include <sys/param.h>
 #include <sys/bus.h>
Index: powernow.c
===================================================================
RCS file: /home/cvs/src/sys/i386/cpufreq/powernow.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/i386/cpufreq/powernow.c -L sys/i386/cpufreq/powernow.c -u -r1.1.1.1 -r1.2
--- sys/i386/cpufreq/powernow.c
+++ sys/i386/cpufreq/powernow.c
@@ -29,7 +29,8 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/i386/cpufreq/powernow.c,v 1.2 2005/03/31 06:11:04 njl Exp $");
+/*$FreeBSD: src/sys/i386/cpufreq/powernow.c,v 1.4 2007/01/23 19:20:30 bruno Exp $ */
+__MBSDID("$MidnightBSD$");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -44,7 +45,6 @@
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
 #include <machine/cputypes.h>
-#include <machine/clock.h>
 #include <machine/vmparam.h>
 #include <sys/rman.h>
 
@@ -56,6 +56,15 @@
 #define PN7_TYPE	0
 #define PN8_TYPE	1
 
+/* Flags for some hardware bugs. */
+#define A0_ERRATA	0x1	/* Bugs for the rev. A0 of Athlon (K7):
+				 * Interrupts must be disabled and no half
+				 * multipliers are allowed */
+#define PENDING_STUCK	0x2	/* With some buggy chipset and some newer AMD64
+				 * processor (Rev. G?):
+				 * the pending bit from the msr FIDVID_STATUS
+				 * is set forever.  No workaround :( */
+
 /* Legacy configuration via BIOS table PSB. */
 #define PSB_START	0
 #define PSB_STEP	0x10
@@ -141,11 +150,6 @@
 	wrmsr(MSR_AMDK7_FIDVID_CTL,	\
 	    (((ctrl) << 32) | (1ULL << 16) | ((vid) << 8) | (fid)))
 
-#define READ_PENDING_WAIT(status)	\
-	do {			\
-		(status) = rdmsr(MSR_AMDK7_FIDVID_STATUS);	\
-	} while (PN8_STA_PENDING(status))
-
 #define COUNT_OFF_IRT(irt)	DELAY(10 * (1 << (irt)))
 #define COUNT_OFF_VST(vst)	DELAY(20 * (vst))
 
@@ -165,11 +169,15 @@
 };
 
 
-static int pn8_fid_to_mult[32] = {
-	40, 50, 60, 70, 80, 90, 100, 110,
-	120, 130, 140, 150, 160, 170, 180, 190,
-	220, 230, 240, 250, 260, 270, 280, 290,
-	300, 310, 320, 330, 340, 350,
+static int pn8_fid_to_mult[64] = {
+	40, 45, 50, 55, 60, 65, 70, 75,
+	80, 85, 90, 95, 100, 105, 110, 115,
+	120, 125, 130, 135, 140, 145, 150, 155,
+	160, 165, 170, 175, 180, 185, 190, 195,
+	200, 205, 210, 215, 220, 225, 230, 235,
+	240, 245, 250, 255, 260, 265, 270, 275,
+	280, 285, 290, 295, 300, 305, 310, 315,
+	320, 325, 330, 335, 340, 345, 350, 355,
 };
 
 /*
@@ -220,7 +228,7 @@
 	int			 low;
 	int			 powernow_max_states;
 	u_int			 powernow_state;
-	int			 errata_a0;
+	u_int			 errata;
 	int			*vid_to_volts;
 };
 
@@ -286,7 +294,7 @@
 	ctl |= PN7_CTR_VID(vid);
 	ctl |= PN7_CTR_SGTC(sc->sgtc);
 
-	if (sc->errata_a0)
+	if (sc->errata & A0_ERRATA)
 		disable_intr();
 
 	if (pn7_fid_to_mult[fid] < pn7_fid_to_mult[cfid]) {
@@ -299,21 +307,49 @@
 			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
 	}
 
-	if (sc->errata_a0)
+	if (sc->errata & A0_ERRATA)
 		enable_intr();
 
 	return (0);
 }
 
 static int
+pn8_read_pending_wait(uint64_t *status)
+{
+	int i = 10000;
+
+	do
+		*status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
+	while (PN8_STA_PENDING(*status) && --i);
+
+	return (i == 0 ? ENXIO : 0);
+}
+
+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);
+}
+
+static int
 pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
 {
 	uint64_t status;
 	int cfid, cvid;
 	int rvo;
+	int rv;
 	u_int val;
 
-	READ_PENDING_WAIT(status);
+	rv = pn8_read_pending_wait(&status);
+	if (rv)
+		return (rv);
+
 	cfid = PN8_STA_CFID(status);
 	cvid = PN8_STA_CVID(status);
 
@@ -326,8 +362,11 @@
 	 */
 	while (cvid > vid) {
 		val = cvid - (1 << sc->mvs);
-		WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
-		READ_PENDING_WAIT(status);
+		rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
+		if (rv) {
+			sc->errata |= PENDING_STUCK;
+			return (rv);
+		}
 		cvid = PN8_STA_CVID(status);
 		COUNT_OFF_VST(sc->vst);
 	}
@@ -337,54 +376,67 @@
 		/* 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);
+		rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
+		if (rv) {
+			sc->errata |= PENDING_STUCK;
+			return (rv);
+		}
 		cvid = PN8_STA_CVID(status);
 		COUNT_OFF_VST(sc->vst);
 	}
 
 	/* Phase 2: change to requested core frequency */
 	if (cfid != fid) {
-		u_int vco_fid, vco_cfid;
+		u_int vco_fid, vco_cfid, fid_delta;
 
 		vco_fid = FID_TO_VCO_FID(fid);
 		vco_cfid = FID_TO_VCO_FID(cfid);
 
 		while (abs(vco_fid - vco_cfid) > 2) {
+			fid_delta = (vco_cfid & 1) ? 1 : 2;
 			if (fid > cfid) {
-				if (cfid > 6)
-					val = cfid + 2;
+				if (cfid > 7)
+					val = cfid + fid_delta;
 				else
-					val = FID_TO_VCO_FID(cfid) + 2;
+					val = FID_TO_VCO_FID(cfid) + fid_delta;
 			} else
-				val = cfid - 2;
-			WRITE_FIDVID(val, cvid, sc->pll * (uint64_t) sc->fsb);
-			READ_PENDING_WAIT(status);
+				val = cfid - fid_delta;
+			rv = pn8_write_fidvid(val, cvid,
+			    sc->pll * (uint64_t) sc->fsb,
+			    &status);
+			if (rv) {
+				sc->errata |= PENDING_STUCK;
+				return (rv);
+			}
 			cfid = PN8_STA_CFID(status);
 			COUNT_OFF_IRT(sc->irt);
 
 			vco_cfid = FID_TO_VCO_FID(cfid);
 		}
 
-		WRITE_FIDVID(fid, cvid, sc->pll * (uint64_t) sc->fsb);
-		READ_PENDING_WAIT(status);
+		rv = pn8_write_fidvid(fid, cvid,
+		    sc->pll * (uint64_t) sc->fsb,
+		    &status);
+		if (rv) {
+			sc->errata |= PENDING_STUCK;
+			return (rv);
+		}
 		cfid = PN8_STA_CFID(status);
 		COUNT_OFF_IRT(sc->irt);
 	}
 
 	/* Phase 3: change to requested voltage */
 	if (cvid != vid) {
-		WRITE_FIDVID(cfid, vid, 1ULL);
-		READ_PENDING_WAIT(status);
+		rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
 		cvid = PN8_STA_CVID(status);
 		COUNT_OFF_VST(sc->vst);
 	}
 
 	/* Check if transition failed. */
 	if (cfid != fid || cvid != vid)
-		return (ENXIO);
+		rv = ENXIO;
 
-	return (0);
+	return (rv);
 }
 
 static int
@@ -399,6 +451,9 @@
 		return (EINVAL);
 	sc = device_get_softc(dev);
 
+	if (sc->errata & PENDING_STUCK)
+		return (ENXIO);
+
 	for (i = 0; i < sc->powernow_max_states; ++i)
 		if (CPUFREQ_CMP(sc->powernow_states[i].freq / 1000, cf->freq))
 			break;
@@ -431,6 +486,8 @@
 	if (cf == NULL)
 		return (EINVAL);
 	sc = device_get_softc(dev);
+	if (sc->errata & PENDING_STUCK)
+		return (ENXIO);
 
 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
 
@@ -518,13 +575,12 @@
 		switch (sc->pn_type) {
 		case PN7_TYPE:
 			state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
-			if (sc->errata_a0 &&
+			if ((sc->errata & A0_ERRATA) &&
 			    (pn7_fid_to_mult[state.fid] % 10) == 5)
 				continue;
 			break;
 		case PN8_TYPE:
-			state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
-			    sc->fsb;
+			state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
 			break;
 		}
 
@@ -541,7 +597,7 @@
 	}
 
 	/*
-	 * Fix powernow_max_states, if errata_a0 give us less states
+	 * Fix powernow_max_states, if errata a0 give us less states
 	 * than expected.
 	 */
 	sc->powernow_max_states = n;
@@ -597,7 +653,7 @@
 	cpuid = regs[0];
 
 	if ((cpuid & 0xfff) == 0x760)
-		sc->errata_a0 = TRUE;
+		sc->errata |= A0_ERRATA;
 
 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
 
@@ -749,7 +805,7 @@
 	do_cpuid(0x80000001, regs);
 	cpuid = regs[0];
 	if ((cpuid & 0xfff) == 0x760)
-		sc->errata_a0 = TRUE;
+		sc->errata |= A0_ERRATA;
 
 	ctrl = 0;
 	sc->sgtc = 0;
@@ -759,7 +815,7 @@
 		case PN7_TYPE:
 			state.fid = ACPI_PN7_CTRL_TO_FID(ctrl);
 			state.vid = ACPI_PN7_CTRL_TO_VID(ctrl);
-			if (sc->errata_a0 &&
+			if ((sc->errata & A0_ERRATA) &&
 			    (pn7_fid_to_mult[state.fid] % 10) == 5)
 				continue;
 			state.freq = 100 * pn7_fid_to_mult[state.fid] * sc->fsb;
@@ -767,8 +823,7 @@
 		case PN8_TYPE:
 			state.fid = ACPI_PN8_CTRL_TO_FID(ctrl);
 			state.vid = ACPI_PN8_CTRL_TO_VID(ctrl);
-			state.freq = 100 * pn8_fid_to_mult[state.fid >> 1] *
-			    sc->fsb;
+			state.freq = 100 * pn8_fid_to_mult[state.fid] * sc->fsb;
 			break;
 		}
 
@@ -854,7 +909,7 @@
 	u_int sfid, mfid, cfid;
 
 	sc = device_get_softc(dev);
-	sc->errata_a0 = FALSE;
+	sc->errata = 0;
 	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
 
 	pc = cpu_get_pcpu(dev);
@@ -891,7 +946,7 @@
 		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 >> 1];
+		sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];
 
 		if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
 			device_set_desc(dev, "PowerNow! K8");
Index: p4tcc.c
===================================================================
RCS file: /home/cvs/src/sys/i386/cpufreq/p4tcc.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/i386/cpufreq/p4tcc.c -L sys/i386/cpufreq/p4tcc.c -u -r1.1.1.1 -r1.2
--- sys/i386/cpufreq/p4tcc.c
+++ sys/i386/cpufreq/p4tcc.c
@@ -37,7 +37,8 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/i386/cpufreq/p4tcc.c,v 1.11.2.1 2005/10/25 20:52:44 njl Exp $");
+/* $FreeBSD: src/sys/i386/cpufreq/p4tcc.c,v 1.11.2.1 2005/10/25 20:52:44 njl Exp $ */
+__MBSDID("$MidnightBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
Index: smist.c
===================================================================
RCS file: /home/cvs/src/sys/i386/cpufreq/smist.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/i386/cpufreq/smist.c -L sys/i386/cpufreq/smist.c -u -r1.1.1.1 -r1.2
--- sys/i386/cpufreq/smist.c
+++ sys/i386/cpufreq/smist.c
@@ -36,15 +36,18 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/i386/cpufreq/smist.c,v 1.1 2005/04/19 16:38:24 njl Exp $");
+__FBSDID("$FreeBSD: src/sys/i386/cpufreq/smist.c,v 1.2 2007/06/17 07:18:23 njl Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/cpu.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
 #include <sys/systm.h>
 
+#include <machine/bus.h>
 #include <machine/md_var.h>
 #include <machine/vm86.h>
 
@@ -71,6 +74,8 @@
 	struct cf_setting	 sets[2];	/* Only two settings. */
 };
 
+static char smist_magic[] = "Copyright (c) 1999 Intel Corporation";
+
 static void	smist_identify(driver_t *driver, device_t parent);
 static int	smist_probe(device_t dev);
 static int	smist_attach(device_t dev);
@@ -147,34 +152,84 @@
 	return (0);
 }
 
-static int
-set_ownership(device_t dev)
-{
-	int result;
-	struct smist_softc *sc;
-	vm_paddr_t pmagic;
-	static char magic[] = "Copyright (c) 1999 Intel Corporation";
+/* Temporary structure to hold mapped page and status. */
+struct set_ownership_data {
+	int	smi_cmd;
+	int	command;
+	int	result;
+	void	*buf;
+};
 
-	sc = device_get_softc(dev);
-	if (!sc)
-		return (ENXIO);
+/* Perform actual SMI call to enable SpeedStep. */
+static void
+set_ownership_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct set_ownership_data *data;
 
-	pmagic = vtophys(magic);
+	data = arg;
+	if (error) {
+		data->result = error;
+		return;
+	}
 
+	/* Copy in the magic string and send it by writing to the SMI port. */
+	strlcpy(data->buf, smist_magic, PAGE_SIZE);
 	__asm __volatile(
 	    "movl $-1, %%edi\n\t"
 	    "out %%al, (%%dx)\n"
-	    : "=D" (result)
-	    : "a" (sc->command),
+	    : "=D" (data->result)
+	    : "a" (data->command),
 	      "b" (0),
 	      "c" (0),
-	      "d" (sc->smi_cmd),
-	      "S" (pmagic)
+	      "d" (data->smi_cmd),
+	      "S" ((uint32_t)segs[0].ds_addr)
 	);
+}
 
-	DPRINT(dev, "taking ownership over BIOS return %d\n", result);
+static int
+set_ownership(device_t dev)
+{
+	struct smist_softc *sc;
+	struct set_ownership_data cb_data;
+	bus_dma_tag_t tag;
+	bus_dmamap_t map;
+
+	/*
+	 * Specify the region to store the magic string.  Since its address is
+	 * passed to the BIOS in a 32-bit register, we have to make sure it is
+	 * located in a physical page below 4 GB (i.e., for PAE.)
+	 */
+	sc = device_get_softc(dev);
+	if (bus_dma_tag_create(/*parent*/ NULL,
+	    /*alignment*/ PAGE_SIZE, /*no boundary*/ 0,
+	    /*lowaddr*/ BUS_SPACE_MAXADDR_32BIT, /*highaddr*/ BUS_SPACE_MAXADDR,
+	    NULL, NULL, /*maxsize*/ PAGE_SIZE, /*segments*/ 1,
+	    /*maxsegsize*/ PAGE_SIZE, 0, busdma_lock_mutex, &Giant,
+	    &tag) != 0) {
+		device_printf(dev, "can't create mem tag\n");
+		return (ENXIO);
+	}
+	if (bus_dmamem_alloc(tag, &cb_data.buf, BUS_DMA_NOWAIT, &map) != 0) {
+		bus_dma_tag_destroy(tag);
+		device_printf(dev, "can't alloc mapped mem\n");
+		return (ENXIO);
+	}
 
-	return (result ? ENXIO : 0);
+	/* Load the physical page map and take ownership in the callback. */
+	cb_data.smi_cmd = sc->smi_cmd;
+	cb_data.command = sc->command;
+	if (bus_dmamap_load(tag, map, cb_data.buf, PAGE_SIZE, set_ownership_cb,
+	    &cb_data, BUS_DMA_NOWAIT) != 0) {
+		bus_dmamem_free(tag, cb_data.buf, map);
+		bus_dma_tag_destroy(tag);
+		device_printf(dev, "can't load mem\n");
+		return (ENXIO);
+	};
+	DPRINT(dev, "taking ownership over BIOS return %d\n", cb_data.result);
+	bus_dmamap_unload(tag, map);
+	bus_dmamem_free(tag, cb_data.buf, map);
+	bus_dma_tag_destroy(tag);
+	return (cb_data.result ? ENXIO : 0);
 }
 
 static int


More information about the Midnightbsd-cvs mailing list