summaryrefslogtreecommitdiff
path: root/sys/src/9/port/pci.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2021-03-01 17:24:54 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2021-03-01 17:24:54 +0100
commita0404ff58245f16d2117542d2dffd1fc6199943d (patch)
tree1eea09a3c9b1426c73858e90f13c77f1bc315bbd /sys/src/9/port/pci.c
parent35558431105e4c793673310bd5bfa7f8a99d89e3 (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.c165
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)