[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