shithub: riscv

Download patch

ref: e81e1a4aeddad2bc612c9c5243573250b6ff33a4
parent: dfe8c8bffb497ecd46e9e43eb838ff3e10912663
author: cinap_lenrek <[email protected]>
date: Tue Oct 21 02:03:03 EDT 2014

pc, pc64: make mtrr() callable from interrupt context and before mpinit

to make it possible to mark the bootscreen framebuffer
as write combining in early initialization, mtrr() is
changed not not to error() but to return an error string.

as bootscreen() is used before multiprocessor initialization,
we have to synchronize the mtrr's for every processor as
it comes online. for this, a new mtrrsync() function is
provided that is called from cpuidentify() if mtrr support
is indicated.

the boot processor runs mtrrsync() which snarfs the
registers. later, mtrrsync() is run again from the
application processors which apply the values from the
boot processor.

checkmtrr() from mp.c was removed as its task is also
done by mtrrsync() now.

--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -256,11 +256,6 @@
 	int	pdballoc;
 	int	pdbfree;
 
-	vlong	mtrrcap;
-	vlong	mtrrdef;
-	vlong	mtrrfix[11];
-	vlong	mtrrvar[32];		/* 256 max. */
-
 	int	stack[1];
 };
 
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -883,6 +883,9 @@
 			rdmsr(0x01, &mct);
 	}
 
+	if(m->cpuiddx & Mtrr)
+		mtrrsync();
+
 	if(m->cpuiddx & Fxsr){			/* have sse fp? */
 		fpsave = fpssesave;
 		fprestore = fpsserestore;
@@ -1024,7 +1027,9 @@
 		size = strtoull(cb->f[2], &ep, 0);
 		if(*ep)
 			error("cache: parse error: size not a number?");
-		mtrr(base, size, cb->f[3]);
+		ep = mtrr(base, size, cb->f[3]);
+		if(ep != nil)
+			error(ep);
 		break;
 	}
 	free(cb);
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -111,9 +111,10 @@
 #define mmuflushtlb(pdb) putcr3(pdb)
 void	mmuinit(void);
 ulong*	mmuwalk(ulong*, ulong, int, int);
-int	mtrr(uvlong, uvlong, char *);
+char*	mtrr(uvlong, uvlong, char *);
 void	mtrrclock(void);
 int	mtrrprint(char *, long);
+void	mtrrsync(void);
 uchar	nvramread(int);
 void	nvramwrite(int, uchar);
 void	outb(int, int);
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -90,58 +90,6 @@
 	return v;
 }
 
