From d5ccecfad720336d85ff50a503fdc68354804cc9 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 24 Apr 2002 15:30:11 +0000 Subject: [PATCH] o Work around bugs in the powerof2 macro: It thinks that 0 is a power of 2, but that's not the case. This fixes the case where there were slots in the PIR table that had no bits set, but we assumed they did and used strange results as a result. o Map invalid INTLINE registers to 255 in pci_cfgreg.c. This should allow us to remove the bogus checks in MI code for non-255 values. I put these changes out for review a while ago, but no one responded to them, so into current they go. This should help us work better on machines that don't route interrupts in the traditional way. MFC After: 4286 millifortnights --- sys/amd64/pci/pci_cfgreg.c | 30 ++++++++++++++++++------------ sys/i386/pci/pci_cfgreg.c | 30 ++++++++++++++++++------------ sys/i386/pci/pci_pir.c | 30 ++++++++++++++++++------------ 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c index 825d9b73e5f..27c89127f68 100644 --- a/sys/amd64/pci/pci_cfgreg.c +++ b/sys/amd64/pci/pci_cfgreg.c @@ -178,6 +178,7 @@ pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes) { + uint32_t line, pin; #ifdef APIC_IO /* * If we are using the APIC, the contents of the intline register will probably @@ -186,7 +187,6 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) * attempts to read them and translate to our private vector numbers. */ if ((reg == PCIR_INTLINE) && (bytes == 1)) { - int pin, line; pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); @@ -217,6 +217,18 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) } return(line); } +#else + /* + * Some BIOS writers seem to want to ignore the spec and put + * 0 in the intline rather than 255 to indicate none. The rest of + * the code uses 255 as an invalid IRQ. + */ + if (reg == PCIR_INTLINE && bytes == 1) { + line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); + pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); + if (pin != 0 && (line == 0 || line >= 128)) + return (255); + } #endif /* APIC_IO */ return(pci_do_cfgregread(bus, slot, func, reg, bytes)); } @@ -307,9 +319,11 @@ static int pci_cfgintr_unique(struct PIR_entry *pe, int pin) { int irq; + uint32_t irqmask; - if (powerof2(pe->pe_intpin[pin - 1].irqs)) { - irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1; + irqmask = pe->pe_intpin[pin - 1].irqs; + if (irqmask != 0 && powerof2(irqmask)) { + irq = ffs(irqmask) - 1; PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); return(irq); } @@ -344,7 +358,7 @@ pci_cfgintr_linked(struct PIR_entry *pe, int pin) continue; /* link destination mapped to a unique interrupt? */ - if (powerof2(pi->irqs)) { + if (pi->irqs != 0 && powerof2(pi->irqs)) { irq = ffs(pi->irqs) - 1; PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", pi->link, irq)); @@ -394,14 +408,6 @@ pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int (pci_get_slot(*childp) == device) && (pci_get_intpin(*childp) == matchpin)) { irq = pci_get_irq(*childp); - /* - * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. Once - * we've found one that matches, we break because there can - * be no others (which is why test looks a little odd). - */ - if (irq == 0) - irq = 255; if (irq != 255) PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", pe->pe_intpin[pin - 1].link, irq, diff --git a/sys/i386/pci/pci_cfgreg.c b/sys/i386/pci/pci_cfgreg.c index 825d9b73e5f..27c89127f68 100644 --- a/sys/i386/pci/pci_cfgreg.c +++ b/sys/i386/pci/pci_cfgreg.c @@ -178,6 +178,7 @@ pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes) { + uint32_t line, pin; #ifdef APIC_IO /* * If we are using the APIC, the contents of the intline register will probably @@ -186,7 +187,6 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) * attempts to read them and translate to our private vector numbers. */ if ((reg == PCIR_INTLINE) && (bytes == 1)) { - int pin, line; pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); @@ -217,6 +217,18 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) } return(line); } +#else + /* + * Some BIOS writers seem to want to ignore the spec and put + * 0 in the intline rather than 255 to indicate none. The rest of + * the code uses 255 as an invalid IRQ. + */ + if (reg == PCIR_INTLINE && bytes == 1) { + line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); + pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); + if (pin != 0 && (line == 0 || line >= 128)) + return (255); + } #endif /* APIC_IO */ return(pci_do_cfgregread(bus, slot, func, reg, bytes)); } @@ -307,9 +319,11 @@ static int pci_cfgintr_unique(struct PIR_entry *pe, int pin) { int irq; + uint32_t irqmask; - if (powerof2(pe->pe_intpin[pin - 1].irqs)) { - irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1; + irqmask = pe->pe_intpin[pin - 1].irqs; + if (irqmask != 0 && powerof2(irqmask)) { + irq = ffs(irqmask) - 1; PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); return(irq); } @@ -344,7 +358,7 @@ pci_cfgintr_linked(struct PIR_entry *pe, int pin) continue; /* link destination mapped to a unique interrupt? */ - if (powerof2(pi->irqs)) { + if (pi->irqs != 0 && powerof2(pi->irqs)) { irq = ffs(pi->irqs) - 1; PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", pi->link, irq)); @@ -394,14 +408,6 @@ pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int (pci_get_slot(*childp) == device) && (pci_get_intpin(*childp) == matchpin)) { irq = pci_get_irq(*childp); - /* - * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. Once - * we've found one that matches, we break because there can - * be no others (which is why test looks a little odd). - */ - if (irq == 0) - irq = 255; if (irq != 255) PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", pe->pe_intpin[pin - 1].link, irq, diff --git a/sys/i386/pci/pci_pir.c b/sys/i386/pci/pci_pir.c index 825d9b73e5f..27c89127f68 100644 --- a/sys/i386/pci/pci_pir.c +++ b/sys/i386/pci/pci_pir.c @@ -178,6 +178,7 @@ pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes) u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes) { + uint32_t line, pin; #ifdef APIC_IO /* * If we are using the APIC, the contents of the intline register will probably @@ -186,7 +187,6 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) * attempts to read them and translate to our private vector numbers. */ if ((reg == PCIR_INTLINE) && (bytes == 1)) { - int pin, line; pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); @@ -217,6 +217,18 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes) } return(line); } +#else + /* + * Some BIOS writers seem to want to ignore the spec and put + * 0 in the intline rather than 255 to indicate none. The rest of + * the code uses 255 as an invalid IRQ. + */ + if (reg == PCIR_INTLINE && bytes == 1) { + line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1); + pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1); + if (pin != 0 && (line == 0 || line >= 128)) + return (255); + } #endif /* APIC_IO */ return(pci_do_cfgregread(bus, slot, func, reg, bytes)); } @@ -307,9 +319,11 @@ static int pci_cfgintr_unique(struct PIR_entry *pe, int pin) { int irq; + uint32_t irqmask; - if (powerof2(pe->pe_intpin[pin - 1].irqs)) { - irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1; + irqmask = pe->pe_intpin[pin - 1].irqs; + if (irqmask != 0 && powerof2(irqmask)) { + irq = ffs(irqmask) - 1; PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq)); return(irq); } @@ -344,7 +358,7 @@ pci_cfgintr_linked(struct PIR_entry *pe, int pin) continue; /* link destination mapped to a unique interrupt? */ - if (powerof2(pi->irqs)) { + if (pi->irqs != 0 && powerof2(pi->irqs)) { irq = ffs(pi->irqs) - 1; PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n", pi->link, irq)); @@ -394,14 +408,6 @@ pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int (pci_get_slot(*childp) == device) && (pci_get_intpin(*childp) == matchpin)) { irq = pci_get_irq(*childp); - /* - * Some BIOS writers seem to want to ignore the spec and put - * 0 in the intline rather than 255 to indicate none. Once - * we've found one that matches, we break because there can - * be no others (which is why test looks a little odd). - */ - if (irq == 0) - irq = 255; if (irq != 255) PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n", pe->pe_intpin[pin - 1].link, irq,