Extl2,
Extapm,
Extaddrsz,
-
- Paerange = 1LL << 36,
};
enum {
vlong base;
vlong mask;
};
-struct Mtrrop {
- Mtrreg *reg;
- int slot;
-};
static char *types[] = {
[Uncacheable] "uc",
[Writeback] "wb",
nil
};
-static Mtrrop *postedop;
-static Rendez oprend;
+
+static int dosync;
+static Mtrreg mtrreg[Nmtrr];
static char *
type2str(int type)
if(regs[0] >= Extaddrsz) { /* ax */
cpuid(Extaddrsz, regs);
mask = (1LL << (regs[0] & 0xFF)) - 1; /* ax */
+ } else {
+ mask &= (1LL << 36) - 1;
}
- mask &= Paerange - 1; /* x86 sanity */
return mask;
}
-/* limit physical addresses to 36 bits on the x86 */
-static void
-sanity(Mtrreg *mtrr)
-{
- mtrr->base &= Paerange - 1;
- mtrr->mask &= Paerange - 1;
-}
-
static int
ispow2(uvlong ul)
{
static int
mtrrdec(Mtrreg *mtrr, uvlong *ptr, uvlong *size, int *type)
{
- sanity(mtrr);
*ptr = mtrr->base & ~(BY2PG-1);
*type = mtrr->base & 0xff;
*size = (physmask() ^ (mtrr->mask & ~(BY2PG-1))) + 1;
{
mtrr->base = ptr | (type & 0xff);
mtrr->mask = (physmask() & ~(size - 1)) | (ok? 1<<11: 0);
- sanity(mtrr);
}
/*
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);
}
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 long bar1, bar2;
- s = splhi(); /* avoid race with mtrrclock */
-
- /*
- * wait for all CPUs to sync here, so that the MTRR setup gets
- * done at roughly the same time on all processors.
- */
- _xinc(&bar1);
- while(bar1 < conf.nmach)
- microdelay(10);
+ s = splhi();
cr4 = getcr4();
putcr4(cr4 & ~CR4PageGlobalEnable);
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);
putcr0(cr0);
putcr4(cr4);
- /*
- * wait for all CPUs to sync up again, so that we don't continue
- * executing while the MTRRs are still being set up.
- */
- _xinc(&bar2);
- while(bar2 < conf.nmach)
- microdelay(10);
- *op = nil;
- _xdec(&bar1);
- while(bar1 > 0)
- microdelay(10);
- _xdec(&bar2);
- wakeup(&oprend);
splx(s);
}
void
mtrrclock(void) /* called from clock interrupt */
{
- if(postedop != nil)
- mtrrop(&postedop);
-}
+ static Ref bar1, bar2;
+ int s;
-/* if there's an operation still pending, keep sleeping */
-static int
-opavail(void *)
-{
- return postedop == nil;
+ 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.
+ */
+ incref(&bar2);
+ while(bar2.ref < conf.nmach)
+ microdelay(10);
+ decref(&bar1);
+ while(bar1.ref > 0)
+ microdelay(10);
+ decref(&bar2);
+
+ dosync = 0;
+ splx(s);
}
-int
-mtrr(uvlong base, uvlong size, char *tstr)
+static char*
+mtrr0(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");
- if(base + size >= Paerange)
- error("mtrr range exceeds 36 bits");
+ return "mtrr base or size not 4k aligned or zero size";
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);
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:
break;
}
- qlock(&mtrrlk);
+ 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);
- /* reuse any entry for addresses above 4GB */
- if(!mok || mp == base && msize == size || mp >= (1LL<<32)){
+ 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){
slot = i;
break;
}
}
if(slot == -1)
- error("no free mtrr slots");
-
- while(postedop != nil)
- sleep(&oprend, opavail, 0);
- mtrrenc(&entry, base, size, type, 1);
- op.reg = &entry;
- op.slot = slot;
- postedop = &op;
- mtrrop(&postedop);
+ return "no free mtrr slots";
+
+ mtrrenc(&mtrreg[slot], base, size, type, 1);
+
+ 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);
- 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))
}
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();
+}