-void
-checkmtrr(void)
-{
-	int i, vcnt;
-	Mach *mach0;
-
-	/*
-	 * If there are MTRR registers, snarf them for validation.
-	 */
-	if(!(m->cpuiddx & Mtrr))
-		return;
-
-	rdmsr(0x0FE, &m->mtrrcap);
-	rdmsr(0x2FF, &m->mtrrdef);
-	if(m->mtrrcap & 0x0100){
-		rdmsr(0x250, &m->mtrrfix[0]);
-		rdmsr(0x258, &m->mtrrfix[1]);
-		rdmsr(0x259, &m->mtrrfix[2]);
-		for(i = 0; i < 8; i++)
-			rdmsr(0x268+i, &m->mtrrfix[(i+3)]);
-	}
-	vcnt = m->mtrrcap & 0x00FF;
-	if(vcnt > nelem(m->mtrrvar))
-		vcnt = nelem(m->mtrrvar);
-	for(i = 0; i < vcnt; i++)
-		rdmsr(0x200+i, &m->mtrrvar[i]);
-
-	/*
-	 * If not the bootstrap processor, compare.
-	 */
-	if(m->machno == 0)
-		return;
-
-	mach0 = MACHP(0);
-	if(mach0->mtrrcap != m->mtrrcap)
-		print("mtrrcap%d: %lluX %lluX\n",
-			m->machno, mach0->mtrrcap, m->mtrrcap);
-	if(mach0->mtrrdef != m->mtrrdef)
-		print("mtrrdef%d: %lluX %lluX\n",
-			m->machno, mach0->mtrrdef, m->mtrrdef);
-	for(i = 0; i < 11; i++){
-		if(mach0->mtrrfix[i] != m->mtrrfix[i])
-			print("mtrrfix%d: i%d: %lluX %lluX\n",
-				m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]);
-	}
-	for(i = 0; i < vcnt; i++){
-		if(mach0->mtrrvar[i] != m->mtrrvar[i])
-			print("mtrrvar%d: i%d: %lluX %lluX\n",
-				m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]);
-	}
-}
-
 uvlong
 tscticks(uvlong *hz)
 {
@@ -233,8 +181,6 @@
 	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");
 	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");
 	lapiconline();
-
-	checkmtrr();
 
 	/*
 	 * Initialise the application processors.
--- a/sys/src/9/pc/mtrr.c
+++ b/sys/src/9/pc/mtrr.c
@@ -69,10 +69,6 @@
 	vlong	base;
 	vlong	mask;
 };
-struct Mtrrop {
-	Mtrreg	*reg;
-	int	slot;
-};
 
 static char *types[] = {
 [Uncacheable]	"uc",
@@ -84,9 +80,10 @@
 [Writeback]	"wb",
 		nil
 };
-static Mtrrop *postedop;
-static Rendez oprend;
 
+static int dosync;
+static Mtrreg mtrreg[Nmtrr];
+
 static char *
 type2str(int type)
 {
@@ -163,8 +160,6 @@
 static void
 mtrrget(Mtrreg *mtrr, uint i)
 {
-	if (i >= Nmtrr)
-		error("mtrr index out of range");
 	rdmsr(MTRRPhysBase0 + 2*i, &mtrr->base);
 	rdmsr(MTRRPhysMask0 + 2*i, &mtrr->mask);
 	sanity(mtrr);
@@ -173,31 +168,44 @@
 static void
 mtrrput(Mtrreg *mtrr, uint i)
 {
-	if (i >= Nmtrr)
-		error("mtrr index out of range");
 	sanity(mtrr);
 	wrmsr(MTRRPhysBase0 + 2*i, mtrr->base);
 	wrmsr(MTRRPhysMask0 + 2*i, mtrr->mask);
 }
 
+static int
+mtrrvcnt(void)
+{
+	vlong cap;
+	int vcnt;
+
+	rdmsr(MTRRCap, &cap);
+	vcnt = cap & Capvcnt;
+	if(vcnt > Nmtrr)
+		vcnt = Nmtrr;
+	return vcnt;
+}
+
+static int
+mtrrgetall(void)
+{
+	int i, vcnt;
+
+	vcnt = mtrrvcnt();
+	for(i = 0; i < vcnt; i++)
+		mtrrget(&mtrreg[i], i);
+	return vcnt;
+}
+
 static void
-mtrrop(Mtrrop **op)
+mtrrputall(void)
 {
-	int s;
+	int s, i, vcnt;
 	ulong cr0, cr4;
 	vlong def;
-	static Ref bar1, bar2;
 
-	s = splhi();		/* avoid race with mtrrclock */
+	s = splhi();
 
-	/*
-	 * wait for all CPUs to sync here, so that the MTRR setup gets
-	 * done at roughly the same time on all processors.
-	 */
-	incref(&bar1);
-	while(bar1.ref < conf.nmach)
-		microdelay(10);
-
 	cr4 = getcr4();
 	putcr4(cr4 & ~CR4PageGlobalEnable);
 	cr0 = getcr0();
@@ -207,7 +215,9 @@
 	rdmsr(MTRRDefaultType, &def);
 	wrmsr(MTRRDefaultType, def & ~(vlong)Defena);
 
-	mtrrput((*op)->reg, (*op)->slot);
+	vcnt = mtrrvcnt();
+	for(i=0; i<vcnt; i++)
+		mtrrput(&mtrreg[i], i);
 
 	wbinvd();
 	wrmsr(MTRRDefaultType, def);
@@ -214,7 +224,31 @@
 	putcr0(cr0);
 	putcr4(cr4);
 
+	splx(s);
+}
+
+void
+mtrrclock(void)				/* called from clock interrupt */
+{
+	static Ref bar1, bar2;
+	int s;
+
+	if(dosync == 0)
+		return;
+
+	s = splhi();
+
 	/*
+	 * wait for all CPUs to sync here, so that the MTRR setup gets
+	 * done at roughly the same time on all processors.
+	 */
+	incref(&bar1);
+	while(bar1.ref < conf.nmach)
+		microdelay(10);
+
+	mtrrputall();
+
+	/*
 	 * wait for all CPUs to sync up again, so that we don't continue
 	 * executing while the MTRRs are still being set up.
 	 */
@@ -225,49 +259,31 @@
 	while(bar1.ref > 0)
 		microdelay(10);
 	decref(&bar2);
-	*op = nil;
-	wakeup(&oprend);
+
+	dosync = 0;
 	splx(s);
 }
 
