M pc/devvga.c => pc/devvga.c +8 -1
@@ 354,9 354,16 @@ vgactl(char *arg)
if(mem == 0)
error("not enough free address space");
+ /*
+ * Be very careful here, upamalloc now returns a
+ * PHYSICAL address. This won't work once devices
+ * start mapping PCI framebuffers at the address
+ * the BIOS sets, but that hopefully will be after
+ * conversion to the Draw kernel.
+ */
if(screenmem != SCREENMEM)
upafree(screenmem, footprint);
- screenmem = mem;
+ screenmem = (ulong)KADDR(mem);
gscreen.base = (void*)screenmem;
footprint = size;
for(n = 0; n < 31; n++)
M pc/ether79c970.c => pc/ether79c970.c +15 -21
@@ 427,25 427,14 @@ amd79c970adapter(Block** bpp, int port, int irq, int tbdf)
*bpp = bp;
}
-static int
-amd79c90(Ether* ether)
+static void
+amd79c970pci(void)
{
- static Pcidev *p;
- int irq, port;
-
- while(p = pcimatch(p, 0x1022, 0x2000)){
- port = p->bar[0] & ~0x01;
- irq = p->intl;
- if(ether->port == 0 || ether->port == port){
- ether->irq = irq;
- ether->tbdf = p->tbdf;
- return port;
- }
-
- amd79c970adapter(&adapter, port, irq, p->tbdf);
- }
+ Pcidev *p;
- return 0;
+ p = nil;
+ while(p = pcimatch(p, 0x1022, 0x2000))
+ amd79c970adapter(&adapter, p->mem[0].bar & ~0x01, p->intl, p->tbdf);
}
static int
@@ 456,11 445,16 @@ reset(Ether* ether)
Adapter *ap;
uchar ea[Eaddrlen];
Ctlr *ctlr;
+ static int scandone;
+
+ if(scandone == 0){
+ amd79c970pci();
+ scandone = 1;
+ }
/*
- * Any adapter matches if no ether->port is supplied, otherwise the
- * ports must match. First see if an adapter that fits the bill has
- * already been found. If not, scan for another.
+ * Any adapter matches if no port is supplied,
+ * otherwise the ports must match.
*/
port = 0;
bpp = &adapter;
@@ 476,7 470,7 @@ reset(Ether* ether)
}
bpp = &bp->next;
}
- if(port == 0 && (port = amd79c90(ether)) == 0)
+ if(port == 0)
return -1;
/*
M pc/ether82557.c => pc/ether82557.c +4 -2
@@ 255,12 255,14 @@ command(Ctlr* ctlr, int c, int v)
* Only back-to-back CUresume can be done
* without waiting for any previous command to complete.
* This should be the common case.
- */
+ * Unfortunately there's a chip errata where back-to-back
+ * CUresumes can be lost, the fix is to always wait.
if(c == CUresume && ctlr->command == CUresume){
csr8w(ctlr, CommandR, c);
iunlock(&ctlr->rlock);
return;
}
+ */
while(csr8r(ctlr, CommandR))
;
@@ 757,7 759,7 @@ i82557pci(void)
* bar[1] is the I/O port register address (32 bytes) and
* bar[2] is for the flash ROM (1MB).
*/
- i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf);
+ i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf);
}
}
M pc/etherelnk3.c => pc/etherelnk3.c +1 -1
@@ 1335,7 1335,7 @@ tcm59Xpci(void)
p = nil;
while(p = pcimatch(p, 0x10B7, 0)){
- port = p->bar[0] & ~0x01;
+ port = p->mem[0].bar & ~0x01;
irq = p->intl;
COMMAND(port, GlobalReset, 0);
while(STATUS(port) & commandInProgress)
M pc/fns.h => pc/fns.h +4 -0
@@ 57,6 57,8 @@ void mathinit(void);
#define mmuflushtlb(pdb) putcr3(pdb)
void meminit(ulong);
void mmuinit(void);
+ulong mmukmap(ulong, ulong, int);
+int mmukmapsync(ulong);
#define mmunewpage(x)
ulong* mmuwalk(ulong*, ulong, int);
void ns16552install(void);
@@ 69,12 71,14 @@ void outs(int, ushort);
void outss(int, void*, int);
void outl(int, ulong);
void outsl(int, void*, int);
+ulong pcibarsize(Pcidev*, int);
int pcicfgr8(Pcidev*, int);
int pcicfgr16(Pcidev*, int);
int pcicfgr32(Pcidev*, int);
void pcicfgw8(Pcidev*, int, int);
void pcicfgw16(Pcidev*, int, int);
void pcicfgw32(Pcidev*, int, int);
+void pcihinv(Pcidev*);
Pcidev* pcimatch(Pcidev*, int, int);
void pcireset(void);
PCMmap* pcmmap(int, ulong, int, int);
M pc/io.h => pc/io.h +12 -3
@@ 131,11 131,20 @@ typedef struct Pcidev {
int tbdf; /* type+bus+device+function */
ushort vid; /* vendor ID */
ushort did; /* device ID */
- ulong bar[2]; /* base address */
+
+ struct {
+ ulong bar; /* base address */
+ int size;
+ } mem[3];
+
uchar intl; /* interrupt line */
+ ushort ccru;
- Pcidev* next; /* next device on this bno */
-} Pcidev;
+
+ Pcidev* list;
+ Pcidev* bridge; /* down a bus */
+ Pcidev* link; /* next device on this bno */
+};
/*
* PCMCIA support code.
M pc/memory.c => pc/memory.c +27 -50
@@ 99,7 99,7 @@ dumpmembank(void)
#endif /* notdef */
void
-mapfree(RMap* rmap, ulong addr, int size)
+mapfree(RMap* rmap, ulong addr, ulong size)
{
Map *mp;
ulong t;
@@ 256,7 256,7 @@ ramscan(ulong maxmem)
* the BIOS data area.
*/
x = PADDR(CPU0MACH+BY2PG);
- bda = (uchar*)(KZERO|0x400);
+ bda = (uchar*)KADDR(0x400);
mapfree(&rmapram, x, ((bda[0x14]<<8)|bda[0x13])*KB-x);
x = PADDR(PGROUND((ulong)end));
@@ 290,7 290,7 @@ ramscan(ulong maxmem)
* be written and read correctly. The page tables are created here
* on the fly, allocating from low memory as necessary.
*/
- k0 = (ulong*)KZERO;
+ k0 = (ulong*)KADDR(0);
kzero = *k0;
map = 0;
x = 0x12345678;
@@ 383,47 383,11 @@ ramscan(ulong maxmem)
mapfree(&rmapram, map, BY2PG);
if(pa < maxmem)
mapfree(&rmapupa, pa, maxmem-pa);
+ if(maxmem < 0xFEC00000)
+ mapfree(&rmapupa, maxmem, 0xFEC00000-maxmem);
*k0 = kzero;
}
-static void
-upainit(void)
-{
- ulong addr, pa, pae, *table, *va, x;
-
- /*
- * Allocate an 8MB chunk aligned to 16MB. Later can
- * make the region selectable via conf if necessary.
- */
- if((addr = mapalloc(&rmapupa, 0, 8*MB, 16*MB)) == 0)
- return;
-
- pa = addr;
- pae = pa+(8*MB);
- while(pa < pae){
- va = KADDR(pa);
- table = &((ulong*)m->pdb)[PDX(va)];
- if((pa % (4*MB)) == 0 && (m->cpuiddx & 0x08)){
- *table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
- pa += (4*MB);
- }
- else{
- if(*table == 0){
- if((x = mapalloc(&rmapram, 0, BY2PG, BY2PG)) == 0)
- break;
- memset(KADDR(x), 0, BY2PG);
- *table = x|PTEWRITE|PTEVALID;
- }
- table = (ulong*)(KZERO|PPN(*table));
- table[PTX(va)] = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
- pa += BY2PG;
- }
- }
-
- mapfree(&xrmapupa, addr, pa-addr);
-}
-
-
void
meminit(ulong maxmem)
{
@@ 448,7 412,6 @@ meminit(ulong maxmem)
umbscan();
ramscan(maxmem);
- upainit();
/*
* Set the conf entries describing two banks of allocatable memory.
@@ 477,7 440,7 @@ umbmalloc(ulong addr, int size, int align)
ulong a;
if(a = mapalloc(&rmapumb, addr, size, align))
- return KZERO|a;
+ return (ulong)KADDR(a);
return 0;
}
@@ 485,7 448,7 @@ umbmalloc(ulong addr, int size, int align)
void
umbfree(ulong addr, int size)
{
- mapfree(&rmapumb, addr & ~KZERO, size);
+ mapfree(&rmapumb, PADDR(addr), size);
}
ulong
@@ 495,7 458,7 @@ umbrwmalloc(ulong addr, int size, int align)
uchar *p;
if(a = mapalloc(&rmapumbrw, addr, size, align))
- return KZERO|a;
+ return(ulong)KADDR(a);
/*
* Perhaps the memory wasn't visible before
@@ 516,22 479,36 @@ umbrwmalloc(ulong addr, int size, int align)
void
umbrwfree(ulong addr, int size)
{
- mapfree(&rmapumbrw, addr & ~KZERO, size);
+ mapfree(&rmapumbrw, PADDR(addr), size);
}
ulong
upamalloc(ulong addr, int size, int align)
{
- ulong a;
+ ulong a, ae;
if(a = mapalloc(&xrmapupa, addr, size, align))
- return KZERO|a;
+ return (ulong)KADDR(a);
- return 0;
+ if((a = mapalloc(&rmapupa, addr, size, align)) == 0)
+ return 0;
+
+ ae = mmukmap(a, 0, size);
+
+ /*
+ * Should check here that it was all delivered
+ * and put it back and barf if not.
+ */
+ USED(ae);
+
+ /*
+ * Be very careful this returns a PHYSICAL address.
+ */
+ return a;
}
void
upafree(ulong addr, int size)
{
- mapfree(&xrmapupa, addr & ~KZERO, size);
+ mapfree(&xrmapupa, addr, size);
}
M pc/mmu.c => pc/mmu.c +97 -26
@@ 23,8 23,6 @@ Segdesc gdt[6] =
#define PDX(va) ((((ulong)(va))>>22) & 0x03FF)
#define PTX(va) ((((ulong)(va))>>12) & 0x03FF)
-static int ptebits = 0;
-
static void
taskswitch(ulong pagetbl, ulong stack)
{
@@ 71,23 69,6 @@ mmuinit(void)
ltr(TSSSEL);
}
-ulong*
-mmuwalk(ulong *pdb, ulong va, int create)
-{
- ulong *table, x;
-
- table = &pdb[PDX(va)];
- if(*table == 0){
- if(create == 0)
- return 0;
- x = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0));
- *table = x|ptebits|PTEWRITE|PTEVALID;
- }
- table = (ulong*)(KZERO|PPN(*table));
- va = PTX(va);
- return &table[va];
-}
-
void
flushmmu(void)
{
@@ 100,7 81,7 @@ flushmmu(void)
}
static void
-mmuptefree(Proc *p)
+mmuptefree(Proc* p)
{
ulong *pdb;
Page **lpg, *pg;
@@ 119,7 100,7 @@ mmuptefree(Proc *p)
}
void
-mmuswitch(Proc *p)
+mmuswitch(Proc* p)
{
ulong *top;
@@ 138,7 119,7 @@ mmuswitch(Proc *p)
}
void
-mmurelease(Proc *p)
+mmurelease(Proc* p)
{
Page *pg, *next;
@@ 216,7 197,7 @@ mmupdballoc(void)
}
void
-putmmu(ulong va, ulong pa, Page *pg)
+putmmu(ulong va, ulong pa, Page* pg)
{
int pdbx;
ulong *pdb, *pt;
@@ 237,17 218,107 @@ putmmu(ulong va, ulong pa, Page *pg)
up->mmufree = pg->next;
memset((void*)pg->va, 0, BY2PG);
}
- pdb[pdbx] = PPN(pg->pa)|ptebits|PTEUSER|PTEWRITE|PTEVALID;
+ pdb[pdbx] = PPN(pg->pa)|PTEUSER|PTEWRITE|PTEVALID;
pg->daddr = pdbx;
pg->next = up->mmuused;
up->mmuused = pg;
}
pt = (ulong*)(PPN(pdb[pdbx])|KZERO);
- pt[PTX(va)] = pa|ptebits|PTEUSER;
+ pt[PTX(va)] = pa|PTEUSER;
s = splhi();
pdb[PDX(MACHADDR)] = ((ulong*)m->pdb)[PDX(MACHADDR)];
- putcr3(up->mmupdb->pa);
+ mmuflushtlb(up->mmupdb->pa);
splx(s);
}
+
+ulong*
+mmuwalk(ulong* pdb, ulong va, int create)
+{
+ ulong pa, *table;
+
+ table = &pdb[PDX(va)];
+ if(*table == 0){
+ if(create == 0)
+ return 0;
+ pa = PADDR((ulong)xspanalloc(BY2PG, BY2PG, 0));
+ *table = pa|PTEWRITE|PTEVALID;
+ }
+ if(*table & PTESIZE)
+ return table;
+
+ table = (ulong*)(KZERO|PPN(*table));
+ va = PTX(va);
+
+ return &table[va];
+}
+
+static Lock mmukmaplock;
+
+int
+mmukmapsync(ulong va)
+{
+ Mach *mach0;
+ ulong entry;
+
+ mach0 = MACHP(0);
+
+ lock(&mmukmaplock);
+
+ if(mmuwalk(mach0->pdb, va, 0) == nil){
+ unlock(&mmukmaplock);
+ return 0;
+ }
+ entry = ((ulong*)mach0->pdb)[PDX(va)];
+
+ if(!(((ulong*)m->pdb)[PDX(va)] & PTEVALID))
+ ((ulong*)m->pdb)[PDX(va)] = entry;
+
+ if(up && up->mmupdb){
+ ((ulong*)up->mmupdb->va)[PDX(va)] = entry;
+ mmuflushtlb(up->mmupdb->pa);
+ }
+ else
+ mmuflushtlb(PADDR(m->pdb));
+
+ unlock(&mmukmaplock);
+
+ return 1;
+}
+
+ulong
+mmukmap(ulong pa, ulong va, int size)
+{
+ Mach *mach0;
+ ulong ova, pae, *table, pgsz, *pte;
+
+ pa &= ~(BY2PG-1);
+ if(va == 0)
+ va = (ulong)KADDR(pa);
+ va &= ~(BY2PG-1);
+ ova = va;
+
+ pae = pa + size;
+ mach0 = MACHP(0);
+ lock(&mmukmaplock);
+ while(pa < pae){
+ table = &((ulong*)mach0->pdb)[PDX(va)];
+ if((pa % (4*MB)) == 0 && (mach0->cpuiddx & 0x08)){
+ *table = pa|PTESIZE|PTEWRITE|PTEUNCACHED|PTEVALID;
+ pgsz = 4*MB;
+ }
+ else{
+ pte = mmuwalk(mach0->pdb, va, 1);
+ *pte = pa|PTEWRITE|PTEUNCACHED|PTEVALID;
+ pgsz = BY2PG;
+ }
+ pa += pgsz;
+ va += pgsz;
+ }
+ unlock(&mmukmaplock);
+
+ mmukmapsync(ova);
+
+ return pa;
+}
M pc/pci.c => pc/pci.c +97 -50
@@ 28,6 28,7 @@ static Lock pcicfginitlock;
static int pcicfgmode = -1;
static int pcimaxdno;
static Pcidev* pciroot;
+static Pcidev* pcilist;
static int pcicfgrw8(int, int, int, int);
static int pcicfgrw16(int, int, int, int);
@@ 36,11 37,13 @@ static int pcicfgrw32(int, int, int, int);
static int
pciscan(int bno, Pcidev** list)
{
+ ulong v;
Pcidev *p, *head, *tail;
- int dno, fno, l, maxfno, maxubn, sbn, tbdf, ubn;
+ int dno, fno, i, l, maxfno, maxubn, rno, sbn, tbdf, ubn;
maxubn = bno;
- head = tail = 0;
+ head = nil;
+ tail = nil;
for(dno = 0; dno <= pcimaxdno; dno++){
maxfno = 0;
for(fno = 0; fno <= maxfno; fno++){
@@ 59,30 62,30 @@ pciscan(int bno, Pcidev** list)
p->tbdf = tbdf;
p->vid = l;
p->did = l>>16;
- p->bar[0] = pcicfgrw32(tbdf, PciBAR0, 0, 1);
- p->bar[1] = pcicfgrw32(tbdf, PciBAR1, 0, 1);
- p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1);
+ p->list = pcilist;
+ pcilist = p;
- /*
- * Read the base and sub- class and if the device is
- * a bridge put it on a list of buses to be descended
- * later.
- * If it's not a bridge just add it to the tail of the
- * device list.
- */
- l = pcicfgrw16(tbdf, PciCCRu, 0, 1);
- if(l == ((0x06<<8)|0x04)){
- if(head)
- tail->next = p;
- else
- head = p;
- tail = p;
- }
- else{
- *list = p;
- list = &p->next;
+ p->intl = pcicfgrw8(tbdf, PciINTL, 0, 1);
+ p->ccru = pcicfgrw16(tbdf, PciCCRu, 0, 1);
+
+ rno = PciBAR0 - 4;
+ for(i = 0; i < nelem(p->mem); i++) {
+ rno += 4;
+ p->mem[i].bar = pcicfgrw32(tbdf, rno, 0, 1);
+ if(i > 0 && p->ccru == ((0x06<<8)|0x04))
+ continue;
+ pcicfgrw32(tbdf, rno, -1, 0);
+ v = pcicfgrw32(tbdf, rno, 0, 1);
+ pcicfgrw32(tbdf, rno, p->mem[i].bar, 0);
+ p->mem[i].size = -(v & ~0xF);
}
+ if(head != nil)
+ tail->link = p;
+ else
+ head = p;
+ tail = p;
+
/*
* If the device is a multi-function device adjust the
* loop count so all possible functions are checked.
@@ 93,20 96,25 @@ pciscan(int bno, Pcidev** list)
}
}
- /*
- * If any bridges were found, recursively descend the tree.
- * The end result will be a single list of all devices in ascending
- * bus number order.
- */
- for(p = head; p; p = head){
+ *list = head;
+ for(p = head; p != nil; p = p->link){
/*
- * Take the primary bridge device off the bridge list
- * and link to the end of the final device list.
+ * Find bridges and recursively descend the tree.
+ * Special case the Intel 82454GX Host-to-PCI bridge,
+ * there can be two of them.
+ * Otherwise, only descend PCI-to-PCI bridges.
*/
- head = p->next;
- p->next = 0;
- *list = p;
- list = &p->next;
+ if(p->ccru == ((0x06<<8)|0) && p->vid == 0x8086 && p->did == 0x84C4){
+ tbdf = p->tbdf;
+ if((sbn = pcicfgrw8(tbdf, 0x4A, 0, 1)) == 0)
+ continue;
+ ubn = pcicfgrw8(tbdf, 0x4B, 0, 1);
+ maxubn = ubn;
+ pciscan(sbn, &p->bridge);
+ continue;
+ }
+ if(p->ccru != ((0x06<<8)|0x04))
+ continue;
/*
* If the secondary or subordinate bus number is not initialised
@@ 133,13 141,13 @@ pciscan(int bno, Pcidev** list)
l = (MaxUBN<<16)|(sbn<<8)|bno;
pcicfgrw32(tbdf, PciPBN, l, 0);
pcicfgrw16(tbdf, PciSPSR, 0xFFFF, 0);
- maxubn = pciscan(sbn, list);
+ maxubn = pciscan(sbn, &p->bridge);
l = (maxubn<<16)|(sbn<<8)|bno;
pcicfgrw32(tbdf, PciPBN, l, 0);
}
else{
maxubn = ubn;
- pciscan(sbn, list);
+ pciscan(sbn, &p->bridge);
}
}
@@ 348,27 356,36 @@ pcicfgw32(Pcidev* pcidev, int rno, int data)
pcicfgrw32(pcidev->tbdf, rno, data, 0);
}
-Pcidev*
-pcimatch(Pcidev* previous, int vid, int did)
+ulong
+pcibarsize(Pcidev* p, int rno)
{
- Pcidev *p;
+ ulong v, size;
+ v = pcicfgrw32(p->tbdf, rno, 0, 1);
+ pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0);
+ size = pcicfgrw32(p->tbdf, rno, 0, 1);
+ pcicfgrw32(p->tbdf, rno, v, 0);
+
+ return -(size & ~0x0F);
+}
+
+Pcidev*
+pcimatch(Pcidev* prev, int vid, int did)
+{
if(pcicfgmode == -1)
pcicfginit();
- if(previous == 0)
- previous = pciroot;
+ if(prev == nil)
+ prev = pcilist;
else
- previous = previous->next;
+ prev = prev->list;
- for(p = previous; p; p = p->next) {
- if(p->vid != vid)
- continue;
- if(did == 0 || p->did == did)
+ while(prev != nil) {
+ if(prev->vid == vid && (did == 0 || prev->did == did))
break;
+ prev = prev->list;
}
-
- return p;
+ return prev;
}
void
@@ 380,12 397,42 @@ pcireset(void)
if(pcicfgmode == -1)
pcicfginit();
- for(p = pciroot; p; p = p->next){
+ for(p = pcilist; p != nil; p = p->list){
pcr = pcicfgr16(p, PciPSR);
pcicfgw16(p, PciPSR, pcr & ~0x04);
}
}
+void
+pcihinv(Pcidev* p)
+{
+ int i;
+ Pcidev *t;
+
+ if(p == nil) {
+ p = pciroot;
+ print("bus dev type vid did memory\n");
+ }
+ for(t = p; t != nil; t = t->link) {
+ print("%d %2d/%d %.4ux %.4ux %.4ux ",
+ BUSBNO(t->tbdf), BUSDNO(t->tbdf), BUSFNO(t->tbdf),
+ t->ccru, t->vid, t->did);
+
+ for(i = 0; i < nelem(p->mem); i++) {
+ if(t->mem[i].size == 0)
+ continue;
+ print("%d:%.8lux %d ", i,
+ t->mem[i].bar, t->mem[i].size);
+ }
+ print("\n");
+ }
+ while(p != nil) {
+ if(p->bridge != nil)
+ pcihinv(p->bridge);
+ p = p->link;
+ }
+}
+
/*
* Hack for now to get SYMBIOS controller on-line.
*/
M pc/trap.c => pc/trap.c +4 -2
@@ 295,8 295,10 @@ fault386(Ureg* ureg, void*)
postnote(up, 1, buf, NDebug);
return;
}
- dumpregs(ureg);
- panic("fault: 0x%lux\n", addr);
+ if(mmukmapsync(addr) == 0){
+ dumpregs(ureg);
+ panic("fault: 0x%lux\n", addr);
+ }
}
up->insyscall = insyscall;
}