From af8657b8dafa07c6e00e883a67e76474443e3742 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 22 Nov 2014 17:23:46 +0100 Subject: pc, pc64: more conservative pcirouting when we hit a conflict where the pci INTL register gives us a different irq than we get from southbridge irq router, dont just change the router setting to the bios assigned irq (that was previously known as the BIOS workarround), but assume the southbridge setting to be valid and change the pci INTL register on the device to it. only when the router link doesnt seem to be configured or disabled, then program the router to the irq that bios asisgned in the INTL register. the reason is that changing the router setting changes the irq routing for *all* devices on the same link and changing it breaks previously checked and valid interrupt routings. (so happend with virtualbox where the last device on the bus is some powermanagement device that has wrong INTL setting and changing the routing breaks the ethernet interrupts) this change shouldnt affect modern machines which use ioapic and mp tables or acpi for pci interrupt routing. --- sys/src/9/pc/pci.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/sys/src/9/pc/pci.c b/sys/src/9/pc/pci.c index a77c149c6..1242892a5 100644 --- a/sys/src/9/pc/pci.c +++ b/sys/src/9/pc/pci.c @@ -746,11 +746,11 @@ pcirouting(void) { Slot *e; Router *r; - int size, i, fn, tbdf; + int i, size, tbdf; Pcidev *sbpci, *pci; uchar *p, pin, irq, link, *map; - if((p = sigsearch("$PIR")) == 0) + if((p = sigsearch("$PIR")) == nil) return; r = (Router*)p; @@ -761,14 +761,14 @@ pcirouting(void) if(0) print("PCI interrupt routing table version %d.%d at %p\n", r->version[0], r->version[1], r); - tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8); + tbdf = MKBUS(BusPCI, r->bus, (r->devfn>>3)&0x1f, r->devfn&7); sbpci = pcimatchtbdf(tbdf); if(sbpci == nil) { print("pcirouting: Cannot find south bridge %T\n", tbdf); return; } - for(i = 0; i != nelem(southbridges); i++) + for(i = 0; i < nelem(southbridges); i++) if(sbpci->vid == southbridges[i].vid && sbpci->did == southbridges[i].did) break; @@ -777,22 +777,21 @@ pcirouting(void) return; } southbridge = &southbridges[i]; - if(southbridge->get == nil || southbridge->set == nil) + if(southbridge->get == nil) return; pciirqs = (r->pciirqs[1] << 8)|r->pciirqs[0]; for(e = (Slot *)&r[1]; (uchar *)e < p + size; e++) { - if (0) { + if(0) { print("%.2uX/%.2uX %.2uX: ", e->bus, e->dev, e->slot); - for (i = 0; i != 4; i++) { - uchar *m = &e->maps[i * 3]; - print("[%d] %.2uX %.4uX ", - i, m[0], (m[2] << 8)|m[1]); + for (i = 0; i < 4; i++) { + map = &e->maps[i * 3]; + print("[%d] %.2uX %.4uX ", i, map[0], (map[2] << 8)|map[1]); } print("\n"); } - for(fn = 0; fn != 8; fn++) { - tbdf = (BusPCI << 24)|(e->bus << 16)|((e->dev | fn) << 8); + for(i = 0; i < 8; i++) { + tbdf = MKBUS(BusPCI, e->bus, (e->dev>>3)&0x1f, i); pci = pcimatchtbdf(tbdf); if(pci == nil) continue; @@ -800,18 +799,20 @@ pcirouting(void) if(pin == 0 || pin == 0xff) continue; - map = &e->maps[(pin - 1) * 3]; + map = &e->maps[((pin - 1) % 4) * 3]; link = map[0]; irq = southbridge->get(sbpci, link); - if(irq == 0 || irq == pci->intl) - continue; - if(pci->intl != 0 && pci->intl != 0xFF) { - 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); + if(irq == pci->intl) continue; + if(irq == 0 || (irq & 0x80) != 0){ + irq = pci->intl; + if(irq == 0 || irq == 0xff) + continue; + if(southbridge->set == nil) + continue; + southbridge->set(sbpci, link, irq); } - print("pcirouting: %T at pin %d link %d irq %d\n", tbdf, pin, link, irq); + print("pcirouting: %T at pin %d link %.2uX irq %d -> %d\n", tbdf, pin, link, pci->intl, irq); pcicfgw8(pci, PciINTL, irq); pci->intl = irq; } -- cgit v1.2.3