-void
-mtrrclock(void)				/* called from clock interrupt */
+static char*
+mtrr0(uvlong base, uvlong size, char *tstr)
 {
-	if(postedop != nil)
-		mtrrop(&postedop);
-}
-
-/* if there's an operation still pending, keep sleeping */
-static int
-opavail(void *)
-{
-	return postedop == nil;
-}
-
-int
-mtrr(uvlong base, uvlong size, char *tstr)
-{
 	int i, vcnt, slot, type, mtype, mok;
 	vlong def, cap;
 	uvlong mp, msize;
-	Mtrreg entry, mtrr;
-	Mtrrop op;
-	static int tickreg;
-	static QLock mtrrlk;
 
 	if(!(m->cpuiddx & Mtrr))
-		error("mtrrs not supported");
+		return "mtrrs not supported";
 	if(base & (BY2PG-1) || size & (BY2PG-1) || size == 0)
-		error("mtrr base or size not 4k aligned or zero size");
+		return "mtrr base or size not 4k aligned or zero size";
 	if(base + size >= Paerange)
-		error("mtrr range exceeds 36 bits");
+		return "mtrr range exceeds 36 bits";
 	if(!ispow2(size))
-		error("mtrr size not power of 2");
+		return "mtrr size not power of 2";
 	if(base & (size - 1))
-		error("mtrr base not naturally aligned");
+		return "mtrr base not naturally aligned";
 
 	if((type = str2type(tstr)) == -1)
-		error("mtrr bad type");
+		return "mtrr bad type";
 
 	rdmsr(MTRRCap, &cap);
 	rdmsr(MTRRDefaultType, &def);
@@ -274,11 +290,10 @@
 
 	switch(type){
 	default:
-		error("mtrr unknown type");
-		break;
+		return "mtrr unknown type";
 	case Writecomb:
 		if(!(cap & Capwc))
-			error("mtrr type wc (write combining) unsupported");
+			return "mtrr type wc (write combining) unsupported";
 		/* fallthrough */
 	case Uncacheable:
 	case Writethru:
@@ -287,18 +302,11 @@
 		break;
 	}
 
-	qlock(&mtrrlk);
-	if(waserror()){
-		qunlock(&mtrrlk);
-		nexterror();
-	}
+	vcnt = mtrrgetall();
+
 	slot = -1;
-	vcnt = cap & Capvcnt;
-	if(vcnt > Nmtrr)
-		vcnt = Nmtrr;
 	for(i = 0; i < vcnt; i++){
-		mtrrget(&mtrr, i);
-		mok = mtrrdec(&mtrr, &mp, &msize, &mtype);
+		mok = mtrrdec(&mtrreg[i], &mp, &msize, &mtype);
 		if(slot == -1 && (!mok || mtype == (def & Deftype)))
 			slot = i;	/* good, but look further for exact match */
 		if(mok && mp == base && msize == size){
@@ -307,40 +315,45 @@
 		}
 	}
 	if(slot == -1)
-		error("no free mtrr slots");
+		return "no free mtrr slots";
 
-	while(!opavail(0))
-		sleep(&oprend, opavail, 0);
+	mtrrenc(&mtrreg[slot], base, size, type, 1);
 
-	mtrrenc(&entry, base, size, type, 1);
-	op.reg = &entry;
-	op.slot = slot;
-	postedop = &op;
-	mtrrop(&postedop);
+	coherence();
+
+	dosync = 1;
+	mtrrclock();
+
+	return nil;
+}
+
+char*
+mtrr(uvlong base, uvlong size, char *tstr)
+{
+	static QLock mtrrlk;
+	char *err;
+
+	qlock(&mtrrlk);
+	err = mtrr0(base, size, tstr);
 	qunlock(&mtrrlk);
-	poperror();
-	return 0;
+
+	return err;
 }
 
 int
 mtrrprint(char *buf, long bufsize)
 {
-	int i, vcnt, type;
-	long n;
+	int i, n, vcnt, type;
 	uvlong base, size;
-	vlong cap, def;
 	Mtrreg mtrr;
+	vlong def;
 
-	n = 0;
 	if(!(m->cpuiddx & Mtrr))
 		return 0;
-	rdmsr(MTRRCap, &cap);
 	rdmsr(MTRRDefaultType, &def);
-	n += snprint(buf+n, bufsize-n, "cache default %s\n",
+	n = snprint(buf, bufsize, "cache default %s\n",
 		type2str(def & Deftype));
-	vcnt = cap & Capvcnt;
-	if(vcnt > Nmtrr)
-		vcnt = Nmtrr;
+	vcnt = mtrrvcnt();
 	for(i = 0; i < vcnt; i++){
 		mtrrget(&mtrr, i);
 		if (mtrrdec(&mtrr, &base, &size, &type))
@@ -349,4 +362,29 @@
 				base, size, type2str(type));
 	}
 	return n;
+}
+
+void
+mtrrsync(void)
+{
+	static vlong cap0, def0;
+	vlong cap, def;
+
+	rdmsr(MTRRCap, &cap);
+	rdmsr(MTRRDefaultType, &def);
+
+	if(m->machno == 0){
+		cap0 = cap;
+		def0 = def;
+		mtrrgetall();
+		return;
+	}
+
+	if(cap0 != cap)
+		print("mtrrcap%d: %lluX %lluX\n",
+			m->machno, cap0, cap);
+	if(def0 != def)
+		print("mtrrdef%d: %lluX %lluX\n",
+			m->machno, def0, def);
+	mtrrputall();
 }
