From a0404ff58245f16d2117542d2dffd1fc6199943d Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Mon, 1 Mar 2021 17:24:54 +0100 Subject: [PATCH] devpccard, pci: fix pccard support and handle pci expansion roms let pci.c deal with the special cardbus controller bar0 and expansion roms. handle apic interrupt routing for devices behind a cardbus slot. do not free the pcidev on card removal, as the drivers most certanly are not prepared to handle this yet. instead, we provide a pcidevfree() function that just unlinks the device from pcilist and the parent bridge. --- sys/src/9/bcm64/pcibcm.c | 2 +- sys/src/9/mtx/pcimtx.c | 2 +- sys/src/9/pc/devpccard.c | 281 +++++++++++++++------------------------ sys/src/9/pc/mp.c | 14 +- sys/src/9/pc/pcipc.c | 6 +- sys/src/9/port/pci.c | 165 +++++++++++++++++++---- sys/src/9/port/pci.h | 29 ++-- sys/src/9/teg2/pciteg.c | 2 +- 8 files changed, 283 insertions(+), 218 deletions(-) diff --git a/sys/src/9/bcm64/pcibcm.c b/sys/src/9/bcm64/pcibcm.c index 0ba9b5111..4e21d7e86 100644 --- a/sys/src/9/bcm64/pcibcm.c +++ b/sys/src/9/bcm64/pcibcm.c @@ -210,7 +210,7 @@ pcicfginit(void) fmtinstall('T', tbdffmt); - pciscan(0, &pciroot); + pciscan(0, &pciroot, nil); if(pciroot == nil) return; diff --git a/sys/src/9/mtx/pcimtx.c b/sys/src/9/mtx/pcimtx.c index a2425d609..c6704c0e1 100644 --- a/sys/src/9/mtx/pcimtx.c +++ b/sys/src/9/mtx/pcimtx.c @@ -67,7 +67,7 @@ pcicfginit(void) list = &pciroot; for(bno = 0; bno <= pcimaxbno; bno++) { int sbno = bno; - bno = pciscan(bno, list); + bno = pciscan(bno, list, nil); while(*list) list = &(*list)->link; diff --git a/sys/src/9/pc/devpccard.c b/sys/src/9/pc/devpccard.c index fdfcdd9b7..88d29fb31 100644 --- a/sys/src/9/pc/devpccard.c +++ b/sys/src/9/pc/devpccard.c @@ -101,7 +101,6 @@ enum { PciPMC = 0xa4, - Nbars = 6, Ncmd = 10, CBIRQ = 9, @@ -346,7 +345,7 @@ engine(Cardbus *cb, int message) break; default: if(DEBUG) - print("#Y%ld: Invalid message %s in SlotEmpty state\n", + print("#Y%zd: Invalid message %s in SlotEmpty state\n", cb - cbslots, messages[message]); break; } @@ -365,7 +364,7 @@ engine(Cardbus *cb, int message) break; default: if(DEBUG) - print("#Y%ld: Invalid message %s in SlotFull state\n", + print("#Y%zd: Invalid message %s in SlotFull state\n", cb - cbslots, messages[message]); break; } @@ -383,7 +382,7 @@ engine(Cardbus *cb, int message) powerdown(cb); break; default: - print("#Y%ld: Invalid message %s in SlotPowered state\n", + print("#Y%zd: Invalid message %s in SlotPowered state\n", cb - cbslots, messages[message]); break; } @@ -399,7 +398,7 @@ engine(Cardbus *cb, int message) break; default: if(DEBUG) - print("#Y%ld: Invalid message %s in SlotConfigured state\n", + print("#Y%zd: Invalid message %s in SlotConfigured state\n", cb - cbslots, messages[message]); break; } @@ -492,7 +491,7 @@ cbinterrupt(Ureg *, void *) rdreg(cb, Rcsc); /* Ack the interrupt */ if(DEBUG) - print("#Y%ld: interrupt: event %.8lX, state %.8lX, (%s)\n", + print("#Y%zd: interrupt: event %.8lX, state %.8lX, (%s)\n", cb - cbslots, event, state, states[cb->state]); if (event & SE_CCD) { @@ -520,7 +519,6 @@ devpccardlink(void) static int initialized; Pcidev *pci; int i; - uchar intl; char *p; if (initialized) @@ -539,9 +537,7 @@ devpccardlink(void) /* Find all CardBus controllers */ pci = nil; - intl = 0xff; while ((pci = pcimatch(pci, 0, 0)) != nil) { - uvlong baddr; Cardbus *cb; uchar pin; @@ -559,20 +555,20 @@ devpccardlink(void) cb->pci = pci; cb->variant = &variant[i]; - if (pci->vid != TI_vid) { - /* - * Gross hack, needs a fix. Inherit the mappings from - * 9load for the TIs (pb) - */ - pcicfgw32(pci, PciCBMBR0, 0xffffffff); - pcicfgw32(pci, PciCBMLR0, 0); - pcicfgw32(pci, PciCBMBR1, 0xffffffff); - pcicfgw32(pci, PciCBMLR1, 0); - pcicfgw32(pci, PciCBIBR0, 0xffffffff); - pcicfgw32(pci, PciCBILR0, 0); - pcicfgw32(pci, PciCBIBR1, 0xffffffff); - pcicfgw32(pci, PciCBILR1, 0); - } + if(pci->mem[0].size == 0 || (pci->mem[0].bar & 0xF) != 0) + continue; + cb->regs = (ulong *)vmap(pci->mem[0].bar & ~0xFULL, pci->mem[0].size); + if(cb->regs == nil) + continue; + + pcicfgw32(pci, PciCBMBR0, 0xffffffff); + pcicfgw32(pci, PciCBMLR0, 0); + pcicfgw32(pci, PciCBMBR1, 0xffffffff); + pcicfgw32(pci, PciCBMLR1, 0); + pcicfgw32(pci, PciCBIBR0, 0xffffffff); + pcicfgw32(pci, PciCBILR0, 0); + pcicfgw32(pci, PciCBIBR1, 0xffffffff); + pcicfgw32(pci, PciCBILR1, 0); /* Set up PCI bus numbers if needed. */ if (pcicfgr8(pci, PciSBN) == 0) { @@ -590,7 +586,7 @@ devpccardlink(void) pcicfgw8(pci, PciINTL, pci->intl); if (pci->intl == 0xff || pci->intl == 0) - print("#Y%ld: No interrupt?\n", cb - cbslots); + print("#Y%zd: No interrupt?\n", cb - cbslots); } /* Don't you love standards! */ @@ -632,30 +628,15 @@ devpccardlink(void) pcicfgw8(cb->pci, 0x94, 0xCA); pcicfgw8(cb->pci, 0xD4, 0xCA); } - - baddr = pcicfgr32(cb->pci, PciBAR0); - if (baddr == 0) { - int size = (pci->did == Ricoh_478_did)? 0x10000: 0x1000; - baddr = upaalloc(-1ULL, size, size); - if(baddr == -1) - continue; - pcicfgw32(cb->pci, PciBAR0, (ulong)baddr); - cb->regs = (ulong *)vmap(baddr, size); - } - else - cb->regs = (ulong *)vmap(baddr, 4096); - if(cb->regs == nil) - continue; cb->state = SlotEmpty; - if (intl != 0xff && intl != pci->intl) - intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus"); + intrenable(pci->intl, cbinterrupt, cb, pci->tbdf, "cardbus"); /* Don't really know what to do with this... */ i82365probe(cb, LegacyAddr, LegacyAddr + 1); - print("#Y%ld: %s, %.8lluX intl %d\n", cb - cbslots, - variant[i].name, baddr, pci->intl); + print("#Y%zd: %s, %.8lluX intl %d\n", cb - cbslots, + variant[i].name, pci->mem[0].bar, pci->intl); nslots++; } @@ -699,7 +680,7 @@ powerup(Cardbus *cb) state = cb->regs[SocketState]; if (state & SS_PC16) { if(DEBUG) - print("#Y%ld: Probed a PC16 card, powering up card\n", + print("#Y%zd: Probed a PC16 card, powering up card\n", cb - cbslots); cb->type = PC16; memset(&cb->linfo, 0, sizeof(Pcminfo)); @@ -719,19 +700,19 @@ powerup(Cardbus *cb) return 0; if (state & SS_NOTCARD) { - print("#Y%ld: No card inserted\n", cb - cbslots); + print("#Y%zd: No card inserted\n", cb - cbslots); return 0; } if ((state & SS_3V) == 0 && (state & SS_5V) == 0) { - print("#Y%ld: Unsupported voltage, powering down card!\n", + print("#Y%zd: Unsupported voltage, powering down card!\n", cb - cbslots); cb->regs[SocketControl] = 0; return 0; } if(DEBUG) - print("#Y%ld: card %spowered at %d volt\n", cb - cbslots, + print("#Y%zd: card %spowered at %d volt\n", cb - cbslots, (state & SS_POWER)? "": "not ", (state & SS_3V)? 3: (state & SS_5V)? 5: -1); @@ -777,10 +758,9 @@ powerdown(Cardbus *cb) static void configure(Cardbus *cb) { - int i, r; Pcidev *pci; - uvlong romlen, memlen, membase, rombase, bar; - ulong iobase, iolen, size; + ulong iobase, iolen; + uvlong membase, memlen; if(DEBUG) print("configuring slot %ld (%s)\n", cb - cbslots, states[cb->state]); @@ -796,102 +776,68 @@ configure(Cardbus *cb) } /* Scan the CardBus for new PCI devices */ - pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge); + pciscan(pcicfgr8(cb->pci, PciSBN), &cb->pci->bridge, cb->pci); - /* - * size the devices on the bus, reserve a minimum for devices arriving later, - * allow for ROM space, allocate space, and set the cardbus mapping registers - */ - pcibussize(cb->pci->bridge, &memlen, &iolen); /* TO DO: need initial alignments */ - - romlen = 0; - for(pci = cb->pci->bridge; pci != nil; pci = pci->list){ - size = pcibarsize(pci, PciEBAR0); - if(size > 0){ - pci->rom.bar = -1; - pci->rom.size = size; - romlen += size; - } - } + /* size the devices on the bus, reserve a minimum for devices arriving later */ + pcibussize(cb->pci->bridge, &memlen, &iolen); if(iolen < 512) iolen = 512; - iobase = ioreserve(-1, iolen, 0, "cardbus"); - if(iobase == -1) - return; - - rombase = memlen; - memlen += romlen; if(memlen < 1*1024*1024) memlen = 1*1024*1024; - membase = upaalloc(-1ULL, memlen, 4*1024*1024); /* TO DO: better alignment */ - if(membase == -1) + + print("#Y%zd: iolen=%lud, memlen=%llud\n", cb - cbslots, iolen, memlen); + + if(cb->pci->parent == nil){ + iobase = ioreserve(-1, + iolen, iolen, "cardbus"); + if(iobase == -1){ +NoIO: + print("#Y%zd: can't allocate io space\n", cb - cbslots); + return; + } + membase = upaalloc(-1ULL, + memlen, 4*1024*1024); + } else { + iobase = ioreservewin(cb->pci->parent->ioa.bar, cb->pci->parent->ioa.size, + iolen, iolen, "cardbus"); + if(iobase == -1) + goto NoIO; + membase = upaallocwin(cb->pci->parent->mema.bar, cb->pci->parent->mema.size, + memlen, 4*1024*1024); + } + if(membase == -1){ + print("#Y%zd: can't allocate memory space\n", cb - cbslots); return; + } + + print("#Y%zd: iobase=%lux, membase=%llux\n", cb - cbslots, iobase, membase); pcicfgw32(cb->pci, PciCBIBR0, iobase); pcicfgw32(cb->pci, PciCBILR0, iobase + iolen-1); - pcicfgw32(cb->pci, PciCBIBR1, 0); + pcicfgw32(cb->pci, PciCBIBR1, 0xffffffff); pcicfgw32(cb->pci, PciCBILR1, 0); + cb->pci->ioa.bar = iobase; + cb->pci->ioa.size = iolen; pcicfgw32(cb->pci, PciCBMBR0, (ulong)membase); pcicfgw32(cb->pci, PciCBMLR0, (ulong)membase + memlen-1); - pcicfgw32(cb->pci, PciCBMBR1, 0); + pcicfgw32(cb->pci, PciCBMBR1, 0xffffffff); pcicfgw32(cb->pci, PciCBMLR1, 0); + cb->pci->mema.bar = membase; + cb->pci->mema.size = memlen; -// pcibussize(cb->pci->bridge, &membase, &iobase); /* now assign them */ - rombase += membase; + /* Route interrupts to INTA#/B#, Disable prefetch for MEM0/1 */ + pcicfgw16(cb->pci, PciBCR, pcicfgr16(cb->pci, PciBCR) & ~(7 << 7)); - for(pci = cb->pci->bridge; pci != nil; pci = pci->list){ - r = pcicfgr16(pci, PciPCR); - r &= ~(PciPCR_IO|PciPCR_MEM); - pcicfgw16(pci, PciPCR, r); + /* Assign resources */ + pcibusmap(cb->pci->bridge, &membase, &iobase, 1); - /* - * Treat the found device as an ordinary PCI card. - * It seems that the CIS is not always present in - * CardBus cards. - * XXX, need to support multifunction cards - */ - for(i = 0; i < Nbars; i++) { - if(pci->mem[i].size == 0) - continue; - bar = pci->mem[i].bar; - if(bar & 1) - bar += iobase; - else - bar += membase; - pci->mem[i].bar = bar; - pcicfgw32(pci, PciBAR0 + 4*i, bar); - if((bar & 1) == 0){ - print("%T mem[%d] %8.8llux %d\n", pci->tbdf, i, bar, pci->mem[i].size); - if(bar & 0x80){ /* TO DO: enable prefetch */ - ; - } - } - } - if((size = pcibarsize(pci, PciEBAR0)) > 0) { /* TO DO: can this be done by pci.c? */ - pci->rom.bar = rombase; - pci->rom.size = size; - rombase += size; - pcicfgw32(pci, PciEBAR0, pci->rom.bar); - } - - /* Set the basic PCI registers for the device */ - pci->pcr = pcicfgr16(pci, PciPCR); - pci->pcr |= PciPCR_IO|PciPCR_MEM|PciPCR_Master; - pci->cls = 8; - pci->ltr = 64; - pcicfgw16(pci, PciPCR, pci->pcr); - pcicfgw8(pci, PciCLS, pci->cls); - pcicfgw8(pci, PciLTR, pci->ltr); - - if (pcicfgr8(pci, PciINTP)) { - pci->intl = pcicfgr8(cb->pci, PciINTL); + /* Assign legacy IRQ's */ + for(pci = cb->pci->bridge; pci != nil; pci = pci->link) { + if(pcicfgr8(pci, PciINTP) != 0) { + pci->intl = cb->pci->intl; pcicfgw8(pci, PciINTL, pci->intl); - - /* Route interrupts to INTA#/B# */ - pcicfgw16(cb->pci, PciBCR, - pcicfgr16(cb->pci, PciBCR) & ~(1 << 7)); } } } @@ -899,58 +845,51 @@ configure(Cardbus *cb) static void unconfigure(Cardbus *cb) { - Pcidev *pci; - int i, ioindex, memindex, r; - if (cb->type == PC16) { - print("#Y%d: Don't know how to unconfigure a PC16 card\n", - (int)(cb - cbslots)); - + print("#Y%zd: Don't know how to unconfigure a PC16 card\n", cb - cbslots); memset(&cb->linfo, 0, sizeof(Pcminfo)); return; } - pci = cb->pci->bridge; - if (pci == nil) - return; /* Not configured */ - cb->pci->bridge = nil; + pcicfgw32(cb->pci, PciCBIBR0, 0xffffffff); + pcicfgw32(cb->pci, PciCBILR0, 0); + pcicfgw32(cb->pci, PciCBIBR1, 0xffffffff); + pcicfgw32(cb->pci, PciCBILR1, 0); - memindex = ioindex = 0; - while (pci) { - Pcidev *_pci; + pcicfgw32(cb->pci, PciCBMBR0, 0xffffffff); + pcicfgw32(cb->pci, PciCBMLR0, 0); + pcicfgw32(cb->pci, PciCBMBR1, 0xffffffff); + pcicfgw32(cb->pci, PciCBMLR1, 0); - for (i = 0; i != Nbars; i++) { - if (pci->mem[i].size == 0) - continue; - if (pci->mem[i].bar & 1) { + /* free i/o space */ + if(cb->pci->ioa.size){ + Pcidev *pci; + int i; + + for(pci = cb->pci->bridge; pci != nil; pci = pci->link) { + for(i = 0; i < nelem(pci->mem); i++) { + if((pci->mem[i].size == 0) + || (pci->mem[i].bar & 1) == 0 + || (pci->mem[i].bar & ~3) == 0) + continue; iofree(pci->mem[i].bar & ~3); - pcicfgw16(cb->pci, PciCBIBR0 + ioindex * 8, - (ushort)-1); - pcicfgw16(cb->pci, PciCBILR0 + ioindex * 8, 0); - ioindex++; - continue; } - - upafree(pci->mem[i].bar & ~0xF, pci->mem[i].size); - pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1); - pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0); - r = pcicfgr16(cb->pci, PciBCR); - r &= ~(1 << (8 + memindex)); - pcicfgw16(cb->pci, PciBCR, r); - memindex++; } - - if (pci->rom.bar && memindex < 2) { - upafree(pci->rom.bar & ~0xF, pci->rom.size); - pcicfgw32(cb->pci, PciCBMBR0 + memindex * 8, (ulong)-1); - pcicfgw32(cb->pci, PciCBMLR0 + memindex * 8, 0); - memindex++; - } - - _pci = pci->list; - free(_pci); - pci = _pci; + iofree(cb->pci->ioa.bar); + cb->pci->ioa.bar = 0; + cb->pci->ioa.size = 0; } + + /* free memory space */ + if(cb->pci->mema.size){ + upafree(cb->pci->mema.bar, cb->pci->mema.size); + cb->pci->mema.bar = 0; + cb->pci->mema.size = 0; + } + + /* remove the devices */ + while(cb->pci->bridge != nil) + pcidevfree(cb->pci->bridge); } static void @@ -1174,7 +1113,7 @@ pccard_pcmspecial(char *idstr, ISAConf *isa) pi->irq = isa->irq; unlock(cb); - print("#Y%ld: %s irq %d, port %lluX\n", cb - cbslots, pi->verstr, isa->irq, isa->port); + print("#Y%zd: %s irq %d, port %lluX\n", cb - cbslots, pi->verstr, isa->irq, isa->port); return (int)(cb - cbslots); } @@ -1321,10 +1260,10 @@ pccardread(Chan *c, void *a, long n, vlong offset) Pcidev *pci = cb->pci->bridge; int i; - while (pci) { + while (pci != nil) { p = seprint(p, e, "%.4uX %.4uX; irq %d\n", pci->vid, pci->did, pci->intl); - for (i = 0; i != Nbars; i++) + for (i = 0; i < nelem(pci->mem); i++) if (pci->mem[i].size) p = seprint(p, e, "\tmem[%d] %.8ullX (%.8uX)\n", @@ -1333,7 +1272,7 @@ pccardread(Chan *c, void *a, long n, vlong offset) if (pci->rom.size) p = seprint(p, e, "\tROM %.8ullX (%.8uX)\n", pci->rom.bar, pci->rom.size); - pci = pci->list; + pci = pci->link; } } break; diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index abb3e010e..ede29b323 100644 --- a/sys/src/9/pc/mp.c +++ b/sys/src/9/pc/mp.c @@ -351,13 +351,19 @@ Findbus: if(bus == nil){ /* - * if the PCI device is behind a PCI-PCI bridge thats not described - * by the MP or ACPI tables then walk up the bus translating interrupt - * pin to parent bus. + * if the PCI device is behind a bridge thats not described + * by the MP or ACPI tables then walk up the bus translating + * interrupt pin to parent bus. */ if(pci != nil && pci->parent != nil && pin > 0){ - pin = ((dno+(pin-1))%4)+1; pci = pci->parent; + if(pci->ccrb == 6 && pci->ccru == 7){ + /* Cardbus bridge, use controllers interrupt pin */ + pin = pcicfgr8(pci, PciINTP); + } else { + /* PCI-PCI bridge */ + pin = ((dno+(pin-1))%4)+1; + } bno = BUSBNO(pci->tbdf); dno = BUSDNO(pci->tbdf); goto Findbus; diff --git a/sys/src/9/pc/pcipc.c b/sys/src/9/pc/pcipc.c index 3355e7b0c..f5bb530bb 100644 --- a/sys/src/9/pc/pcipc.c +++ b/sys/src/9/pc/pcipc.c @@ -557,6 +557,10 @@ pcireserve(void) upaalloc(pa, p->mem[i].size, 0); } } + if(p->rom.size && (p->rom.bar & 1) != 0){ + pa = p->rom.bar & ~0x7FFULL; + upaalloc(pa, p->rom.size, 0); + } } /* @@ -688,7 +692,7 @@ pcicfginit(void) list = &pciroot; for(bno = 0; bno <= pcimaxbno; bno++) { int sbno = bno; - bno = pciscan(bno, list); + bno = pciscan(bno, list, nil); while(*list) list = &(*list)->link; diff --git a/sys/src/9/port/pci.c b/sys/src/9/port/pci.c index 3efe83b00..bf5f43af0 100644 --- a/sys/src/9/port/pci.c +++ b/sys/src/9/port/pci.c @@ -18,8 +18,7 @@ struct Pcisiz int pcimaxdno; static Lock pcicfglock; -static Pcidev* pcilist; -static Pcidev* pcitail; +static Pcidev *pcilist, **pcitail; static char* bustypes[] = { "CBUSI", @@ -68,6 +67,46 @@ tbdffmt(Fmt* fmt) } } +static Pcidev* +pcidevalloc(void) +{ + Pcidev *p; + + p = xalloc(sizeof(*p)); + if(p == nil) + panic("pci: no memory for Pcidev"); + return p; +} + +void +pcidevfree(Pcidev *p) +{ + Pcidev **l; + + if(p == nil) + return; + + while(p->bridge != nil) + pcidevfree(p->bridge); + + if(p->parent != nil){ + for(l = &p->parent->bridge; *l != nil; l = &(*l)->link) { + if(*l == p) { + *l = p->link; + break; + } + } + } + for(l = &pcilist; *l != nil; l = &(*l)->list) { + if(*l == p) { + if((*l = p->list) == nil) + pcitail = l; + break; + } + } + /* leaked */ +} + int pcicfgr8(Pcidev* p, int rno) { @@ -135,12 +174,15 @@ pcibarsize(Pcidev *p, int rno) pcicfgrw32(p->tbdf, rno, v, 0); iunlock(&pcicfglock); - if(v & 1){ + if(rno == PciEBAR0 || rno == PciEBAR1){ + size &= ~0x7FF; + } else if(v & 1){ size = (short)size; size &= ~3; } else { size &= ~0xF; } + return -size; } @@ -217,7 +259,7 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) ntb++; ntb *= (PciCIS-PciBAR0)/4; - table = malloc(2*ntb*sizeof(Pcisiz)); + table = malloc((2*ntb+1)*sizeof(Pcisiz)); if(table == nil) panic("pcibusmap: can't allocate memory"); itb = table; @@ -228,6 +270,22 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) */ for(p = root; p != nil; p = p->link) { if(p->ccrb == 0x06) { + /* carbus bridge? */ + if(p->ccru == 0x07){ + if(pcicfgr32(p, PciBAR0) & 1) + continue; + size = pcibarsize(p, PciBAR0); + if(size == 0) + continue; + mtb->dev = p; + mtb->bar = 0; + mtb->siz = size; + mtb->typ = 0; + mtb++; + continue; + } + + /* pci bridge? */ if(p->ccru != 0x04 || p->bridge == nil) continue; @@ -252,9 +310,27 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) mtb->siz = hole; mtb->typ = 0; mtb++; + + size = pcibarsize(p, PciEBAR1); + if(size != 0){ + mtb->dev = p; + mtb->bar = -3; + mtb->siz = size; + mtb->typ = 0; + mtb++; + } continue; } + size = pcibarsize(p, PciEBAR0); + if(size != 0){ + mtb->dev = p; + mtb->bar = -2; + mtb->siz = size; + mtb->typ = 0; + mtb++; + } + for(i = 0; i < nelem(p->mem); i++) { rno = PciBAR0 + i*4; v = pcicfgr32(p, rno); @@ -321,6 +397,14 @@ pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg) if(tptr->bar == -1) { p->mema.bar = mema; p->mema.size = tptr->siz; + } else if(tptr->bar == -2) { + p->rom.bar = mema|1; + p->rom.size = tptr->siz; + pcisetbar(p, PciEBAR0, p->rom.bar); + } else if(tptr->bar == -3) { + p->rom.bar = mema|1; + p->rom.size = tptr->siz; + pcisetbar(p, PciEBAR1, p->rom.bar); } else { p->mem[tptr->bar].size = tptr->siz; p->mem[tptr->bar].bar = mema|tptr->typ; @@ -409,10 +493,10 @@ pcivalidbar(Pcidev *p, uvlong bar, int size) } } -static int -pcilscan(int bno, Pcidev** list, Pcidev *parent) +int +pciscan(int bno, Pcidev** list, Pcidev *parent) { - Pcidev *p, *head, *tail; + Pcidev *p, *head, **tail; int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn; maxubn = bno; @@ -437,19 +521,11 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) if(l == 0xFFFFFFFF || l == 0) continue; - p = malloc(sizeof(*p)); - if(p == nil) - panic("pcilscan: can't allocate memory"); + p = pcidevalloc(); p->tbdf = tbdf; p->vid = l; p->did = l>>16; - if(pcilist != nil) - pcitail->list = p; - else - pcilist = p; - pcitail = p; - p->pcr = pcicfgr16(p, PciPCR); p->rid = pcicfgr8(p, PciRID); p->ccrp = pcicfgr8(p, PciCCRp); @@ -502,20 +578,43 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) } rno += 4; } + + p->rom.bar = (ulong)pcicfgr32(p, PciEBAR0); + p->rom.size = pcibarsize(p, PciEBAR0); break; - case 0x05: /* memory controller */ case 0x06: /* bridge device */ + /* cardbus bridge? */ + if(p->ccru == 0x07){ + p->mem[0].bar = (ulong)pcicfgr32(p, PciBAR0); + p->mem[0].size = pcibarsize(p, PciBAR0); + break; + } + + /* pci bridge? */ + if(p->ccru != 0x04) + break; + + p->rom.bar = (ulong)pcicfgr32(p, PciEBAR1); + p->rom.size = pcibarsize(p, PciEBAR1); + break; + case 0x05: /* memory controller */ default: break; } p->parent = parent; if(head != nil) - tail->link = p; + *tail = p; else head = p; - tail = p; + tail = &p->link; + + if(pcilist != nil) + *pcitail = p; + else + pcilist = p; + pcitail = &p->list; } } @@ -529,6 +628,7 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) if(p->ccru == 0x04) break; default: + /* check and clear invalid membars for non bridges */ for(i = 0; i < nelem(p->mem); i++) { if(p->mem[i].size == 0) continue; @@ -540,9 +640,24 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) pcisetbar(p, PciBAR0 + i*4, p->mem[i].bar); } } + if(p->rom.size) { + if((p->rom.bar & 1) == 0 + || !pcivalidbar(p, p->rom.bar & ~0x7FFUL, p->rom.size)){ + p->rom.bar = 0; + pcisetbar(p, PciEBAR0, p->rom.bar); + } + } continue; } + if(p->rom.size) { + if((p->rom.bar & 1) == 0 + || !pcivalidbar(p, p->rom.bar & ~0x7FFULL, p->rom.size)){ + p->rom.bar = 0; + pcisetbar(p, PciEBAR1, p->rom.bar); + } + } + /* * If the secondary or subordinate bus number is not * initialised try to do what the PCI BIOS should have @@ -581,7 +696,7 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) pcisetwin(p, 0xFFF00000|0, 0); pcisetwin(p, 0xFFF00000|8, 0); - maxubn = pcilscan(sbn, &p->bridge, p); + maxubn = pciscan(sbn, &p->bridge, p); l = (maxubn<<16)|(sbn<<8)|bno; pcicfgw32(p, PciPBN, l); @@ -635,19 +750,13 @@ pcilscan(int bno, Pcidev** list, Pcidev *parent) if(ubn > maxubn) maxubn = ubn; - pcilscan(sbn, &p->bridge, p); + pciscan(sbn, &p->bridge, p); } } return maxubn; } -int -pciscan(int bno, Pcidev **list) -{ - return pcilscan(bno, list, nil); -} - void pcibussize(Pcidev *root, uvlong *msize, ulong *iosize) { @@ -720,6 +829,8 @@ pcilhinv(Pcidev* p) continue; print("%d:%.8llux %d ", i, t->mem[i].bar, t->mem[i].size); } + if(t->rom.bar || t->rom.size) + print("rom:%.8llux %d ", t->rom.bar, t->rom.size); if(t->ioa.bar || t->ioa.size) print("ioa:%.8llux-%.8llux %d ", t->ioa.bar, t->ioa.bar+t->ioa.size, t->ioa.size); if(t->mema.bar || t->mema.size) diff --git a/sys/src/9/port/pci.h b/sys/src/9/port/pci.h index fc84d1e2b..7d4acb2f8 100644 --- a/sys/src/9/port/pci.h +++ b/sys/src/9/port/pci.h @@ -96,7 +96,7 @@ enum { /* type 1 pre-defined header */ PciPULR = 0x2C, /* prefetchable limit upper 32 bits */ PciIUBR = 0x30, /* I/O base upper 16 bits */ PciIULR = 0x32, /* I/O limit upper 16 bits */ - PciEBAR1 = 0x28, /* expansion ROM base address */ + PciEBAR1 = 0x38, /* expansion ROM base address */ PciBCR = 0x3E, /* bridge control register */ }; @@ -173,30 +173,33 @@ struct Pcidev uchar cls; uchar ltr; + uchar intl; /* interrupt line */ + struct { uvlong bar; /* base address */ int size; } mem[6]; - struct { + struct { /* expansion rom bar */ uvlong bar; int size; } rom; - uchar intl; /* interrupt line */ + + struct { /* 32-bit io and memory windows */ + uvlong bar; + int size; + } ioa, mema; + + struct { /* 64-bit prefechable memory window */ + uvlong bar; + uvlong size; + } prefa; Pcidev* list; Pcidev* link; /* next device on this bno */ Pcidev* parent; /* up a bus */ Pcidev* bridge; /* down a bus */ - struct { - uvlong bar; - int size; - } ioa, mema; - struct { - uvlong bar; - uvlong size; - } prefa; int pmrb; /* power management register block */ int msi; /* MSI capability register block */ @@ -221,6 +224,8 @@ enum extern int pcimaxdno; +extern void pcidevfree(Pcidev* pcidev); + extern int pcicfgr32(Pcidev* pcidev, int rno); extern void pcicfgw32(Pcidev* pcidev, int rno, int data); extern int pcicfgr16(Pcidev* pcidev, int rno); @@ -228,7 +233,7 @@ extern void pcicfgw16(Pcidev* pcidev, int rno, int data); extern int pcicfgr8(Pcidev* pcidev, int rno); extern void pcicfgw8(Pcidev* pcidev, int rno, int data); -extern int pciscan(int bno, Pcidev **list); +extern int pciscan(int bno, Pcidev **list, Pcidev *parent); extern void pcibusmap(Pcidev *root, uvlong *pmema, ulong *pioa, int wrreg); extern void pcibussize(Pcidev *root, uvlong *msize, ulong *iosize); diff --git a/sys/src/9/teg2/pciteg.c b/sys/src/9/teg2/pciteg.c index d6cc8a291..96430ee36 100644 --- a/sys/src/9/teg2/pciteg.c +++ b/sys/src/9/teg2/pciteg.c @@ -181,7 +181,7 @@ pcicfginit(void) list = &pciroot; /* was bno = 0; trimslice needs to start at 1 */ for(bno = 1; bno <= pcimaxbno; bno++) { - bno = pciscan(bno, list); + bno = pciscan(bno, list, nil); while(*list) list = &(*list)->link; }