summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2001-05-12 21:01:54 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2001-05-12 21:01:54 +0000
commit581920fcf962851a624f7a04e3c9ec5d6a649df1 (patch)
tree8c36e589922f95753b6e72b02ab103fa616e85bd /sys/arch/i386
parent7943beacaf964ed4004bc56762890e11a76f0ad6 (diff)
A number of buggy BIOS implementations leave the router
entry as 000:00:0, which is typically not the correct device/function. If the router device address is set to this value, and the compatible router entry is undefined (zero is the correct value to indicate undefined), then we work on the basis it is most likely an error, and search the entire device-space of bus 0 (but obviously starting with 000:00:0, in case that really is the right one). from Dave Sainty <dave@dtsp.co.nz>
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/pci/pci_intr_fixup.c79
1 files changed, 60 insertions, 19 deletions
diff --git a/sys/arch/i386/pci/pci_intr_fixup.c b/sys/arch/i386/pci/pci_intr_fixup.c
index 8dc53ad83da..bed4e666372 100644
--- a/sys/arch/i386/pci/pci_intr_fixup.c
+++ b/sys/arch/i386/pci/pci_intr_fixup.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pci_intr_fixup.c,v 1.14 2001/05/12 19:12:44 mickey Exp $ */
+/* $OpenBSD: pci_intr_fixup.c,v 1.15 2001/05/12 21:01:53 mickey Exp $ */
/* $NetBSD: pci_intr_fixup.c,v 1.10 2000/08/10 21:18:27 soda Exp $ */
/*
@@ -668,7 +668,6 @@ pci_intr_fixup(sc, pc, iot)
struct pcibios_pir_header *pirh = &pcibios_pir_header;
const struct pciintr_icu_table *piit = NULL;
pcitag_t icutag;
- pcireg_t icuid;
/*
* Attempt to initialize our PCI interrupt router. If
@@ -676,22 +675,33 @@ pci_intr_fixup(sc, pc, iot)
* specified by the PIR Table, and use the compat ID,
* if present. Otherwise, we have to look for the router
* ourselves (the PCI-ISA bridge).
+ *
+ * A number of buggy BIOS implementations leave the router
+ * entry as 000:00:0, which is typically not the correct
+ * device/function. If the router device address is set to
+ * this value, and the compatible router entry is undefined
+ * (zero is the correct value to indicate undefined), then we
+ * work on the basis it is most likely an error, and search
+ * the entire device-space of bus 0 (but obviously starting
+ * with 000:00:0, in case that really is the right one).
*/
- if (pirh->signature != 0) {
- icutag = pci_make_tag(pc, pirh->router_bus,
- PIR_DEVFUNC_DEVICE(pirh->router_devfunc),
- PIR_DEVFUNC_FUNCTION(pirh->router_devfunc));
- icuid = pirh->compat_router;
- if (icuid == 0 ||
- (piit = pciintr_icu_lookup(icuid)) == NULL) {
+ if (pirh->signature != 0 && (pirh->router_bus != 0 ||
+ pirh->router_devfunc != 0 || pirh->compat_router != 0)) {
+
+ if (pirh->compat_router == 0 ||
+ (piit = pciintr_icu_lookup(pirh->compat_router)) == NULL) {
/*
* No compat ID, or don't know the compat ID? Read
* it from the configuration header.
*/
- icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
+ pirh->compat_router = pci_conf_read(pc,
+ pci_make_tag(pc, pirh->router_bus,
+ PIR_DEVFUNC_DEVICE(pirh->router_devfunc),
+ PIR_DEVFUNC_FUNCTION(pirh->router_devfunc)),
+ PCI_ID_REG);
}
if (piit == NULL)
- piit = pciintr_icu_lookup(icuid);
+ piit = pciintr_icu_lookup(pirh->compat_router);
} else {
int device, maxdevs = pci_bus_maxdevs(pc, 0);
@@ -700,6 +710,11 @@ pci_intr_fixup(sc, pc, iot)
* router.
*/
for (device = 0; device < maxdevs; device++) {
+ const struct pci_quirkdata *qd;
+ int function, nfuncs;
+ pcireg_t icuid;
+ pcireg_t bhlcr;
+
icutag = pci_make_tag(pc, 0, device, 0);
icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
@@ -710,21 +725,47 @@ pci_intr_fixup(sc, pc, iot)
if (PCI_VENDOR(icuid) == 0)
continue;
- if ((piit = pciintr_icu_lookup(icuid))) {
- pirh->compat_router = icuid;
- pirh->router_bus = 0;
- pirh->router_devfunc =
- PIR_DEVFUNC_COMPOSE(device, 0);
- break;
+ qd = pci_lookup_quirkdata(PCI_VENDOR(icuid),
+ PCI_PRODUCT(icuid));
+
+ bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG);
+ if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL &&
+ (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
+ nfuncs = 8;
+ else
+ nfuncs = 1;
+
+ for (function = 0; function < nfuncs; function++) {
+ icutag = pci_make_tag(pc, 0, device, function);
+ icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
+
+ /* Invalid vendor ID value? */
+ if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
+ continue;
+ /* Not invalid, but we've done this ~forever. */
+ if (PCI_VENDOR(icuid) == 0)
+ continue;
+
+ if ((piit = pciintr_icu_lookup(icuid))) {
+ pirh->compat_router = icuid;
+ pirh->router_bus = 0;
+ pirh->router_devfunc =
+ PIR_DEVFUNC_COMPOSE(device, 0);
+ break;
+ }
}
+
+ if (piit != NULL)
+ break;
}
}
if (piit == NULL) {
printf("%s: no compatible PCI ICU found", sc->sc_dev.dv_xname);
- if (pirh->signature != 0 && icuid != 0)
+ if (pirh->signature != 0 && pirh->compat_router != 0)
printf(": ICU vendor 0x%04x product 0x%04x",
- PCI_VENDOR(icuid), PCI_PRODUCT(icuid));
+ PCI_VENDOR(pirh->compat_router),
+ PCI_PRODUCT(pirh->compat_router));
printf("\n");
if (!(pcibios_flags & PCIBIOS_INTR_GUESS)) {
if (pciintr_link_init(pc))