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();