]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/mtrr.c
pc/ether*: use 64-bit physical addresses and check pci membar types and sizes
[plan9front.git] / sys / src / 9 / pc / mtrr.c
index b40bf0de61bba3bb37562e6340bf81098d477113..4b1558bfeeebf1b3015c3b13a10d07ffd28df614 100644 (file)
@@ -34,8 +34,6 @@ enum {
        Extl2,
        Extapm,
        Extaddrsz,
-
-       Paerange = 1LL << 36,
 };
 
 enum {
@@ -69,10 +67,6 @@ struct Mtrreg {
        vlong   base;
        vlong   mask;
 };
-struct Mtrrop {
-       Mtrreg  *reg;
-       int     slot;
-};
 
 static char *types[] = {
 [Uncacheable]  "uc",
@@ -84,8 +78,9 @@ static char *types[] = {
 [Writeback]    "wb",
                nil
 };
-static Mtrrop *postedop;
-static Rendez oprend;
+
+static int dosync;
+static Mtrreg mtrreg[Nmtrr];
 
 static char *
 type2str(int type)
@@ -118,19 +113,12 @@ physmask(void)
        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)
 {
@@ -141,7 +129,6 @@ 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;
@@ -153,7 +140,6 @@ mtrrenc(Mtrreg *mtrr, uvlong ptr, uvlong size, int type, int ok)
 {
        mtrr->base = ptr | (type & 0xff);
        mtrr->mask = (physmask() & ~(size - 1)) | (ok? 1<<11: 0);
-       sanity(mtrr);
 }
 
 /*
@@ -163,40 +149,49 @@ mtrrenc(Mtrreg *mtrr, uvlong ptr, uvlong size, int type, int ok)
 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);
@@ -207,78 +202,83 @@ mtrrop(Mtrrop **op)
        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:
@@ -287,53 +287,58 @@ mtrr(uvlong base, uvlong size, char *tstr)
                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))
@@ -343,3 +348,28 @@ mtrrprint(char *buf, long bufsize)
        }
        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();
+}