diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2021-03-01 17:24:54 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2021-03-01 17:24:54 +0100 |
commit | a0404ff58245f16d2117542d2dffd1fc6199943d (patch) | |
tree | 1eea09a3c9b1426c73858e90f13c77f1bc315bbd /sys/src/9/port/pci.c | |
parent | 35558431105e4c793673310bd5bfa7f8a99d89e3 (diff) |
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.
Diffstat (limited to 'sys/src/9/port/pci.c')
-rw-r--r-- | sys/src/9/port/pci.c | 165 |
1 files changed, 138 insertions, 27 deletions
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) |