ref: a0404ff58245f16d2117542d2dffd1fc6199943d
parent: 35558431105e4c793673310bd5bfa7f8a99d89e3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Mar 1 12:24:54 EST 2021
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.
--- a/sys/src/9/bcm64/pcibcm.c
+++ b/sys/src/9/bcm64/pcibcm.c
@@ -210,7 +210,7 @@
fmtinstall('T', tbdffmt);
- pciscan(0, &pciroot);
+ pciscan(0, &pciroot, nil);
if(pciroot == nil)
return;
--- a/sys/src/9/mtx/pcimtx.c
+++ b/sys/src/9/mtx/pcimtx.c
@@ -67,7 +67,7 @@
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;
--- a/sys/src/9/pc/devpccard.c
+++ b/sys/src/9/pc/devpccard.c
@@ -101,7 +101,6 @@
PciPMC = 0xa4,
- Nbars = 6,
Ncmd = 10,
CBIRQ = 9,
@@ -346,7 +345,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
static int initialized;
Pcidev *pci;
int i;
- uchar intl;
char *p;
if (initialized)
@@ -539,9 +537,7 @@
/* Find all CardBus controllers */
pci = nil;
- intl = 0xff;
while ((pci = pcimatch(pci, 0, 0)) != nil) {
- uvlong baddr;
Cardbus *cb;
uchar pin;
@@ -559,21 +555,21 @@
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) {
static int busbase = 0x20;
@@ -590,7 +586,7 @@
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 @@
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 @@
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,12 +700,12 @@
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;
@@ -731,7 +712,7 @@
}
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 @@
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 @@
}
/* 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 */
+ /* size the devices on the bus, reserve a minimum for devices arriving later */
+ pcibussize(cb->pci->bridge, &memlen, &iolen);
- 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;
- }
- }
-
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 @@
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++;
}
+ iofree(cb->pci->ioa.bar);
+ cb->pci->ioa.bar = 0;
+ cb->pci->ioa.size = 0;
+ }
- 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;
+ /* 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 @@
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 @@
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 @@
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;
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -351,13 +351,19 @@
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;
--- a/sys/src/9/pc/pcipc.c
+++ b/sys/src/9/pc/pcipc.c
@@ -557,6 +557,10 @@
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 @@
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;
--- a/sys/src/9/port/pci.c
+++ b/sys/src/9/port/pci.c
@@ -18,8 +18,7 @@
int pcimaxdno;
static Lock pcicfglock;
-static Pcidev* pcilist;
-static Pcidev* pcitail;
+static Pcidev *pcilist, **pcitail;
static char* bustypes[] = {
"CBUSI",
@@ -68,6 +67,46 @@
}
}
+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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 @@
}
}
-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 @@
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,10 +578,27 @@
}
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;
}
@@ -512,10 +605,16 @@
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 @@
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 @@
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 @@
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,7 +750,7 @@
if(ubn > maxubn)
maxubn = ubn;
- pcilscan(sbn, &p->bridge, p);
+ pciscan(sbn, &p->bridge, p);
}
}
@@ -642,12 +757,6 @@
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 @@
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)
--- a/sys/src/9/port/pci.h
+++ b/sys/src/9/port/pci.h
@@ -96,7 +96,7 @@
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,31 +173,34 @@
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 */
- Pcidev* list;
- Pcidev* link; /* next device on this bno */
-
- Pcidev* parent; /* up a bus */
- Pcidev* bridge; /* down a bus */
- struct {
+ struct { /* 32-bit io and memory windows */
uvlong bar;
int size;
} ioa, mema;
- struct {
+
+ 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 */
+
int pmrb; /* power management register block */
int msi; /* MSI capability register block */
};
@@ -221,6 +224,8 @@
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 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);
--- a/sys/src/9/teg2/pciteg.c
+++ b/sys/src/9/teg2/pciteg.c
@@ -181,7 +181,7 @@
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;
}