/** * Default implementation of implementing BUS_PRINT_CHILD(). */ static int bhnd_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { bhnd_addr_t addr; bhnd_size_t size; if (device_get_parent(child) != dev) { return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, buf, buflen)); } if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { /* No device default port/region */ if (buflen > 0) *buf = '\0'; return (0); } snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); return (0); }
/** * Initialize the full bridge configuration. * * This is called during the DEVICE_ATTACH() process by the bridged bhndb(4) * bus, prior to probe/attachment of child cores. * * At this point, we can introspect the enumerated cores, find our host * bridge device, and apply any bridge-level hardware workarounds required * for proper operation of the bridged device cores. */ static int bhndb_pci_init_full_config(device_t dev, device_t child, const struct bhndb_hw_priority *prio_table) { struct bhnd_core_info core; const struct bhndb_pci_id *id; struct bhndb_pci_softc *sc; struct bhndb_region *pcir; bhnd_addr_t pcir_addr; bhnd_size_t pcir_size; int error; sc = device_get_softc(dev); /* Let bhndb perform full discovery and initialization of the * available register windows and bridge resources. */ if ((error = bhndb_generic_init_full_config(dev, child, prio_table))) return (error); /* * Identify our PCI bridge core, its register family, and any * applicable hardware quirks. */ KASSERT(sc->bhndb.hostb_dev, ("missing hostb device\n")); core = bhnd_get_core_info(sc->bhndb.hostb_dev); id = bhndb_pci_find_core_id(&core); if (id == NULL) { device_printf(dev, "%s %s hostb core is not recognized\n", bhnd_vendor_name(core.vendor), bhnd_core_name(&core)); } sc->regfmt = id->regfmt; /* Now that we've identified the PCI bridge core, we can determine the * full set of device quirks */ sc->quirks = bhndb_pci_discover_quirks(sc, id); /* * Determine and save a reference to the bhndb resource and offset * at which the bridge core's device registers are mapped. * * All known bhnd(4) hardware provides a fixed static mapping of * the PCI core's registers. If this changes in the future -- which * is unlikely -- this driver will need to be adjusted to use * dynamic register windows. */ /* Find base address and size of the PCI core's register block. */ error = bhnd_get_region_addr(sc->bhndb.hostb_dev, BHND_PORT_DEVICE, 0, 0, &pcir_addr, &pcir_size); if (error) { device_printf(dev, "failed to locate PCI core registers\n"); return (error); } /* Find the bhndb_region that statically maps this block */ pcir = bhndb_find_resource_region(sc->bhndb.bus_res, pcir_addr, pcir_size); if (pcir == NULL || pcir->static_regwin == NULL) { device_printf(dev, "missing static PCI core register window\n"); return (ENXIO); } /* Save borrowed reference to the mapped PCI core registers */ sc->mem_off = pcir->static_regwin->win_offset; sc->mem_res = bhndb_find_regwin_resource(sc->bhndb.bus_res, pcir->static_regwin); if (sc->mem_res == NULL || !(rman_get_flags(sc->mem_res) & RF_ACTIVE)) { device_printf(dev, "no active resource maps the PCI core register window\n"); return (ENXIO); } /* Configure a direct bhnd_resource wrapper that we can pass to * bhnd_resource APIs */ sc->bhnd_mem_res = (struct bhnd_resource) { .res = sc->mem_res, .direct = true }; /* * Attach MMIO device (if this is a PCIe device), which is used for * access to the PCIe SerDes required by the quirk workarounds. */ if (sc->pci_devclass == BHND_DEVCLASS_PCIE) { sc->mdio = device_add_child(dev, devclass_get_name(bhnd_mdio_pci_devclass), 0); if (sc->mdio == NULL) return (ENXIO); if ((error = device_probe_and_attach(sc->mdio))) { device_printf(dev, "failed to attach MDIO device\n"); return (error); } } /* Apply any early one-time quirk workarounds */ if ((error = bhndb_pci_wars_early_once(sc))) return (error); /* Apply attach-time quirk workarounds, required before the bridged * bhnd(4) bus itself performs a full attach(). */ if ((error = bhndb_pci_wars_hwup(sc))) return (error); return (0); } /** * Apply any hardware workarounds that must be executed prior to attempting * register access on the bridged chipset. * * This must be called very early in attach() or resume(), after the basic * set of applicable device quirks has been determined. */ static int bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc) { int error; if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) { if ((error = bhndb_enable_pci_clocks(sc))) { device_printf(sc->dev, "failed to enable clocks\n"); return (error); } } return (0); }