## diffname pc/pci.c 1995/0517 ## diff -e /dev/null /n/fornaxdump/1995/0517/sys/src/brazil/pc/pci.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" static Lock pcicfglock; /* * Read a chunk of PCI configuration space. * Assumes arguments are within limits and regno and * nbytes are DWORD aligned. */ void pcicfgr(uchar busno, uchar devno, uchar funcno, uchar regno, void* data, int nbytes) { ulong base, *p; int len; lock(&pcicfglock); outb(PCIcse, 0x80|((funcno & 0x07)<<1)); outb(PCIforward, busno); base = (0xC000|(devno<<8)) + regno; p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ *p = inl(base); p++; base += sizeof(ulong); } outb(PCIcse, 0x00); unlock(&pcicfglock); } int pcimatch(uchar busno, uchar devno, PCIcfg* pcicfg) { ulong l; l = 0; pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong)); if((l & 0xFFFF) != pcicfg->vid) return 0; if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did) return 0; pcicfgr(busno, devno, 0, 0, pcicfg, sizeof(PCIcfg)); return 1; } . ## diffname pc/pci.c 1995/0721 ## diff -e /n/fornaxdump/1995/0517/sys/src/brazil/pc/pci.c /n/fornaxdump/1995/0721/sys/src/brazil/pc/pci.c 43,51c while(devno < MaxPCI){ l = 0; pcicfgr(busno, devno, 0, 0, &l, sizeof(ulong)); devno++; if((l & 0xFFFF) != pcicfg->vid) continue; if(pcicfg->did && ((l>>16) & 0xFFFF) != pcicfg->did) continue; pcicfgr(busno, devno-1, 0, 0, pcicfg, sizeof(PCIcfg)); return devno; } return -1; . 39c pcimatch(int busno, int devno, PCIcfg* pcicfg) . 37a void pcicfgw(int busno, int devno, int funcno, int regno, void* data, int nbytes) { ulong* p; int base, len; lock(&pcicfglock); outb(PCIcse, 0x80|((funcno & 0x07)<<1)); outb(PCIforward, busno); base = (0xC000|(devno<<8)) + regno; p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ outl(base, *p); p++; base += sizeof(*p); } outb(PCIcse, 0x00); unlock(&pcicfglock); } . 31c base += sizeof(*p); . 19,20c ulong* p; int base, len; . 17c pcicfgr(int busno, int devno, int funcno, int regno, void* data, int nbytes) . ## diffname pc/pci.c 1995/0725 ## diff -e /n/fornaxdump/1995/0721/sys/src/brazil/pc/pci.c /n/fornaxdump/1995/0725/sys/src/brazil/pc/pci.c 56d 48,53c switch(pcicfgmode){ case 1: addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ outl(PCIaddr, addr|(regno & 0xFF)); outl(PCIdata, *p); p++; regno += sizeof(ulong); } outl(PCIaddr, 0); break; case 2: outb(PCIcse, 0x80|((funcno & 0x07)<<1)); outb(PCIforward, busno); base = (0xC000|(devno<<8)) + regno; p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ outl(base, *p); p++; base += sizeof(*p); } outb(PCIcse, 0); . 45,46c if(pcicfgmode == -1) pcicfginit(busno); . 41c ulong addr, *p; . 34d 26,31c switch(pcicfgmode){ case 1: addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ outl(PCIaddr, addr|(regno & 0xFF)); *p = inl(PCIdata); p++; regno += sizeof(ulong); } outl(PCIaddr, 0); break; case 2: outb(PCIcse, 0x80|((funcno & 0x07)<<1)); outb(PCIforward, busno); base = (0xC000|(devno<<8)) + regno; p = data; for(len = nbytes/sizeof(ulong); len > 0; len--){ *p = inl(base); p++; base += sizeof(*p); } outb(PCIcse, 0); break; . 23,24c if(pcicfgmode == -1) pcicfginit(busno); . 19c ulong addr, *p; . 10a static int pcicfgmode = -1; static void pcicfginit(int) { /* * Try to determine which PCI configuration mode is implemented. * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses * a DWORD at 0xCF8 and another at 0xCFC and will pass through * any non-DWORD accesses as normal I/O cycles. There shouldn't be * a device behind theses addresses so if Mode2 accesses fail try * for Mode1 (which is preferred, Mode2 is deprecated). */ outb(PCIcse, 0); if(inb(PCIcse) == 0){ pcicfgmode = 2; return; } outl(PCIaddr, 0); if(inl(PCIaddr) == 0){ pcicfgmode = 1; return; } pcicfgmode = -1; } . 0a /* * Trivial PCI configuration code. * Only deals with bus 0, amongst other glaring omissions. */ . ## diffname pc/pci.c 1995/0726 ## diff -e /n/fornaxdump/1995/0725/sys/src/brazil/pc/pci.c /n/fornaxdump/1995/0726/sys/src/brazil/pc/pci.c 140a if(pcicfgmode == 2 && devno >= 16) break; . 139a lock(&pcicfglock); if(pcicfgmode == -1) pcicfginit(busno); unlock(&pcicfglock); . 117a if(devno >= 16) break; . 73a if(devno >= 16) break; . ## diffname pc/pci.c 1995/1206 ## diff -e /n/fornaxdump/1995/0726/sys/src/brazil/pc/pci.c /n/fornaxdump/1995/1206/sys/src/brazil/pc/pci.c 128a p++; base += sizeof(*p); } outb(PCIcse, 0); } unlock(&pcicfglock); } /* * This is not in the spec, but at least the CMD640B requires it. */ void pcicfgw8(int busno, int devno, int funcno, int regno, void* data, int nbytes) { uchar *p; int base, len; lock(&pcicfglock); if(pcicfgmode == -1) pcicfginit(busno); switch(pcicfgmode){ default: panic("pcicfgw8: pcicfgmode %d\n", pcicfgmode); break; case 2: if(devno >= 16) break; outb(PCIcse, 0x80|((funcno & 0x07)<<1)); outb(PCIforward, busno); base = (0xC000|(devno<<8)) + regno; p = data; for(len = nbytes/sizeof(*p); len > 0; len--){ outb(base, *p); . 127c for(len = nbytes/sizeof(*p); len > 0; len--){ . 113c regno += sizeof(*p); . 109c for(len = nbytes/sizeof(*p); len > 0; len--){ . ## diffname pc/pci.c 1996/0112 ## diff -e /n/fornaxdump/1995/1206/sys/src/brazil/pc/pci.c /n/fornaxdump/1996/0112/sys/src/brazil/pc/pci.c 155c addr = 0x80000000|((busno & 0xFF)<<16)|((devno & 0x1F)<<11)|((funcno & 0x03)<<8); p = data; for(len = nbytes/sizeof(*p); len > 0; len--){ outl(PCIaddr, addr|(regno & 0xFF)); outb(PCIdata, *p); p++; regno += sizeof(*p); } outl(PCIaddr, 0); break; . 144a ulong addr; . ## diffname pc/pci.c 1997/0327 ## diff -e /n/fornaxdump/1996/0112/sys/src/brazil/pc/pci.c /n/emeliedump/1997/0327/sys/src/brazil/pc/pci.c 212c return p; } void pcireset(void) { Pcidev *p; int pcr; if(pcicfgmode == -1) pcicfginit(); for(p = pciroot; p; p = p->next){ pcr = pcicfgr16(p, PciPSR); pcicfgw16(p, PciPSR, pcr & ~0x04); } } /* * Hack for now to get SYMBIOS controller on-line. */ void* pcimemmap(int tbdf, int rno, ulong *paddr) { long size; ulong p, v; if(pcicfgmode == -1) pcicfginit(); v = pcicfgrw32(tbdf, rno, 0, 1); if(v & 1){ print("pcimemmap: not a memory base register\n"); return 0; } if(v & 6){ print("pcimemmap: only 32 bit relocs supported\n"); return 0; } v = 0xFFFFFFFF; pcicfgrw32(tbdf, rno, v, 0); v = pcicfgrw32(tbdf, rno, 0, 1); /* clear out bottom bits and negate to find size */ size = -(v & ~0x0F); v = umbmalloc(0, size, size); print("rno %uX, size %uX, v %uX\n", rno, size, v); p = PADDR(v); if(paddr) *paddr = p; pcicfgrw32(tbdf, rno, p, 0); return (void*)v; . 207,210c if(did == 0 || p->did == did) break; . 199,205c if(previous == 0) previous = pciroot; else previous = previous->next; for(p = previous; p; p = p->next){ if(p->vid != vid) . 196,197c pcicfginit(); . 194c void pcicfgw32(Pcidev* pcidev, int rno, int data) { pcicfgrw32(pcidev->tbdf, rno, data, 0); } Pcidev* pcimatch(Pcidev* previous, int vid, int did) { Pcidev *p; . 192c return pcicfgrw32(pcidev->tbdf, rno, 0, 1); } . 190c pcicfgr32(Pcidev* pcidev, int rno) . 186a return x; . 185d 170,183c outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); outb(PciFORWARD, BUSBNO(tbdf)); if(read) x = inl((0xC000|(BUSDNO(tbdf)<<8)) + rno); else outl((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); outb(PciCSE, 0); break; . 167d 155,165c case 1: rno &= ~0x03; outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); if(read) x = inl(PciDATA); else outl(PciDATA, data); outl(PciADDR, 0); . 152a if(BUSBNO(tbdf)) type = 0x01; else type = 0x00; x = -1; if(BUSDNO(tbdf) >= pcimaxdno) return x; lock(&pcicfglock); . 151c pcicfginit(); . 149c static int pcicfgrw32(int tbdf, int rno, int data, int read) { int type, x; . 145,147c pcicfgrw16(pcidev->tbdf, rno, data, 0); } . 143c pcicfgw16(Pcidev* pcidev, int rno, int data) . 139,141c int pcicfgr16(Pcidev* pcidev, int rno) { return pcicfgrw16(pcidev->tbdf, rno, 0, 1); } . 136a return x; . 135d 120,133c outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); outb(PciFORWARD, BUSBNO(tbdf)); if(read) x = ins((0xC000|(BUSDNO(tbdf)<<8)) + rno); else outs((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); outb(PciCSE, 0); break; . 107,116c o = rno & 0x02; rno &= ~0x03; outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); if(read) x = ins(PciDATA+o); else outs(PciDATA+o, data); outl(PciADDR, 0); . 103a if(BUSBNO(tbdf)) type = 0x01; else type = 0x00; x = -1; if(BUSDNO(tbdf) >= pcimaxdno) return x; lock(&pcicfglock); . 102c pcicfginit(); . 100c static int pcicfgrw16(int tbdf, int rno, int data, int read) { int o, type, x; . 97,98c pcicfgrw8(pcidev->tbdf, rno, data, 0); } . 95c pcicfgw8(Pcidev* pcidev, int rno, int data) . 93a int pcicfgr8(Pcidev* pcidev, int rno) { return pcicfgrw8(pcidev->tbdf, rno, 0, 1); } . 91a return x; . 90d 74,87c outb(PciCSE, 0x80|(BUSFNO(tbdf)<<1)); outb(PciFORWARD, BUSBNO(tbdf)); if(read) x = inb((0xC000|(BUSDNO(tbdf)<<8)) + rno); else outb((0xC000|(BUSDNO(tbdf)<<8)) + rno, data); outb(PciCSE, 0); . 61,70c o = rno & 0x03; rno &= ~0x03; outl(PciADDR, 0x80000000|BUSBDF(tbdf)|rno|type); if(read) x = inb(PciDATA+o); else outb(PciDATA+o, data); outl(PciADDR, 0); . 57a if(BUSBNO(tbdf)) type = 0x01; else type = 0x00; x = -1; if(BUSDNO(tbdf) >= pcimaxdno) return x; lock(&pcicfglock); . 56c pcicfginit(); . 54c static int pcicfgrw8(int tbdf, int rno, int data, int read) { int o, type, x; . 51,52c lock(&pcicfginitlock); if(pcicfgmode == -1){ /* * Try to determine which PCI configuration mode is implemented. * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses * a DWORD at 0xCF8 and another at 0xCFC and will pass through * any non-DWORD accesses as normal I/O cycles. There shouldn't be * a device behind theses addresses so if Mode2 accesses fail try * for Mode1 (which is preferred, Mode2 is deprecated). */ outb(PciCSE, 0); if(inb(PciCSE) == 0){ pcicfgmode = 2; pcimaxdno = 31; } else{ outl(PciADDR, 0); if(inl(PciADDR) == 0){ pcicfgmode = 1; pcimaxdno = 15; } } if(pcicfgmode > 0) pciscan(0, &pciroot); } unlock(&pcicfginitlock); } . 43,49c static void pcicfginit(void) . 40c return maxubn; . 34,37c /* * If the secondary or subordinate bus number is not initialised * try to do what the PCI BIOS should have done and fill in the * numbers as the tree is descended. On the way down the subordinate * bus number is set to the maximum as it's not known how many * buses are behind this one; the final value is set on the way * back up. */ tbdf = p->tbdf; sbn = pcicfgrw8(tbdf, PciSBN, 0, 1); ubn = pcicfgrw8(tbdf, PciUBN, 0, 1); if(sbn == 0 || ubn == 0){ sbn = maxubn+1; /* * Make sure memory, I/O and master enables are off, * set the primary, secondary and subordinate bus numbers * and clear the secondary status before attempting to * scan the secondary bus. * * Initialisation of the bridge should be done here. */ pcicfgrw32(tbdf, PciPCR, 0xFFFF0000, 0); l = (MaxUBN<<16)|(sbn<<8)|bno; pcicfgrw32(tbdf, PciPBN, l, 0); pcicfgrw16(tbdf, PciSPSR, 0xFFFF, 0); maxubn = pciscan(sbn, list); l = (maxubn<<16)|(sbn<<8)|bno; pcicfgrw32(tbdf, PciPBN, l, 0); } else{ maxubn = ubn; pciscan(sbn, list); } . 28,32c for(p = head; p; p = head){ /* * Take the primary bridge device off the bridge list * and link to the end of the final device list. */ head = p->next; p->next = 0; *list = p; list = &p->next; . 21,26c * 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. . 19a Pcidev *p, *head, *tail; int dno, fno, l, maxfno, maxubn, sbn, tbdf, ubn; maxubn = bno; head = tail = 0; for(dno = 0; dno < pcimaxdno; dno++){ maxfno = 0; for(fno = 0; fno <= maxfno; fno++){ /* * For this possible device, form the bus+device+function * triplet needed to address it and try to read the vendor * and device ID. If successful, allocate a device struct * and start to fill it in with some useful information from * the device's configuration space. */ tbdf = MKBUS(BusPCI, bno, dno, fno); l = pcicfgrw32(tbdf, PciVID, 0, 1); if(l == 0xFFFFFFFF || l == 0) continue; p = malloc(sizeof(*p)); 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); /* * 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; } /* * If the device is a multi-function device adjust the * loop count so all possible functions are checked. */ l = pcicfgrw8(tbdf, PciHDT, 0, 1); if(l & 0x80) maxfno = MaxFNO; } } . 17,18c static int pcicfgrw8(int, int, int, int); static int pcicfgrw16(int, int, int, int); static int pcicfgrw32(int, int, int, int); static int pciscan(int bno, Pcidev** list) . 15a static int pcimaxdno; static Pcidev* pciroot; . 14a /* configuration mechanism #2 */ PciCSE = 0xCF8, /* configuration space enable */ PciFORWARD = 0xCFA, /* which bus */ MaxFNO = 7, MaxUBN = 255, }; static Lock pcicfglock; static Lock pcicfginitlock; . 13c enum { /* configuration mechanism #1 */ PciADDR = 0xCF8, /* CONFIG_ADDRESS */ PciDATA = 0xCFC, /* CONFIG_DATA */ . 2,3c * PCI support code. * To do: * initialise bridge mappings if the PCI BIOS didn't. . ## diffname pc/pci.c 1997/0329 ## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/pci.c /n/emeliedump/1997/0329/sys/src/brazil/pc/pci.c 171c pcimaxdno = 31; . 165c pcimaxdno = 15; . ## diffname pc/pci.c 1997/0412 ## diff -e /n/emeliedump/1997/0329/sys/src/brazil/pc/pci.c /n/emeliedump/1997/0412/sys/src/brazil/pc/pci.c 308c if(BUSDNO(tbdf) > pcimaxdno) . 251c if(BUSDNO(tbdf) > pcimaxdno) . 194c if(BUSDNO(tbdf) > pcimaxdno) . 44c for(dno = 0; dno <= pcimaxdno; dno++){ . ## diffname pc/pci.c 1997/0711 ## diff -e /n/emeliedump/1997/0412/sys/src/brazil/pc/pci.c /n/emeliedump/1997/0711/sys/src/brazil/pc/pci.c 416d 413c /* * Clear out bottom bits and negate to find size. * If none can be found could try for UPA memory here. */ . ## diffname pc/pci.c 1997/0831 ## diff -e /n/emeliedump/1997/0711/sys/src/brazil/pc/pci.c /n/emeliedump/1997/0831/sys/src/brazil/pc/pci.c 364c for(p = previous; p; p = p->next) { . ## diffname pc/pci.c 1997/1011 ## diff -e /n/emeliedump/1997/0831/sys/src/brazil/pc/pci.c /n/emeliedump/1997/1011/sys/src/brazil/pc/pci.c 385a } } 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; . 383c for(p = pcilist; p != nil; p = p->list){ . 370,371c return prev; . 368a prev = prev->list; . 364,367c while(prev != nil) { if(prev->vid == vid && (did == 0 || prev->did == did)) . 362c prev = prev->list; . 359,360c if(prev == nil) prev = pcilist; . 355a 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) { . 354c ulong v, size; . 351,352c ulong pcibarsize(Pcidev* p, int rno) . 142c pciscan(sbn, &p->bridge); . 136c maxubn = pciscan(sbn, &p->bridge); . 106,109c 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; . 103,104c * 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. . 96,101c *list = head; for(p = head; p != nil; p = p->link){ . 85a if(head != nil) tail->link = p; else head = p; tail = p; . 81,84d 66,79c 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); . 64a p->ccru = pcicfgrw16(tbdf, PciCCRu, 0, 1); . 62,63c p->list = pcilist; pcilist = p; . 43c head = nil; tail = nil; . 40c int dno, fno, i, l, maxfno, maxubn, rno, sbn, tbdf, ubn; . 38a ulong v; . 30a static Pcidev* pcilist; . ## diffname pc/pci.c 1997/1101 ## diff -e /n/emeliedump/1997/1011/sys/src/brazil/pc/pci.c /n/emeliedump/1997/1101/sys/src/brazil/pc/pci.c 65,66c if(pcilist != nil) pcitail->list = p; else pcilist = p; pcitail = p; . 31a static Pcidev* pcitail; . ## diffname pc/pci.c 1998/0108 ## diff -e /n/emeliedump/1997/1101/sys/src/brazil/pc/pci.c /n/emeliedump/1998/0108/sys/src/brazil/pc/pci.c 475a } void pcireset(void) { Pcidev *p; int pcr; if(pcicfgmode == -1) pcicfginit(); for(p = pcilist; p != nil; p = p->list){ pcr = pcicfgr16(p, PciPSR); pcicfgw16(p, PciPSR, pcr & ~0x04); } . 424c t->ccru, t->vid, t->did, t->intl); . 422c print("%d %2d/%d %.4ux %.4ux %.4ux %d ", . 397,411d ## diffname pc/pci.c 1998/0312 ## diff -e /n/emeliedump/1998/0108/sys/src/brazil/pc/pci.c /n/emeliedump/1998/0312/sys/src/brazil/pc/pci.c 424,460d 364,376d 188,189c if(pcicfgmode > 0){ if(p = getconf("*pcimaxdno")) pcimaxdno = strtoul(p, 0, 0); list = &pciroot; for(bno = 0; bno < 256; bno++){ bno = pciscan(bno, list); while(*list && (*list)->link) list = &(*list)->link; } } . 172c * a device behind these addresses so if Mode2 accesses fail try . 164a char *p; int bno; Pcidev **list; . 151c pcicfgw32(p, PciPBN, l); . 147,148c pcicfgw32(p, PciPBN, l); pcicfgw16(p, PciSPSR, 0xFFFF); . 145c pcicfgw32(p, PciPCR, 0xFFFF0000); . 132,134c sbn = pcicfgr8(p, PciSBN); ubn = pcicfgr8(p, PciUBN); . 112,120d 107,110c * Find PCI-PCI bridges and recursively descend the tree. . 93,100d 76,85c /* * If the device is a multi-function device adjust the * loop count so all possible functions are checked. */ hdt = pcicfgr8(p, PciHDT); if(hdt & 0x80) maxfno = MaxFNO; /* * If appropriate, read the base address registers * and work out the sizes. */ switch(p->ccru>>8){ case 0x01: /* mass storage controller */ case 0x02: /* network controller */ case 0x03: /* display controller */ case 0x04: /* multimedia device */ case 0x07: /* simple communication controllers */ case 0x08: /* base system peripherals */ case 0x09: /* input devices */ case 0x0A: /* docking stations */ case 0x0B: /* processors */ case 0x0C: /* serial bus controllers */ if((hdt & 0x7F) != 0) break; rno = PciBAR0 - 4; for(i = 0; i < nelem(p->mem); i++){ rno += 4; p->mem[i].bar = pcicfgr32(p, rno); pcicfgw32(p, rno, -1); v = pcicfgr32(p, rno); pcicfgw32(p, rno, p->mem[i].bar); p->mem[i].size = -(v & ~0xF); } break; case 0x00: case 0x05: /* memory controller */ case 0x06: /* bridge device */ default: break; . 73,74c p->intl = pcicfgr8(p, PciINTL); p->ccru = pcicfgr16(p, PciCCRu); . 43c int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; . 34,35d ## diffname pc/pci.c 1998/0322 ## diff -e /n/emeliedump/1998/0312/sys/src/brazil/pc/pci.c /n/emeliedump/1998/0322/sys/src/brazil/pc/pci.c 417c print("%d %2d/%d %.4ux %.4ux %.4ux %2d ", . 414c print("bus dev type vid did intl memory\n"); . ## diffname pc/pci.c 1998/0324 ## diff -e /n/emeliedump/1998/0322/sys/src/brazil/pc/pci.c /n/emeliedump/1998/0324/sys/src/brazil/pc/pci.c 208c while(*list) . ## diffname pc/pci.c 1998/0906 ## diff -e /n/emeliedump/1998/0324/sys/src/brazil/pc/pci.c /n/emeliedump/1998/0906/sys/src/brazil/pc/pci.c 403a } Pcidev* pcimatchtbdf(int tbdf) { Pcidev *pcidev; if(pcicfgmode == -1) pcicfginit(); for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list){ if(pcidev->tbdf == tbdf) break; } return pcidev; . 398c while(prev != nil){ . ## diffname pc/pci.c 1998/1121 ## diff -e /n/emeliedump/1998/0906/sys/src/brazil/pc/pci.c /n/emeliedump/1998/1121/sys/src/brazil/pc/pci.c 399c if((vid == 0 || prev->vid == vid) && (did == 0 || prev->did == did)) . ## diffname pc/pci.c 1999/0301 ## diff -e /n/emeliedump/1998/1121/sys/src/brazil/pc/pci.c /n/emeliedump/1999/0301/sys/src/brazil/pc/pci.c 434c t->ccrb, t->ccru, t->ccrp, t->vid, t->did, t->intl); . 432c print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %2d ", . 414c for(pcidev = pcilist; pcidev != nil; pcidev = pcidev->list) { . 399c if((vid == 0 || prev->vid == vid) && (did == 0 || prev->did == did)) . 213a out: . 205,212c return; . 201,203c print("Sizes: mem=%lux io=%lux\n", mema, ioa); /* * Align the windows and map it */ size = pcimask(mema); mema = (0xFE000000 & ~(size-1)) - size; size = pcimask(ioa); ioa = (0xFE00 & ~(size-1)) - size; pcibusmap(pciroot, &mema, &ioa, 1); unlock(&pcicfginitlock); pcihinv(nil); . 188,199c mema = 0; ioa = 0; pcibusmap(pciroot, &mema, &ioa, 0); . 181,186c * Work out how big the top bus is . 179c if(pcicfgmode != -1) goto out; /* * Try to determine which PCI configuration mode is implemented. * Mode2 uses a byte at 0xCF8 and another at 0xCFA; Mode1 uses * a DWORD at 0xCF8 and another at 0xCFC and will pass through * any non-DWORD accesses as normal I/O cycles. There shouldn't be * a device behind these addresses so if Mode2 accesses fail try * for Mode1 (which is preferred, Mode2 is deprecated). */ outb(PciCSE, 0); if(inb(PciCSE) == 0){ pcicfgmode = 2; pcimaxdno = 15; } else { outl(PciADDR, 0); if(inl(PciADDR) == 0){ pcicfgmode = 1; pcimaxdno = 31; } } if(pcicfgmode < 0) goto out; if(p = getconf("*pcimaxdno")) pcimaxdno = strtoul(p, 0, 0); list = &pciroot; for(bno = 0; bno < 256; bno++) { bno = pciscan(bno, list); while(*list) list = &(*list)->link; } if(NOBIOS){ . 176a ulong mema, ioa, size; . 170a static ulong pcimask(ulong v) { ulong m; if(!NOBIOS) return 0; m = BI2BY*sizeof(v); for(m = 1<<(m-1); m != 0; m >>= 1) { if(m & v) break; } v |= m-1; return v+1; } . 165a /* * Now figure out the size of things below the bridge */ if(NOBIOS) { mema = 0; ioa = 0; pcibusmap(p->bridge, &mema, &ioa, 0); p->mem[BARmem].size = ROUND(mema, 1<<20); p->mem[BARio].size = ROUND(ioa, 1<<12); } . 162c else { . 159a . 147,150c * Make sure memory, I/O and master enables are * off, set the primary, secondary and subordinate * bus numbers and clear the secondary status before * attempting to scan the secondary bus. . 144c if(sbn == 0 || ubn == 0 || NOBIOS) { . 135,140c * If the secondary or subordinate bus number is not * initialised try to do what the PCI BIOS should have * done and fill in the numbers as the tree is descended. * On the way down the subordinate bus number is set to * the maximum as it's not known how many buses are behind * this one; the final value is set on the way back up. . 131c if(p->ccrb != 0x06 || p->ccru != 0x04) . 104,107c p->mem[i].size = pcibarsize(p, rno); . 101c for(i = 0; i < nelem(p->mem); i++) { . 92c case 0x07: /* simple comm. controllers */ . 86,87c switch(p->ccrb) { . 72c p->ccrp = pcicfgr8(p, PciCCRp); p->ccru = pcicfgr8(p, PciCCRu); p->ccrb = pcicfgr8(p, PciCCRb); . 50,54c * For this possible device, form the * bus+device+function triplet needed to address it * and try to read the vendor and device ID. * If successful, allocate a device struct and * start to fill it in with some useful information * from the device's configuration space. . 39c ulong mema, ioa; . 35a ulong pcibarsize(Pcidev *p, int rno) { ulong v, size; v = pcicfgrw32(p->tbdf, rno, 0, 1); pcicfgrw32(p->tbdf, rno, 0xFFFFFFF0, 0); size = pcicfgrw32(p->tbdf, rno, 0, 1); if(v & 1) size |= 0xFFFF0000; pcicfgrw32(p->tbdf, rno, v, 0); return -(size & ~0x0F); } static void pcibusmap(Pcidev *p, ulong *pmema, ulong *pioa, int wrreg) { int i, size, k; ulong addr, v, mema, ioa, pcr, tmema, tioa; if(!NOBIOS) return; mema = *pmema; ioa = *pioa; print("pcibusmap wr=%d %d.%d.%d mem=%lux io=%lux\n", wrreg, BUSBNO(p->tbdf), BUSDNO(p->tbdf), BUSFNO(p->tbdf), mema, ioa); /* * Allocate address space on this bus * note this loop follows link, not list */ for(; p; p = p->link) { if(p->ccrb == 0x06) { if(p->ccru != 0x04) { print("pci: ignored bridge %d.%d.%d\n", BUSBNO(p->tbdf), BUSDNO(p->tbdf), BUSFNO(p->tbdf)); continue; } /* Base */ p->mem[BARio].bar = ioa; p->mem[BARmem].bar = mema; tioa = ioa; tmema = mema; /* Limit */ ioa += p->mem[BARio].size; mema += p->mem[BARmem].size; if(wrreg == 0) continue; pcibusmap(p->bridge, &tmema, &tioa, 1); /* * IO base[15:12], IO limit [15:12] */ v = (0xFFFF<<16)| (ioa & 0xF000)| ((p->mem[BARio].bar & 0xF000)>>8); pcicfgrw32(p->tbdf, PciBAR3, v, 0); /* * Memory Base/Limit */ v = (mema & ~((1<<20)-1)) | ((p->mem[BARmem].bar & ~((1<<20)-1)) >> 16); pcicfgrw32(p->tbdf, PciBAR4, v, 0); /* * Disable memory prefetch */ pcicfgrw32(p->tbdf, PciBAR5, 0x0000FFFF, 0); /* * Enable the bridge */ v = 0xFFFF0000 | IOen | MEMen | MASen; pcicfgrw32(p->tbdf, PciPCR, v, 0); continue; } pcr = pcicfgrw32(p->tbdf, PciPCR, 0, 1); for(i = PciBAR0; i <= PciBAR5; i += 4) { v = pcicfgrw32(p->tbdf, i, 0, 1); size = pcibarsize(p, i); if(size > 16*1024*1024) print("pcimap: size %d?\n", size); if(size == 0) continue; if(v & 1) { /* Allocate IO space */ ioa = (ioa+size-1) & ~(size-1); addr = ioa; ioa += size; pcr |= IOen; } else { /* Allocate Memory space */ mema = (mema+size-1) & ~(size-1); addr = mema; mema += size; pcr |= MEMen; } k = (i-PciBAR0)/4; p->mem[k].size = size; p->mem[k].bar = addr; if(wrreg) pcicfgrw32(p->tbdf, i, addr, 0); } /* * Set latency timer * Enable memory/io/master */ if(wrreg) { pcicfgrw8(p->tbdf, PciLTR, 64, 0); pcr |= MASen; pcicfgrw32(p->tbdf, PciPCR, pcr, 0); } } print("pcibusmap mem=%lux io=%lux\n", mema, ioa); *pmema = mema; *pioa = ioa; } . 34a static int pcicfgrw8(int, int, int, int); . 25a enum { /* command register */ IOen = (1<<0), MEMen = (1<<1), MASen = (1<<2), MemWrInv = (1<<4), PErrEn = (1<<6), SErrEn = (1<<8), }; . 23a BARio = 0, /* fake BAR registers for bridges */ BARmem, NOBIOS = 0, /* initialise if the BIOS didn't */ . 14c enum { /* configuration mechanism #1 */ . 3,4d ## diffname pc/pci.c 1999/0314 ## diff -e /n/emeliedump/1999/0301/sys/src/brazil/pc/pci.c /n/emeliedump/1999/0314/sys/src/brazil/pc/pci.c 674a } void pcisetbme(Pcidev* p) { int pcr; pcr = pcicfgr16(p, PciPCR); pcr |= 0x0004; pcicfgw16(p, PciPCR, pcr); . 672,673c pcr = pcicfgr16(p, PciPCR); pcr &= ~0x0004; pcicfgw16(p, PciPCR, pcr); . ## diffname pc/pci.c 1999/0620 ## diff -e /n/emeliedump/1999/0314/sys/src/brazil/pc/pci.c /n/emeliedump/1999/0620/sys/src/brazil/pc/pci.c 191d ## diffname pc/pci.c 1999/0622 ## diff -e /n/emeliedump/1999/0620/sys/src/brazil/pc/pci.c /n/emeliedump/1999/0622/sys/src/brazil/pc/pci.c 683c pcr |= MASen; . 658a #else print("more...\n"); #endif /* notdef */ . 653a #define notdef #ifdef notdef . 651a if(t->ioa.bar || t->ioa.size) print("ioa:%.8lux %d ", t->ioa.bar, t->ioa.size); if(t->mema.bar || t->mema.size) print("mema:%.8lux %d ", t->mema.bar, t->mema.size); if(t->bridge) print("->%d", BUSBNO(t->bridge->tbdf)); . 642c print("%d %2d/%d %.2ux %.2ux %.2ux %.4ux %.4ux %3d ", . 637a putstrn(PCICONS.output, PCICONS.ptr); . 418,419d 415a DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); . 410,414c ioa = 0x1000; mema = 0x90000000; pcilog("Mask sizes: mem=%lux io=%lux\n", mema, ioa); . 405,406d 403a DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n", mema, pcimask(mema), ioa); . 397c if(pciroot == nil) goto out; if(NOBIOS) { . 386a fmtinstall('T', tbdfconv); . 357c ulong mema, ioa; . 334,350d 318,328d 226a p->pcr = pcicfgr32(p, PciPCR); . 185a free(table); if(wrreg == 0) return; /* * Finally set all the bridge addresses & registers */ for(p = root; p != nil; p = p->link) { if(p->bridge == nil) { pcicfgrw8(p->tbdf, PciLTR, 64, 0); p->pcr |= MASen; pcicfgrw32(p->tbdf, PciPCR, p->pcr, 0); continue; } base = p->ioa.bar; limit = base+p->ioa.size-1; v = pcicfgrw32(p->tbdf, PciBAR3, 0, 1); v = (v&0xFFFF0000)|(limit & 0xF000)|((base & 0xF000)>>8); pcicfgrw32(p->tbdf, PciBAR3, v, 0); v = (limit & 0xFFFF0000)|(base>>16); pcicfgrw32(p->tbdf, 0x30, v, 0); base = p->mema.bar; limit = base+p->mema.size-1; v = (limit & 0xFFF00000)|((base & 0xFFF00000)>>16); pcicfgrw32(p->tbdf, PciBAR4, v, 0); /* * Disable memory prefetch */ pcicfgrw32(p->tbdf, PciBAR5, 0x0000FFFF, 0); pcicfgrw8(p->tbdf, PciLTR, 64, 0); /* * Enable the bridge */ v = 0xFFFF0000 | IOen | MEMen | MASen; pcicfgrw32(p->tbdf, PciPCR, v, 0); sioa = p->ioa.bar; smema = p->mema.bar; pcibusmap(p->bridge, &smema, &sioa, 1); } . 183a p = tptr->dev; if(tptr->bar == -1) p->mema.bar = mema; else { p->pcr |= MEMen; p->mem[tptr->bar].bar = mema; if(wrreg) pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), mema, 0); } mema += tptr->siz; } . 182c /* * Allocate Memory address space on this bus */ for(tptr = table+ntb; tptr < mtb; tptr++) { hole = tptr->siz; if(tptr->bar == -1) hole = 1<<20; mema = (mema+hole-1) & ~(hole-1); . 179a ioa += tptr->siz; . 177,178c /* * Allocate IO address space on this bus */ for(tptr = table; tptr < itb; tptr++) { hole = tptr->siz; if(tptr->bar == -1) hole = 1<<12; ioa = (ioa+hole-1) & ~(hole-1); p = tptr->dev; if(tptr->bar == -1) p->ioa.bar = ioa; else { p->pcr |= IOen; p->mem[tptr->bar].bar = ioa|1; if(wrreg) pcicfgrw32(p->tbdf, PciBAR0+(tptr->bar*4), ioa|1, 0); . 170,175c /* * Sort both tables IO smallest first, Memory largest */ qsort(table, itb-table, sizeof(Pcisiz), pcisizcmp); tptr = table+ntb; qsort(tptr, mtb-tptr, sizeof(Pcisiz), pcisizcmp); . 168a } . 163,167c p->mem[i].size = size; . 156,160c else { mtb->dev = p; mtb->bar = i; mtb->siz = size; mtb++; . 150,154c if(v & 1) { itb->dev = p; itb->bar = i; itb->siz = size; itb++; . 140,146c for(i = 0; i <= 5; i++) { rno = PciBAR0 + i*4; v = pcicfgrw32(p->tbdf, rno, 0, 1); size = pcibarsize(p, rno); . 117,136c mtb->dev = p; mtb->bar = -1; mtb->siz = p->mema.size; mtb++; . 110,115c itb->dev = p; itb->bar = -1; itb->siz = p->ioa.size; itb++; . 108c p->ioa.size = hole; . 105,106c hole = pcimask(sioa-ioa); if(hole < (1<<12)) hole = 1<<12; . 101,103c hole = pcimask(smema-mema); if(hole < (1<<20)) hole = 1<<20; p->mema.size = hole; . 95,99c sioa = ioa; smema = mema; pcibusmap(p->bridge, &smema, &sioa, 0); . 87,91c if(p->ccru != 0x04 || p->bridge == nil) { // DBG("pci: ignored bridge %T\n", p->tbdf); . 85c for(p = root; p != nil; p = p->link) { . 82,83c * Build a table of sizes . 80a ntb = 0; for(p = root; p != nil; p = p->link) ntb++; ntb *= (PciCIS-PciBAR0)/4; table = malloc(2*ntb*sizeof(Pcisiz)); itb = table; mtb = table+ntb; . 77,79c DBG("pcibusmap wr=%d %T mem=%lux io=%lux\n", wrreg, root->tbdf, mema, ioa); . 75a mema = *pmema; . 74d 68,69c Pcidev *p; int ntb, i, size, rno, hole; ulong v, mema, ioa, sioa, smema, base, limit; Pcisiz *table, *tptr, *mtb, *itb; extern void qsort(void*, long, long, int (*)(void*, void*)); . 66c pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) . 64a static int pcisizcmp(void* va, void* vb) { Pcisiz *a, *b; a = va; b = vb; return a->siz - b->siz; } static ulong pcimask(ulong v) { ulong m; m = BI2BY*sizeof(v); for(m = 1<<(m-1); m != 0; m >>= 1) { if(m & v) break; } m--; if((v & m) == 0) return v; v |= m; return v+1; } . 49a static char* bustypes[] = { "CBUSI", "CBUSII", "EISA", "FUTURE", "INTERN", "ISA", "MBI", "MBII", "MCA", "MPI", "MPSA", "NUBUS", "PCI", "PCMCIA", "TC", "VL", "VME", "XPRESS", }; #pragma varargck type "T" int static int tbdfconv(va_list* arg, Fconv* f) { char *p; int l, type, tbdf; p = malloc(READSTR); if(p == nil){ strconv("(tbdfconv)", f); return sizeof(int); } switch(f->chr){ case 'T': tbdf = va_arg(*arg, int); type = BUSTYPE(tbdf); if(type < nelem(bustypes)) l = snprint(p, READSTR, bustypes[type]); else l = snprint(p, READSTR, "%d", type); snprint(p+l, READSTR-l, ".%d.%d.%d", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); break; default: snprint(p, READSTR, "(tbdfconv)"); break; } strconv(p, f); free(p); return sizeof(int); } . 30c enum { /* command register */ . 24,26d 11a #define DBG if(0) pcilog struct { char output[16384]; int ptr; }PCICONS; int pcilog(char *fmt, ...) { int n; va_list arg; char buf[PRINTSIZE]; va_start(arg, fmt); n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); memmove(PCICONS.output+PCICONS.ptr, buf, n); PCICONS.ptr += n; return n; } . ## diffname pc/pci.c 2000/0506 ## diff -e /n/emeliedump/1999/0622/sys/src/brazil/pc/pci.c /n/emeliedump/2000/0506/sys/src/9/pc/pci.c 818,820d 811,812d 788c putstrn(PCICONS.output, PCICONS.ptr); . 567c DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa); . 556c DBG("Sizes: mem=%8.8lux size=%8.8lux io=%8.8lux\n", mema, pcimask(mema), ioa); . 455c if(p->ccrb != 0x06 || (p->ccru != 0x04 && p->ccru != 0x07)) . 401a p->intl = pcicfgr8(p, PciINTL); . 396c p->rid = pcicfgr8(p, PciRID); . 205c if((p->ccru != 0x04 && p->ccru != 0x07) || p->bridge == nil) { . 188c DBG("pcibusmap wr=%d %T mem=%luX io=%luX\n", . 149,151c aa = a; bb = b; return aa->siz - bb->siz; . 147c Pcisiz *aa, *bb; . 145c pcisizcmp(void *a, void *b) . ## diffname pc/pci.c 2000/0517 ## diff -e /n/emeliedump/2000/0506/sys/src/9/pc/pci.c /n/emeliedump/2000/0517/sys/src/9/pc/pci.c 458c if(p->ccrb != 0x06 || p->ccru != 0x04) . 205,206c if(p->ccru != 0x04 || p->bridge == nil) { . ## diffname pc/pci.c 2000/0617 ## diff -e /n/emeliedump/2000/0517/sys/src/9/pc/pci.c /n/emeliedump/2000/0617/sys/src/9/pc/pci.c 541c for(bno = 0; bno <= pcimaxbno; bno++) { . 536a if(p = getconf("*pcimaxbno")) pcimaxbno = strtoul(p, 0, 0); . 63a static int pcimaxbno = 255; . ## diffname pc/pci.c 2000/0805 ## diff -e /n/emeliedump/2000/0617/sys/src/9/pc/pci.c /n/emeliedump/2000/0805/sys/src/9/pc/pci.c 64c static int pcimaxbno = 7; . ## diffname pc/pci.c 2000/1108 ## diff -e /n/emeliedump/2000/0805/sys/src/9/pc/pci.c /n/emeliedump/2000/1108/sys/src/9/pc/pci.c 553c if(nobios) { . 511a if (getconf("*nobios")) nobios = 1; . 472c if(sbn == 0 || ubn == 0 || nobios) { . 183c if(!nobios) . 68a static int nobios; . 47,48d ## diffname pc/pci.c 2001/0622 ## diff -e /n/emeliedump/2000/1108/sys/src/9/pc/pci.c /n/emeliedump/2001/0622/sys/src/9/pc/pci.c 822c } } void pcihinv(Pcidev* p) { qlock(&pcicfginitlock); pcilhinv(p); qunlock(&pcicfginitlock); . 788,789c static void pcilhinv(Pcidev* p) . 580c qunlock(&pcicfginitlock); cbinit(); . 576c qunlock(&pcicfginitlock); . 546c bno = pcilscan(bno, list); . 507c qlock(&pcicfginitlock); . 498a int pciscan(int bno, Pcidev **list) { int ubn; qlock(&pcicfginitlock); ubn = pcilscan(bno, list); qunlock(&pcicfginitlock); return ubn; } . 492c pcilscan(sbn, &p->bridge); . 485c maxubn = pcilscan(sbn, &p->bridge); . 362c pcilscan(int bno, Pcidev** list) . 60c static QLock pcicfginitlock; . ## diffname pc/pci.c 2001/0626 ## diff -e /n/emeliedump/2001/0622/sys/src/9/pc/pci.c /n/emeliedump/2001/0626/sys/src/9/pc/pci.c 592d ## diffname pc/pci.c 2001/0905 ## diff -e /n/emeliedump/2001/0626/sys/src/9/pc/pci.c /n/emeliedump/2001/0905/sys/src/9/pc/pci.c 866a pcicfgw16(p, PciPCR, pcr); } void pciclrbme(Pcidev* p) { int pcr; pcr = pcicfgr16(p, PciPCR); pcr &= ~MASen; . 559a if (sbno == 0) { Pcidev *pci; /* * If we have found a PCI-to-Cardbus bridge, make sure * it has no valid mappings anymore. */ pci = pciroot; while (pci) { if (pci->ccrb == 6 && pci->ccru == 7) { ushort bcr; /* reset the cardbus */ bcr = pcicfgr16(pci, PciBCR); pcicfgw16(pci, PciBCR, 0x40 | bcr); pcicfgw16(pci, PciBCR, bcr); } pci = pci->link; } } . 557a . 556a int sbno = bno; . ## diffname pc/pci.c 2001/0925 ## diff -e /n/emeliedump/2001/0905/sys/src/9/pc/pci.c /n/emeliedump/2001/0925/sys/src/9/pc/pci.c 854c pcilhinv(p->bridge); . 578c delay(50); . ## diffname pc/pci.c 2001/0928 ## diff -e /n/emeliedump/2001/0925/sys/src/9/pc/pci.c /n/emeliedump/2001/0928/sys/src/9/pc/pci.c 821a uchar pciipin(Pcidev *pci, uchar pin) { if (pci == nil) pci = pcilist; while (pci) { uchar intl; if (pcicfgr8(pci, PciINTP) == pin && pci->intl != 0 && pci->intl != 0xff) return pci->intl; if (pci->bridge && (intl = pciipin(pci->bridge, pin)) != 0) return intl; pci = pci->list; } return 0; } . ## diffname pc/pci.c 2001/1003 ## diff -e /n/emeliedump/2001/0928/sys/src/9/pc/pci.c /n/emeliedump/2001/1003/sys/src/9/pc/pci.c 612a pcirouting(); . 510a pcirouting(void) { uchar *p, pin, irq; ulong tbdf, vdid; ushort vid, did; router_t *r; slot_t *e; int size, i, fn; Pcidev *sbpci, *pci; // Peek in the BIOS for (p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) if (p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') break; if (p >= (uchar *)KADDR(0xfffff)) return; r = (router_t *)p; // print("PCI interrupt routing table version %d.%d at %.6uX\n", // r->rt_version[0], r->rt_version[1], (ulong)r & 0xfffff); tbdf = (BusPCI << 24)|(r->rt_bus << 16)|(r->rt_devfn << 8); vdid = pcicfgrw32(tbdf, PciVID, 0, 1); vid = vdid; did = vdid >> 16; for (i = 0; i != nelem(southbridges); i++) if (vid == southbridges[i].sb_vid && did == southbridges[i].sb_did) break; if (i == nelem(southbridges)) { print("pcirouting: South bridge %.4uX, %.4uX not found\n", vid, did); return; } southbridge = &southbridges[i]; if ((sbpci = pcimatch(nil, vid, did)) == nil) { print("pcirouting: Cannot match south bridge %.4uX, %.4uX\n", vid, did); return; } pciirqs = (r->rt_pciirqs[1] << 8)|r->rt_pciirqs[0]; size = (r->rt_size[1] << 8)|r->rt_size[0]; for (e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) { // print("%.2uX/%.2uX %.2uX: ", e->e_bus, e->e_dev, e->e_slot); // for (i = 0; i != 4; i++) { // uchar *m = &e->e_maps[i * 3]; // print("[%d] %.2uX %.4uX ", // i, m[0], (m[2] << 8)|m[1]); // } // print("\n"); for (fn = 0; fn != 8; fn++) { uchar *m; // Retrieve the did and vid through the devfn before // obtaining the Pcidev structure. tbdf = (BusPCI << 24)|(e->e_bus << 16)|((e->e_dev | fn) << 8); vdid = pcicfgrw32(tbdf, PciVID, 0, 1); if (vdid == 0xFFFFFFFF || vdid == 0) continue; vid = vdid; did = vdid >> 16; pci = nil; while ((pci = pcimatch(pci, vid, did)) != nil) { if (pci->intl != 0 && pci->intl != 0xFF) continue; pin = pcicfgr8(pci, PciINTP); if (pin == 0 || pin == 0xff) continue; m = &e->e_maps[(pin - 1) * 3]; irq = southbridge->sb_translate(sbpci, m[0]); if (irq) { print("pcirouting: %.4uX/%.4uX at pin %d irq %d\n", vid, did, pin, irq); pcicfgw8(pci, PciINTL, irq); pci->intl = irq; } } } } } static void . 509a static uchar pIIx_link(Pcidev *router, uchar link) { uchar pirq; /* link should be 0x60, 0x61, 0x62, 0x63 */ pirq = pcicfgr8(router, link); return (pirq < 16)? pirq: 0; } static void pIIx_init(Pcidev *router, uchar link, uchar irq) { pcicfgw8(router, link, irq); } static uchar via_link(Pcidev *router, uchar link) { uchar pirq; /* link should be 1, 2, 3, 5 */ pirq = (link < 6)? pcicfgr8(router, 0x55 + (link>>1)): 0; return (link & 1)? (pirq >> 4): (pirq & 15); } static void via_init(Pcidev *router, uchar link, uchar irq) { uchar pirq; pirq = pcicfgr8(router, 0x55 + (link >> 1)); pirq &= (link & 1)? 0x0f: 0xf0; pirq |= (link & 1)? (irq << 4): (irq & 15); pcicfgw8(router, 0x55 + (link>>1), pirq); } static uchar opti_link(Pcidev *router, uchar link) { uchar pirq = 0; /* link should be 0x02, 0x12, 0x22, 0x32 */ if ((link & 0xcf) == 0x02) pirq = pcicfgr8(router, 0xb8 + (link >> 5)); return (link & 0x10)? (pirq >> 4): (pirq & 15); } static void opti_init(Pcidev *router, uchar link, uchar irq) { uchar pirq; pirq = pcicfgr8(router, 0xb8 + (link >> 5)); pirq &= (link & 0x10)? 0x0f : 0xf0; pirq |= (link & 0x10)? (irq << 4): (irq & 15); pcicfgw8(router, 0xb8 + (link >> 5), pirq); } static uchar ali_link(Pcidev *router, uchar link) { /* No, you're not dreaming */ static const uchar map[] = { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 }; uchar pirq; /* link should be 0x01..0x08 */ pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); return (link & 1)? map[pirq&15]: map[pirq>>4]; } static void ali_init(Pcidev *router, uchar link, uchar irq) { /* Inverse of map in ali_link */ static const uchar map[] = { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 }; uchar pirq; pirq = pcicfgr8(router, 0x48 + ((link-1)>>1)); pirq &= (link & 1)? 0x0f: 0xf0; pirq |= (link & 1)? (map[irq] << 4): (map[irq] & 15); pcicfgw8(router, 0x48 + ((link-1)>>1), pirq); } static uchar cyrix_link(Pcidev *router, uchar link) { uchar pirq; /* link should be 1, 2, 3, 4 */ pirq = pcicfgr8(router, 0x5c + ((link-1)>>1)); return ((link & 1)? pirq >> 4: pirq & 15); } static void cyrix_init(Pcidev *router, uchar link, uchar irq) { uchar pirq; pirq = pcicfgr8(router, 0x5c + (link>>1)); pirq &= (link & 1)? 0x0f: 0xf0; pirq |= (link & 1)? (irq << 4): (irq & 15); pcicfgw8(router, 0x5c + (link>>1), pirq); } enum { Intel = 0x8086, Intel_82371FB_0 = 0x122e, Intel_82371SB_0 = 0x7000, Intel_82371AB_0 = 0x7110, Intel_82443MX_1 = 0x7198, Intel_82801AA_0 = 0x2410, Intel_82801AB_0 = 0x2420, Intel_82801BA_0 = 0x2440, Intel_82801BAM_0 = 0x244c, Viatech = 0x1106, Via_82C586_0 = 0x0586, Via_82C596 = 0x0596, Via_82C686 = 0x0686, Opti = 0x1045, Opti_82C700 = 0xc700, Al = 0x10b9, Al_M1533 = 0x1533, SI = 0x1039, SI_503 = 0x0008, SI_496 = 0x0496, Cyrix = 0x1078, Cyrix_5530_Legacy = 0x0100, }; typedef struct { ushort sb_vid, sb_did; uchar (*sb_translate)(Pcidev *, uchar); void (*sb_initialize)(Pcidev *, uchar, uchar); } bridge_t; static bridge_t southbridges[] = { { Intel, Intel_82371FB_0, pIIx_link, pIIx_init }, { Intel, Intel_82371SB_0, pIIx_link, pIIx_init }, { Intel, Intel_82371AB_0, pIIx_link, pIIx_init }, { Intel, Intel_82443MX_1, pIIx_link, pIIx_init }, { Intel, Intel_82801AA_0, pIIx_link, pIIx_init }, { Intel, Intel_82801AB_0, pIIx_link, pIIx_init }, { Intel, Intel_82801BA_0, pIIx_link, pIIx_init }, { Intel, Intel_82801BAM_0, pIIx_link, pIIx_init }, { Viatech, Via_82C586_0, via_link, via_init }, { Viatech, Via_82C596, via_link, via_init }, { Viatech, Via_82C686, via_link, via_init }, { Opti, Opti_82C700, opti_link, opti_init }, { Al, Al_M1533, ali_link, ali_init }, { SI, SI_503, pIIx_link, pIIx_init }, { SI, SI_496, pIIx_link, pIIx_init }, { Cyrix, Cyrix_5530_Legacy, cyrix_link, cyrix_init } }; typedef struct { uchar e_bus; // Pci bus number uchar e_dev; // Pci device number uchar e_maps[12]; // Avoid structs! Link and mask. uchar e_slot; // Add-in/built-in slot uchar e_reserved; } slot_t; typedef struct { uchar rt_signature[4]; // Routing table signature uchar rt_version[2]; // Version number uchar rt_size[2]; // Total table size uchar rt_bus; // Interrupt router bus number uchar rt_devfn; // Router's devfunc uchar rt_pciirqs[2]; // Exclusive PCI irqs uchar rt_compat[4]; // Compatible PCI interrupt router uchar rt_miniport[4]; // Miniport data uchar rt_reserved[11]; uchar rt_checksum; } router_t; static ushort pciirqs; // Exclusive PCI irqs static bridge_t *southbridge; // Which southbridge to use. . ## diffname pc/pci.c 2001/1215 ## diff -e /n/emeliedump/2001/1003/sys/src/9/pc/pci.c /n/emeliedump/2001/1215/sys/src/9/pc/pci.c 1157a if(pcicfgmode == -1) pcicfginit(); . ## diffname pc/pci.c 2001/1229 ## diff -e /n/emeliedump/2001/1215/sys/src/9/pc/pci.c /n/emeliedump/2001/1229/sys/src/9/pc/pci.c 1174,1178c for(p = pcilist; p != nil; p = p->list) pciclrbme(p); . 1169d ## diffname pc/pci.c 2002/0109 ## diff -e /n/emeliedump/2001/1229/sys/src/9/pc/pci.c /n/emeliedump/2002/0109/sys/src/9/pc/pci.c 1174a } . 1173c for(p = pcilist; p != nil; p = p->list) { /* don't mess with the bridges */ if(p->ccrb == 0x06) continue; . 890a . ## diffname pc/pci.c 2002/0212 ## diff -e /n/emeliedump/2002/0109/sys/src/9/pc/pci.c /n/emeliedump/2002/0212/sys/src/9/pc/pci.c 648,662c { Intel, Intel_82371FB_0, pIIx_link, pIIx_init }, { Intel, Intel_82371MX_0, pIIx_link, pIIx_init }, { Intel, Intel_82371SB_0, pIIx_link, pIIx_init }, { Intel, Intel_82371AB_0, pIIx_link, pIIx_init }, { Intel, Intel_82443MX_1, pIIx_link, pIIx_init }, { Intel, Intel_82801AA_0, pIIx_link, pIIx_init }, { Intel, Intel_82801AB_0, pIIx_link, pIIx_init }, { Intel, Intel_82801BA_0, pIIx_link, pIIx_init }, { Intel, Intel_82801BAM_0, pIIx_link, pIIx_init }, { Viatech, Via_82C586_0, via_link, via_init }, { Viatech, Via_82C596, via_link, via_init }, { Viatech, Via_82C686, via_link, via_init }, { Opti, Opti_82C700, opti_link, opti_init }, { Al, Al_M1533, ali_link, ali_init }, { SI, SI_503, pIIx_link, pIIx_init }, { SI, SI_496, pIIx_link, pIIx_init }, . 644c void (*sb_initialize)(Pcidev *, uchar, uchar); . 618a Intel_82371MX_0 = 0x1234, . ## diffname pc/pci.c 2002/0217 ## diff -e /n/emeliedump/2002/0212/sys/src/9/pc/pci.c /n/emeliedump/2002/0217/sys/src/9/pc/pci.c 823c fmtinstall('T', tbdffmt); . 126c return r; . 123c r = fmtstrcpy(fmt, p); . 109c tbdf = va_arg(fmt->args, int); . 107c switch(fmt->r){ . 101,105c if((p = malloc(READSTR)) == nil) return fmtstrcpy(fmt, "(tbdfconv)"); . 99c int l, r, type, tbdf; . 96c tbdffmt(Fmt* fmt) . 28c n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf; . ## diffname pc/pci.c 2002/0419 ## diff -e /n/emeliedump/2002/0217/sys/src/9/pc/pci.c /n/emeliedump/2002/0419/sys/src/9/pc/pci.c 777a print("pcirouting: %T at pin %d irq %d\n", tbdf, pin, irq); pcicfgw8(pci, PciINTL, irq); pci->intl = irq; . 756,776c m = &e->e_maps[(pin - 1) * 3]; irq = southbridge->get(sbpci, m[0]); if(irq == 0 || irq == pci->intl) continue; if (pci->intl != 0 && pci->intl != 0xFF) { print("pcirouting: BIOS workaround: %T at pin %d irq %d -> %d\n", tbdf, pin, irq, pci->intl); southbridge->set(sbpci, m[0], pci->intl); continue; . 754a pin = pcicfgr8(pci, PciINTP); if (pin == 0 || pin == 0xff) continue; . 752,753c pci = pcimatchtbdf(tbdf); if(pci == nil) . 747,750d 727,732d 723c print("pcirouting: South bridge %.4uX/%.4uX unknown\n", sbpci->vid, sbpci->did); . 719c if (sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) . 714,716c sbpci = pcimatchtbdf(tbdf); if(sbpci == nil) { print("pcirouting: Cannot find south bridge %T\n", tbdf); return; } . 700c // Search for PCI interrupt routing table in BIOS . 698a uchar *p, *m, pin, irq; . 697c router_t *r; int size, i, fn, tbdf; . 692,695d 646,662c { 0x8086, 0x122e, pIIx_get, pIIx_set }, // Intel 82371FB { 0x8086, 0x1234, pIIx_get, pIIx_set }, // Intel 82371MX { 0x8086, 0x7000, pIIx_get, pIIx_set }, // Intel 82371SB { 0x8086, 0x7110, pIIx_get, pIIx_set }, // Intel 82371AB { 0x8086, 0x7198, pIIx_get, pIIx_set }, // Intel 82443MX (fn 1) { 0x8086, 0x2410, pIIx_get, pIIx_set }, // Intel 82801AA { 0x8086, 0x2420, pIIx_get, pIIx_set }, // Intel 82801AB { 0x8086, 0x2440, pIIx_get, pIIx_set }, // Intel 82801BA { 0x8086, 0x244c, pIIx_get, pIIx_set }, // Intel 82801BAM { 0x1106, 0x0586, via_get, via_set }, // Viatech 82C586 { 0x1106, 0x0596, via_get, via_set }, // Viatech 82C596 { 0x1106, 0x0686, via_get, via_set }, // Viatech 82C686 { 0x1045, 0xc700, opti_get, opti_set }, // Opti 82C700 { 0x10b9, 0x1533, ali_get, ali_set }, // Al M1533 { 0x1039, 0x0008, pIIx_get, pIIx_set }, // SI 503 { 0x1039, 0x0496, pIIx_get, pIIx_set }, // SI 496 { 0x1078, 0x0100, cyrix_get, cyrix_set } // Cyrix 5530 Legacy . 613,642c typedef struct { ushort vid; ushort did; uchar (*get)(Pcidev *, uchar); void (*set)(Pcidev *, uchar, uchar); . 603c cyrix_set(Pcidev *router, uchar link, uchar irq) . 593c cyrix_get(Pcidev *router, uchar link) . 582c /* Inverse of map in ali_get */ . 580c ali_set(Pcidev *router, uchar link, uchar irq) . 568c ali_get(Pcidev *router, uchar link) . 557c opti_set(Pcidev *router, uchar link, uchar irq) . 546c opti_get(Pcidev *router, uchar link) . 535c via_set(Pcidev *router, uchar link, uchar irq) . 524c via_get(Pcidev *router, uchar link) . 518c pIIx_set(Pcidev *router, uchar link, uchar irq) . 508c pIIx_get(Pcidev *router, uchar link) . ## diffname pc/pci.c 2002/0420 ## diff -e /n/emeliedump/2002/0419/sys/src/9/pc/pci.c /n/emeliedump/2002/0420/sys/src/9/pc/pci.c 1122c unlock(&pcicfginitlock); . 1120c lock(&pcicfginitlock); . 849c unlock(&pcicfginitlock); . 842c unlock(&pcicfginitlock); . 750c lock(&pcicfginitlock); . 503c unlock(&pcicfginitlock); . 501c lock(&pcicfginitlock); . 60c static Lock pcicfginitlock; . ## diffname pc/pci.c 2002/0501 ## diff -e /n/emeliedump/2002/0420/sys/src/9/pc/pci.c /n/emeliedump/2002/0501/sys/src/9/pc/pci.c 729c if(pci->intl != 0 && pci->intl != 0xFF) { . 722c if(pin == 0 || pin == 0xff) . 716c for(fn = 0; fn != 8; fn++) { . 707c for(e = (slot_t *)&r[1]; (uchar *)e < p + size; e++) { . 703c . 698,699c if(i == nelem(southbridges)) { print("pcirouting: south bridge %.4uX/%.4uX (unknown type)\n", sbpci->vid, sbpci->did); . 694,695c for(i = 0; i != nelem(southbridges); i++) if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) . 679c if(p >= (uchar *)KADDR(0xfffff)) . 675,676c for(p = (uchar *)KADDR(0xf0000); p < (uchar *)KADDR(0xfffff); p += 16) if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') . ## diffname pc/pci.c 2002/0511 ## diff -e /n/emeliedump/2002/0501/sys/src/9/pc/pci.c /n/emeliedump/2002/0511/sys/src/9/pc/pci.c 846c if (!nopcirouting) pcirouting(); . 755a if (getconf("*nopcirouting")) nopcirouting = 1; . 67c static int nobios, nopcirouting; . ## diffname pc/pci.c 2002/0514 ## diff -e /n/emeliedump/2002/0511/sys/src/9/pc/pci.c /n/emeliedump/2002/0514/sys/src/9/pc/pci.c 735c print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq); . 730,732c print("pcirouting: BIOS workaround: %T at pin %d link %d irq %d -> %d\n", tbdf, pin, link, irq, pci->intl); southbridge->set(sbpci, link, pci->intl); . 726c link = m[0]; irq = southbridge->get(sbpci, link); . 672c uchar *p, *m, pin, irq, link; . ## diffname pc/pci.c 2002/0517 ## diff -e /n/emeliedump/2002/0514/sys/src/9/pc/pci.c /n/emeliedump/2002/0517/sys/src/9/pc/pci.c 699c print("pcirouting: ignoring south bridge %T %.4uX/%.4uX\n", tbdf, sbpci->vid, sbpci->did); . ## diffname pc/pci.c 2002/0824 ## diff -e /n/emeliedump/2002/0517/sys/src/9/pc/pci.c /n/emeliedump/2002/0824/sys/src/9/pc/pci.c 855a if(getconf("*pcihinv")) pcihinv(nil); . 773,777c else{ outb(PciCSE, 0); if(inb(PciCSE) == 0){ pcicfgmode = 2; pcimaxdno = 15; . 768,771c outl(PciADDR, 0); if(inl(PciADDR) == 0){ pcicfgmode = 1; pcimaxdno = 31; . 765,766c * a device behind these addresses so if Mode1 accesses fail try * for Mode2 (Mode2 is deprecated). .