From b4ab588719514adc812c17357e29c0122bad8143 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 11 Oct 1997 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1997-10-11 --- pc/devvga.c | 9 ++- pc/ether79c970.c | 36 +++++------- pc/ether82557.c | 6 +- pc/etherelnk3.c | 2 +- pc/fns.h | 4 ++ pc/io.h | 15 ++++- pc/memory.c | 77 +++++++++---------------- pc/mmu.c | 123 ++++++++++++++++++++++++++++++--------- pc/pci.c | 147 +++++++++++++++++++++++++++++++---------------- pc/trap.c | 6 +- 10 files changed, 269 insertions(+), 156 deletions(-) diff --git a/pc/devvga.c b/pc/devvga.c index 183dd282b99723c66ecd600fe829b0fd02b79ef6..44188f7b8aeb1cf059539ad60f6d7d53739c3cfd 100644 --- a/pc/devvga.c +++ b/pc/devvga.c @@ -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++) diff --git a/pc/ether79c970.c b/pc/ether79c970.c index 7c6a9efb9b4b12425af249ca7f48e5e96a66f725..741bfa8692010d355fe09edeb3a7fefb033d497c 100644 --- a/pc/ether79c970.c +++ b/pc/ether79c970.c @@ -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; /* diff --git a/pc/ether82557.c b/pc/ether82557.c index d0213b0f4e07e6ccc2247efd2f3909210d4e6a9a..6ea8408c959da87522860043372da855ed831c00 100644 --- a/pc/ether82557.c +++ b/pc/ether82557.c @@ -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); } } diff --git a/pc/etherelnk3.c b/pc/etherelnk3.c index e005ab04f6a5c0ee69eeff81bc21367fbfab4fc8..9e0b87b3373e07f2a7bced0762f447f10dd7572f 100644 --- a/pc/etherelnk3.c +++ b/pc/etherelnk3.c @@ -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) diff --git a/pc/fns.h b/pc/fns.h index fc14e34db24d9fc456eee8fc960cee5b6fd4e9ce..fd3ec63e121769af1dddac453d0092f2cc52b4d8 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -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); diff --git a/pc/io.h b/pc/io.h index 9b5312b255e6e232eba9aa95cff3943bbe9a6da6..a541313483124c4eb47ffd87ade6f9346be97c3e 100644 --- a/pc/io.h +++ b/pc/io.h @@ -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. diff --git a/pc/memory.c b/pc/memory.c index 445e23d43e9bb18a2dd5d450b3a7ef5228f2a0e9..fe65979c8594e056cff5538d6b1586d4c4cbc937 100644 --- a/pc/memory.c +++ b/pc/memory.c @@ -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); } diff --git a/pc/mmu.c b/pc/mmu.c index 2e9f79a2f93d426add9031958b60a141a2727be3..58c47c354ef03b93de7bdc2cfd41c93d5184a374 100644 --- a/pc/mmu.c +++ b/pc/mmu.c @@ -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; +} diff --git a/pc/pci.c b/pc/pci.c index e8e31ffb653b696b982cc01ac5f5140d173877d5..d0bc2f123be417866643e98039dd3685984e5bda 100644 --- a/pc/pci.c +++ b/pc/pci.c @@ -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. */ diff --git a/pc/trap.c b/pc/trap.c index e7a28619c0d50577770967770c032533b6097966..9dfc62a13a5665a3c1bd4410911cbd0f14ae5e09 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -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; }