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); } } }
int pciprint(void *aux, const char *pnp) { struct pci_attach_args *pa = aux; char devinfo[256]; const struct pci_quirkdata *qd; if (pnp) { pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); aprint_normal("%s at %s", devinfo, pnp); } aprint_normal(" dev %d function %d", pa->pa_device, pa->pa_function); if (pci_config_dump) { printf(": "); pci_conf_print(pa->pa_pc, pa->pa_tag, NULL); if (!pnp) pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); printf("%s at %s", devinfo, pnp ? pnp : "?"); printf(" dev %d function %d (", pa->pa_device, pa->pa_function); #ifdef __i386__ printf("tag %#lx, intrtag %#lx, intrswiz %#lx, intrpin %#lx", *(long *)&pa->pa_tag, *(long *)&pa->pa_intrtag, (long)pa->pa_intrswiz, (long)pa->pa_intrpin); #else printf("intrswiz %#lx, intrpin %#lx", (long)pa->pa_intrswiz, (long)pa->pa_intrpin); #endif printf(", i/o %s, mem %s,", pa->pa_flags & PCI_FLAGS_IO_OKAY ? "on" : "off", pa->pa_flags & PCI_FLAGS_MEM_OKAY ? "on" : "off"); qd = pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), PCI_PRODUCT(pa->pa_id)); if (qd == NULL) { printf(" no quirks"); } else { snprintb(devinfo, sizeof (devinfo), "\002\001multifn\002singlefn\003skipfunc0" "\004skipfunc1\005skipfunc2\006skipfunc3" "\007skipfunc4\010skipfunc5\011skipfunc6" "\012skipfunc7", qd->quirks); printf(" quirks %s", devinfo); } printf(")"); } return UNCONF; }
/* * 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; }
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 */ }