static void scan_pci(int busarg, int devarg, int funcarg, void (*cb)(u_int, u_int, u_int)) { u_int busmin, busmax; u_int devmin, devmax; u_int funcmin, funcmax; u_int bus, dev, func; pcireg_t id, bhlcr; if (busarg == -1) { busmin = 0; busmax = 255; } else busmin = busmax = busarg; if (devarg == -1) { devmin = 0; if (pci_businfo.maxdevs <= 0) devmax = 0; else devmax = pci_businfo.maxdevs - 1; } else devmin = devmax = devarg; for (bus = busmin; bus <= busmax; bus++) { for (dev = devmin; dev <= devmax; dev++) { if (pcibus_conf_read(pcifd, bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0) continue; if (funcarg == -1) { funcmin = 0; if (PCI_HDRTYPE_MULTIFN(bhlcr)) funcmax = 7; else funcmax = 0; } else funcmin = funcmax = funcarg; for (func = funcmin; func <= funcmax; func++) { if (pcibus_conf_read(pcifd, bus, dev, func, PCI_ID_REG, &id) != 0) continue; /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* * XXX Not invalid, but we've done this * ~forever. */ if (PCI_VENDOR(id) == 0) continue; (*cb)(bus, dev, func); } } } }
static int pci_nfuncs(int domain, int bus, int dev) { uint32_t hdr; if (domain < 0 || domain >= ndomains) return ENXIO; if (pci_read(domain, bus, dev, 0, PCI_BHLC_REG, &hdr) != 0) return -1; return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1); }
void mpbios_intr_fixup(void) { const struct mpbios_icu_table *mpit = NULL; pci_chipset_tag_t pc = NULL; pcitag_t icutag; int device, maxdevs = pci_bus_maxdevs(pc, 0); /* Search configuration space for a known interrupt 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); /* Invalid vendor ID value? */ if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID) continue; 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; if ((mpit = mpbios_icu_lookup(icuid))) break; } if (mpit != NULL) break; } if (mpit) mpit->mpit_mpbios_fixup(pc, icutag); }
void pci_device_foreach(struct shpcic_softc *sc, pci_chipset_tag_t pc, int maxbus, void (*func)(struct shpcic_softc *, pci_chipset_tag_t, pcitag_t)) { const struct pci_quirkdata *qd; int bus, device, function, maxdevs, nfuncs; pcireg_t id, bhlcr; pcitag_t tag; for (bus = 0; bus <= maxbus; bus++) { maxdevs = pci_bus_maxdevs(pc, bus); for (device = 0; device < maxdevs; device++) { tag = pci_make_tag(pc, bus, device, 0); id = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); bhlcr = pci_conf_read(pc, tag, 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++) { tag = pci_make_tag(pc, bus, device, function); id = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* * XXX Not invalid, but we've done this * ~forever. */ if (PCI_VENDOR(id) == 0) continue; (*func)(sc, pc, tag); } } } }
void pciaddr_remap(pci_chipset_tag_t pc) { pcitag_t devtag; int device; /* Must fix up all PCI devices, ahc_pci expects proper i/o mapping */ for (device = 1; device < 4; device++) { const struct pci_quirkdata *qd; int function, nfuncs; pcireg_t bhlcr, id; devtag = pci_make_tag(pc, 0, device, 0); id = pci_conf_read(pc, devtag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); bhlcr = pci_conf_read(pc, devtag, 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++) { devtag = pci_make_tag(pc, 0, device, function); id = pci_conf_read(pc, devtag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* Not invalid, but we've done this ~forever */ if (PCI_VENDOR(id) == 0) continue; pciaddr_resource_manage(pc, devtag, NULL); } } }
static int pci_scan_bus(struct pci_bus *bus) { int totaldev = 0; struct pci_func df; memset(&df, 0, sizeof(df)); df.bus = bus; for (df.dev = 0; df.dev < 32; df.dev++) { uint32_t bhlc = pci_conf_read(&df, PCI_BHLC_REG); struct pci_func f; if (PCI_HDRTYPE_TYPE(bhlc) > 1) /* Unsupported or no device */ continue; /* found a device */ totaldev++; f = df; for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1); f.func++) { struct pci_func *af; uint32_t dev_id; uint32_t intr; dev_id = pci_conf_read(&f, PCI_ID_REG); if (PCI_VENDOR(dev_id) == 0xffff) continue; /* found a function */ af = kmem_alloc(sizeof(*af)); *af = f; list_init(&af->link); list_insert(&pci_func_list, &af->link); af->dev_id = dev_id; intr = pci_conf_read(af, PCI_INTERRUPT_REG); af->irq_line = PCI_INTERRUPT_LINE(intr); af->dev_class = pci_conf_read(af, PCI_CLASS_REG); #ifdef SHOW_PCI_VERBOSE_INFO pci_print_func(af); #endif } } return totaldev; }
static bus_addr_t pucprobe_doit(struct consdev *cn) { struct pci_attach_args pa; int bus; static int dev = 0, func = 0; int maxdev, nfunctions = 0, i; /* XXX */ pcireg_t reg, bhlcr, subsys = 0; /* XXX */ int foundport = 0; const struct puc_device_description *desc; pcireg_t base; /* Fetch our tags */ if (cpu_comcnprobe(cn, &pa) != 0) { return 0; } puctag = pa.pa_iot; pci_decompose_tag(pa.pa_pc, pa.pa_tag, &bus, &maxdev, NULL); /* scan through devices */ for (; dev <= maxdev ; dev++) { pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, 0); reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || PCI_VENDOR(reg) == 0) continue; bhlcr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(bhlcr)) { nfunctions = 8; } else { nfunctions = 1; } resume_scan: for (; func < nfunctions; func++) { pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, func); reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_CLASS_REG); if (PCI_CLASS(reg) == PCI_CLASS_COMMUNICATIONS && PCI_SUBCLASS(reg) == PCI_SUBCLASS_COMMUNICATIONS_SERIAL) { pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); subsys = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_SUBSYS_ID_REG); foundport = 1; break; } } if (foundport) break; func = 0; } if (!foundport) return 0; foundport = 0; desc = puc_find_description(PCI_VENDOR(pa.pa_id), PCI_PRODUCT(pa.pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys)); if (desc == NULL) { func++; goto resume_scan; } for (i = 0; PUC_PORT_VALID(desc, i); i++) { if (desc->ports[i].type != PUC_PORT_TYPE_COM) continue; base = pci_conf_read(pa.pa_pc, pa.pa_tag, desc->ports[i].bar); base += desc->ports[i].offset; if (PCI_MAPREG_TYPE(base) != PCI_MAPREG_TYPE_IO) continue; base = PCI_MAPREG_IO_ADDR(base); if (com_is_console(puctag, base, NULL)) continue; foundport = 1; break; } if (foundport == 0) { func++; goto resume_scan; } cn->cn_pri = CN_REMOTE; return PCI_MAPREG_IO_ADDR(base); }
/* * We can't use the generic pci_enumerate_bus, because the hypervisor * may hide the function 0 from us, while other functions are * available */ int xen_pci_enumerate_bus(struct pci_softc *sc, const int *locators, int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) { pci_chipset_tag_t pc = sc->sc_pc; int device, function, nfunctions, ret; const struct pci_quirkdata *qd; pcireg_t id, bhlcr; pcitag_t tag; for (device = 0; device < sc->sc_maxndevs; device++) { if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && (locators[PCICF_DEV] != device)) continue; tag = pci_make_tag(pc, sc->sc_bus, device, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); id = pci_conf_read(pc, tag, PCI_ID_REG); qd = NULL; if (PCI_VENDOR(id) != PCI_VENDOR_INVALID) { /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; if (PCI_HDRTYPE_TYPE(bhlcr) > 2) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); if (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) nfunctions = 8; else if (qd != NULL && (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) nfunctions = 1; else nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; } else { /* * Vendor ID invalid. This may be because there's no * device, or because the hypervisor is hidding * function 0 from us. Try to probe other functions * anyway. */ nfunctions = 8; } for (function = 0; function < nfunctions; function++) { if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) && (locators[PCICF_FUNCTION] != function)) continue; if (qd != NULL && (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) continue; tag = pci_make_tag(pc, sc->sc_bus, device, function); ret = pci_probe_device(sc, tag, match, pap); if (match != NULL && ret != 0) return (ret); } } return (0); }
/* * Generic PCI bus enumeration routine. Used unless machine-dependent * code needs to provide something else. */ int pci_enumerate_bus(struct pci_softc *sc, const int *locators, int (*match)(const struct pci_attach_args *), struct pci_attach_args *pap) { pci_chipset_tag_t pc = sc->sc_pc; int device, function, nfunctions, ret; const struct pci_quirkdata *qd; pcireg_t id, bhlcr; pcitag_t tag; uint8_t devs[32]; int i, n; n = pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs, __arraycount(devs)); for (i = 0; i < n; i++) { device = devs[i]; if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && (locators[PCICF_DEV] != device)) continue; tag = pci_make_tag(pc, sc->sc_bus, device, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) > 2) continue; id = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(id) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); if (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) nfunctions = 8; else if (qd != NULL && (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) nfunctions = 1; else nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; #ifdef __PCI_DEV_FUNCORDER char funcs[8]; int j; for (j = 0; j < nfunctions; j++) { funcs[j] = j; } if (j < __arraycount(funcs)) funcs[j] = -1; if (nfunctions > 1) { pci_dev_funcorder(sc->sc_pc, sc->sc_bus, device, nfunctions, funcs); } for (j = 0; j < 8 && (function = funcs[j]) < 8 && function >= 0; j++) { #else for (function = 0; function < nfunctions; function++) { #endif if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) && (locators[PCICF_FUNCTION] != function)) continue; if (qd != NULL && (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) continue; tag = pci_make_tag(pc, sc->sc_bus, device, function); ret = pci_probe_device(sc, tag, match, pap); if (match != NULL && ret != 0) return ret; } } return 0; } #endif /* PCI_MACHDEP_ENUMERATE_BUS */ /* * Vital Product Data (PCI 2.2) */ int pci_vpd_read(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, pcireg_t *data) { uint32_t reg; int ofs, i, j; KASSERT(data != NULL); KASSERT((offset + count) < 0x7fff); if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) return 1; for (i = 0; i < count; offset += sizeof(*data), i++) { reg &= 0x0000ffff; reg &= ~PCI_VPD_OPFLAG; reg |= PCI_VPD_ADDRESS(offset); pci_conf_write(pc, tag, ofs, reg); /* * PCI 2.2 does not specify how long we should poll * for completion nor whether the operation can fail. */ j = 0; do { if (j++ == 20) return 1; delay(4); reg = pci_conf_read(pc, tag, ofs); } while ((reg & PCI_VPD_OPFLAG) == 0); data[i] = pci_conf_read(pc, tag, PCI_VPD_DATAREG(ofs)); } return 0; }
/* * Set up bus common stuff, then loop over devices & functions. * If we find something, call pci_do_device_query()). */ static int probe_bus(pciconf_bus_t *pb) { int device, maxdevs; #ifdef __PCI_BUS_DEVORDER char devs[32]; int i; #endif maxdevs = pci_bus_maxdevs(pb->pc, pb->busno); pb->ndevs = 0; pb->niowin = 0; pb->nmemwin = 0; pb->freq_66 = 1; pb->fast_b2b = 1; pb->prefetch = 1; pb->max_mingnt = 0; /* we are looking for the maximum */ pb->min_maxlat = 0x100; /* we are looking for the minimum */ pb->bandwidth_used = 0; #ifdef __PCI_BUS_DEVORDER pci_bus_devorder(pb->pc, pb->busno, devs); for (i=0; (device=devs[i]) < 32 && device >= 0; i++) { #else for (device=0; device < maxdevs; device++) { #endif pcitag_t tag; pcireg_t id, bhlcr; int function, nfunction; int confmode; tag = pci_make_tag(pb->pc, pb->busno, device, 0); if (pci_conf_debug) { print_tag(pb->pc, tag); } id = pci_conf_read(pb->pc, tag, PCI_ID_REG); if (pci_conf_debug) { printf("id=%x: Vendor=%x, Product=%x\n", id, PCI_VENDOR(id),PCI_PRODUCT(id)); } /* Invalid vendor ID value? */ if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; bhlcr = pci_conf_read(pb->pc, tag, PCI_BHLC_REG); nfunction = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; for (function = 0 ; function < nfunction ; function++) { tag = pci_make_tag(pb->pc, pb->busno, device, function); id = pci_conf_read(pb->pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) continue; if (pb->ndevs+1 < MAX_CONF_DEV) { if (pci_conf_debug) { print_tag(pb->pc, tag); printf("Found dev 0x%04x 0x%04x -- " "really probing.\n", PCI_VENDOR(id), PCI_PRODUCT(id)); } #ifdef __HAVE_PCI_CONF_HOOK confmode = pci_conf_hook(pb->pc, pb->busno, device, function, id); if (confmode == 0) continue; #else /* * Don't enable expansion ROMS -- some cards * share address decoders between the EXPROM * and PCI memory space, and enabling the ROM * when not needed will cause all sorts of * lossage. */ confmode = PCI_CONF_ALL & ~PCI_CONF_MAP_ROM; #endif if (pci_do_device_query(pb, tag, device, function, confmode)) return -1; pb->ndevs++; } } } return 0; } static void alloc_busno(pciconf_bus_t *parent, pciconf_bus_t *pb) { pb->busno = parent->next_busno; if (parent->next_busno + parent->busno_spacing > parent->last_busno) panic("Too many PCI busses on bus %d", parent->busno); parent->next_busno = parent->next_busno + parent->busno_spacing; pb->next_busno = pb->busno+1; pb->busno_spacing = parent->busno_spacing >> 1; if (!pb->busno_spacing) panic("PCI busses nested too deep."); pb->last_busno = parent->next_busno - 1; }
static bus_addr_t pucprobe_doit(struct consdev *cn) { struct pci_attach_args pa; int bus; static int dev = 0, func = 0; int maxdev, nfunctions = 0, i; /* XXX */ pcireg_t reg, bhlcr, subsys = 0; /* XXX */ int foundport = 0; const struct puc_device_description *desc; pcireg_t base; /* Fetch our tags */ #if defined(amd64) || defined(i386) if (cpu_puc_cnprobe(cn, &pa) != 0) #endif return 0; pci_decompose_tag(pa.pa_pc, pa.pa_tag, &bus, &maxdev, NULL); /* Scan through devices and find a communication class device. */ for (; dev <= maxdev ; dev++) { pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, 0); reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID || PCI_VENDOR(reg) == 0) continue; bhlcr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(bhlcr)) { nfunctions = 8; } else { nfunctions = 1; } resume_scan: for (; func < nfunctions; func++) { pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, func); reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_CLASS_REG); if (PCI_CLASS(reg) == PCI_CLASS_COMMUNICATIONS && PCI_SUBCLASS(reg) == PCI_SUBCLASS_COMMUNICATIONS_SERIAL) { pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); subsys = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_SUBSYS_ID_REG); foundport = 1; break; } } if (foundport) break; func = 0; } /* * If all devices was scanned and couldn't find any communication * device, return with 0. */ if (!foundport) return 0; /* Clear foundport flag */ foundport = 0; /* Check whether the device is in the puc device table or not */ desc = puc_find_description(PCI_VENDOR(pa.pa_id), PCI_PRODUCT(pa.pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys)); /* If not, check the next communication device */ if (desc == NULL) { /* Resume from the next function */ func++; goto resume_scan; } /* * We found a device and it's on the puc table. Set the tag and * the base address. */ for (i = 0; PUC_PORT_VALID(desc, i); i++) { if (desc->ports[i].type != PUC_PORT_TYPE_COM) continue; puccnflags = desc->ports[i].flags; base = pci_conf_read(pa.pa_pc, pa.pa_tag, desc->ports[i].bar); base += desc->ports[i].offset; if (PCI_MAPREG_TYPE(base) == PCI_MAPREG_TYPE_IO) { puctag = pa.pa_iot; base = PCI_MAPREG_IO_ADDR(base); } #if 0 /* For MMIO device */ else { puctag = pa.pa_memt; base = PCI_MAPREG_MEM_ADDR(base); } #endif if (com_is_console(puctag, base, NULL)) continue; foundport = 1; break; } if (foundport == 0) { func++; goto resume_scan; } #if 0 cn->cn_pri = CN_REMOTE; #else if (cn) cn->cn_pri = CN_REMOTE; #endif return base; }
int pci_bus_fixup(pci_chipset_tag_t pc, int bus) { static int bus_total; static int bridge_cnt; int device, maxdevs, function, nfuncs, bridge, bus_max, bus_sub; const struct pci_quirkdata *qd; pcireg_t reg; pcitag_t tag; bus_max = bus; bus_sub = 0; if (++bus_total > 256) panic("pci_bus_fixup: more than 256 PCI busses?"); /* Reset bridge configuration on this bus */ pci_bridge_foreach(pc, bus, bus, pci_bridge_reset, 0); maxdevs = pci_bus_maxdevs(pc, bus); for (device = 0; device < maxdevs; device++) { tag = pci_make_tag(pc, bus, device, 0); reg = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(reg) == 0) continue; qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); reg = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_MULTIFN(reg) || (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) nfuncs = 8; else nfuncs = 1; for (function = 0; function < nfuncs; function++) { tag = pci_make_tag(pc, bus, device, function); reg = pci_conf_read(pc, tag, PCI_ID_REG); /* Invalid vendor ID value? */ if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID) continue; /* XXX Not invalid, but we've done this ~forever. */ if (PCI_VENDOR(reg) == 0) continue; aprint_debug("PCI fixup examining %02x:%02x\n", PCI_VENDOR(reg), PCI_PRODUCT(reg)); reg = pci_conf_read(pc, tag, PCI_CLASS_REG); if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI || PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) { /* Assign the bridge #. */ bridge = bridge_cnt++; /* Assign the bridge's secondary bus #. */ bus_max++; reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO); reg &= 0xff000000; reg |= bus | (bus_max << 8) | (0xff << 16); pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); /* Scan subordinate bus. */ bus_sub = pci_bus_fixup(pc, bus_max); /* Configure the bridge. */ reg &= 0xff000000; reg |= bus | (bus_max << 8) | (bus_sub << 16); pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg); /* record relationship */ pci_bus_parent[bus_max]=bus; pci_bus_tag[bus_max]=tag; aprint_debug("PCI bridge %d: primary %d, " "secondary %d, subordinate %d\n", bridge, bus, bus_max, bus_sub); /* Next bridge's secondary bus #. */ bus_max = (bus_sub > bus_max) ? bus_sub : bus_max; } } } return (bus_max); /* last # of subordinate bus */ }