--- a/sys/src/9/pc/screen.c
+++ b/sys/src/9/pc/screen.c
@@ -512,13 +512,7 @@
 	scr->paddr = paddr;
 	scr->apsize = nsize;
 
-	if(up != nil){
-		/* let mtrr harmlessly fail on old CPUs, e.g., P54C */
-		if(!waserror()){
-			mtrr(npaddr, nsize, "wc");
-			poperror();
-		}
-	}
+	mtrr(npaddr, nsize, "wc");
 
 	return nil;
 }
--- a/sys/src/9/pc/squidboy.c
+++ b/sys/src/9/pc/squidboy.c
@@ -8,8 +8,6 @@
 
 #include "mp.h"
 
-extern void checkmtrr(void);
-
 static void
 squidboy(Apic* apic)
 {
@@ -20,7 +18,6 @@
 
 	cpuidentify();
 	cpuidprint();
-	checkmtrr();
 
 	apic->online = 1;
 	coherence();
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -223,11 +223,6 @@
 	int	pdballoc;
 	int	pdbfree;
 
-	vlong	mtrrcap;
-	vlong	mtrrdef;
-	vlong	mtrrfix[11];
-	vlong	mtrrvar[32];		/* 256 max. */
-
 	uintptr	stack[1];
 };
 
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -102,9 +102,10 @@
 #define mmuflushtlb() putcr3(getcr3())
 void	mmuinit(void);
 uintptr	*mmuwalk(uintptr*, uintptr, int, int);
-int	mtrr(uvlong, uvlong, char *);
+char*	mtrr(uvlong, uvlong, char *);
 void	mtrrclock(void);
 int	mtrrprint(char *, long);
+void	mtrrsync(void);
 void	noteret(void);
 uchar	nvramread(int);
 void	nvramwrite(int, uchar);
--- a/sys/src/9/pc64/squidboy.c
+++ b/sys/src/9/pc64/squidboy.c
@@ -8,8 +8,6 @@
 
 #include "mp.h"
 
-extern void checkmtrr(void);
-
 static void
 squidboy(Apic* apic)
 {
@@ -17,7 +15,6 @@
 	mmuinit();
 	cpuidentify();
 	cpuidprint();
-	checkmtrr();
 	apic->online = 1;
 	coherence();