--- //depot/vendor/freebsd/src/sys/amd64/include/resource.h +++ //depot/projects/pci/sys/amd64/include/resource.h @@ -40,5 +40,8 @@ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ +#ifdef NEW_PCIB +#define PCI_RES_BUS 5 /* PCI bus numbers */ +#endif #endif /* !_MACHINE_RESOURCE_H_ */ --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib_acpi.c +++ //depot/projects/pci/sys/dev/acpica/acpi_pcib_acpi.c @@ -44,6 +44,7 @@ #include #include +#include #include #include #include "pcib_if.h" @@ -96,6 +97,11 @@ static int acpi_pcib_acpi_adjust_resource(device_t dev, device_t child, int type, struct resource *r, u_long start, u_long end); +#ifdef PCI_RES_BUS +static int acpi_pcib_acpi_release_resource(device_t dev, + device_t child, int type, int rid, + struct resource *r); +#endif #endif static device_method_t acpi_pcib_acpi_methods[] = { @@ -115,7 +121,11 @@ #else DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), #endif +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + DEVMETHOD(bus_release_resource, acpi_pcib_acpi_release_resource), +#else DEVMETHOD(bus_release_resource, bus_generic_release_resource), +#endif DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), @@ -271,6 +281,20 @@ } #endif +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static int +first_decoded_bus(struct acpi_hpcib_softc *sc, u_long *startp) +{ + struct resource_list_entry *rle; + + rle = resource_list_find(&sc->ap_host_res.hr_rl, PCI_RES_BUS, 0); + if (rle == NULL) + return (ENXIO); + *startp = rle->start; + return (0); +} +#endif + static int acpi_pcib_acpi_attach(device_t dev) { @@ -278,6 +302,11 @@ ACPI_STATUS status; static int bus0_seen = 0; u_int slot, func, busok; +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + struct resource *bus_res; + u_long start; + int rid; +#endif uint8_t busno; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -389,8 +418,41 @@ } } +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) /* * If nothing else worked, hope that ACPI at least lays out the + * Host-PCI bridges in order and that as a result the next free + * bus number is our bus number. + */ + if (busok == 0) { + /* + * If we have a region of bus numbers, use the first + * number for our bus. + */ + if (first_decoded_bus(sc, &start) == 0) + sc->ap_bus = start; + else { + rid = 0; + bus_res = pci_domain_alloc_bus(sc->ap_segment, dev, &rid, 0, + PCI_BUSMAX, 1, 0); + if (bus_res == NULL) { + device_printf(dev, + "could not allocate bus number\n"); + pcib_host_res_free(dev, &sc->ap_host_res); + return (ENXIO); + } + sc->ap_bus = rman_get_start(bus_res); + pci_domain_release_bus(sc->ap_segment, dev, rid, bus_res); + } + } else { +#ifdef INVARIANTS + if (first_decoded_bus(sc, &start) == 0) + KASSERT(start == sc->ap_bus, ("bus number mismatch")); +#endif + } +#else + /* + * If nothing else worked, hope that ACPI at least lays out the * host-PCI bridges in order and that as a result our unit number * is actually our bus number. There are several reasons this * might not be true. @@ -399,6 +461,7 @@ sc->ap_bus = device_get_unit(dev); device_printf(dev, "trying bus number %d\n", sc->ap_bus); } +#endif /* If this is bus 0 on segment 0, note that it has been seen already. */ if (sc->ap_segment == 0 && sc->ap_bus == 0) @@ -534,6 +597,11 @@ #ifdef NEW_PCIB sc = device_get_softc(dev); +#ifdef PCI_RES_BUS + if (type == PCI_RES_BUS) + return (pci_domain_alloc_bus(sc->ap_segment, child, rid, start, end, + count, flags)); +#endif res = pcib_host_res_alloc(&sc->ap_host_res, child, type, rid, start, end, count, flags); @@ -562,7 +630,26 @@ struct acpi_hpcib_softc *sc; sc = device_get_softc(dev); +#ifdef PCI_RES_BUS + if (type == PCI_RES_BUS) + return (pci_domain_adjust_bus(sc->ap_segment, child, r, start, + end)); +#endif return (pcib_host_res_adjust(&sc->ap_host_res, child, type, r, start, end)); } + +#ifdef PCI_RES_BUS +int +acpi_pcib_acpi_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct acpi_hpcib_softc *sc; + + sc = device_get_softc(dev); + if (type == PCI_RES_BUS) + return (pci_domain_release_bus(sc->ap_segment, child, rid, r)); + return (bus_generic_release_resource(dev, child, type, rid, r)); +} +#endif #endif --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib_pci.c +++ //depot/projects/pci/sys/dev/acpica/acpi_pcib_pci.c @@ -120,7 +120,7 @@ pcib_attach_common(dev); sc = device_get_softc(dev); sc->ap_handle = acpi_get_handle(dev); - return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.secbus)); + return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.bus.sec)); } static int --- //depot/vendor/freebsd/src/sys/dev/cardbus/cardbus.c +++ //depot/projects/pci/sys/dev/cardbus/cardbus.c @@ -96,17 +96,36 @@ cardbus_attach(device_t cbdev) { struct cardbus_softc *sc; +#ifdef PCI_RES_BUS + int rid; +#endif sc = device_get_softc(cbdev); sc->sc_dev = cbdev; +#ifdef PCI_RES_BUS + rid = 0; + sc->sc_bus = bus_alloc_resource(cbdev, PCI_RES_BUS, &rid, + pcib_get_bus(cbdev), pcib_get_bus(cbdev), 1, 0); + if (sc->sc_bus == NULL) { + device_printf(cbdev, "failed to allocate bus number\n"); + return (ENXIO); + } +#endif return (0); } static int cardbus_detach(device_t cbdev) { +#ifdef PCI_RES_BUS + struct cardbus_softc *sc; +#endif cardbus_detach_card(cbdev); +#ifdef PCI_RES_BUS + sc = device_get_softc(cbdev); + (void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus); +#endif return (0); } --- //depot/vendor/freebsd/src/sys/dev/cardbus/cardbusvar.h +++ //depot/projects/pci/sys/dev/cardbus/cardbusvar.h @@ -69,6 +69,9 @@ struct cardbus_softc { device_t sc_dev; +#ifdef PCI_RES_BUS + struct resource *sc_bus; +#endif }; /* --- //depot/vendor/freebsd/src/sys/dev/pccbb/pccbb.c +++ //depot/projects/pci/sys/dev/pccbb/pccbb.c @@ -97,6 +97,7 @@ #include #include +#include #include #include @@ -1534,7 +1535,7 @@ *result = sc->domain; return (0); case PCIB_IVAR_BUS: - *result = sc->secbus; + *result = sc->bus.sec; return (0); } return (ENOENT); @@ -1543,14 +1544,12 @@ int cbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value) { - struct cbb_softc *sc = device_get_softc(brdev); switch (which) { case PCIB_IVAR_DOMAIN: return (EINVAL); case PCIB_IVAR_BUS: - sc->secbus = value; - return (0); + return (EINVAL); } return (ENOENT); } --- //depot/vendor/freebsd/src/sys/dev/pccbb/pccbb_isa.c +++ //depot/projects/pci/sys/dev/pccbb/pccbb_isa.c @@ -51,6 +51,9 @@ #include +#include +#include + #include #include --- //depot/vendor/freebsd/src/sys/dev/pccbb/pccbb_pci.c +++ //depot/projects/pci/sys/dev/pccbb/pccbb_pci.c @@ -93,6 +93,7 @@ #include #include +#include #include #include @@ -303,13 +304,15 @@ static int cbb_pci_attach(device_t brdev) { +#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ + uint32_t pribus; +#endif struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; int rid; device_t parent; - uint32_t pribus; parent = device_get_parent(brdev); mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF); @@ -318,9 +321,15 @@ sc->cbdev = NULL; sc->exca[0].pccarddev = NULL; sc->domain = pci_get_domain(brdev); - sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1); - sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1); + sc->bus.sec = pci_read_config(brdev, PCIR_SECBUS_2, 1); + sc->bus.sub = pci_read_config(brdev, PCIR_SUBBUS_2, 1); sc->pribus = pcib_get_bus(parent); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); + sc->bus.sec_reg = PCIR_SECBUS_2; + sc->bus.sub_reg = PCIR_SUBBUS_2; + pcib_setup_secbus(brdev, &sc->bus); +#endif SLIST_INIT(&sc->rl); cbb_powerstate_d0(brdev); @@ -352,9 +361,9 @@ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", - CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number"); + CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", - CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); + CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); #if 0 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory", CTLFLAG_RD, &sc->subbus, 0, "Memory window open"); @@ -366,15 +375,16 @@ CTLFLAG_RD, &sc->subbus, 0, "io range 2 open"); #endif +#if !(defined(NEW_PCIB) && defined(PCI_RES_BUS)) /* * This is a gross hack. We should be scanning the entire pci * tree, assigning bus numbers in a way such that we (1) can * reserve 1 extra bus just in case and (2) all sub busses * are in an appropriate range. */ - DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus)); + DEVPRINTF((brdev, "Secondary bus is %d\n", sc->bus.sec)); pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1); - if (sc->secbus == 0 || sc->pribus != pribus) { + if (sc->bus.sec == 0 || sc->pribus != pribus) { if (curr_bus_number <= sc->pribus) curr_bus_number = sc->pribus + 1; if (pribus != sc->pribus) { @@ -382,13 +392,14 @@ sc->pribus)); pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); } - sc->secbus = curr_bus_number++; - sc->subbus = curr_bus_number++; + sc->bus.sec = curr_bus_number++; + sc->bus.sub = curr_bus_number++; DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", - sc->secbus, sc->subbus)); - pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1); - pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1); + sc->bus.sec, sc->bus.sub)); + pci_write_config(brdev, PCIR_SECBUS_2, sc->bus.sec, 1); + pci_write_config(brdev, PCIR_SUBBUS_2, sc->bus.sub, 1); } +#endif /* attach children */ sc->cbdev = device_add_child(brdev, "cardbus", -1); @@ -467,8 +478,8 @@ /* Restore bus configuration */ pci_write_config(sc->dev, PCIR_PRIBUS_2, sc->pribus, 1); - pci_write_config(sc->dev, PCIR_SECBUS_2, sc->secbus, 1); - pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->subbus, 1); + pci_write_config(sc->dev, PCIR_SECBUS_2, sc->bus.sec, 1); + pci_write_config(sc->dev, PCIR_SUBBUS_2, sc->bus.sub, 1); /* Enable memory access */ PCI_MASK_CONFIG(sc->dev, PCIR_COMMAND, @@ -786,6 +797,58 @@ return retval; } +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static struct resource * +cbb_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct cbb_softc *sc; + + sc = device_get_softc(bus); + if (type == PCI_RES_BUS) + return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, + count, flags)); + return (cbb_alloc_resource(bus, child, type, rid, start, end, count, + flags)); +} + +static int +cbb_pci_adjust_resource(device_t bus, device_t child, int type, + struct resource *r, u_long start, u_long end) +{ + struct cbb_softc *sc; + + sc = device_get_softc(bus); + if (type == PCI_RES_BUS) { + if (!rman_is_region_manager(r, &sc->bus.rman)) + return (EINVAL); + return (rman_adjust_resource(r, start, end)); + } + return (bus_generic_adjust_resource(bus, child, type, r, start, end)); +} + +static int +cbb_pci_release_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct cbb_softc *sc; + int error; + + sc = device_get_softc(bus); + if (type == PCI_RES_BUS) { + if (!rman_is_region_manager(r, &sc->bus.rman)) + return (EINVAL); + if (rman_get_flags(r) & RF_ACTIVE) { + error = bus_deactivate_resource(child, type, rid, r); + if (error) + return (error); + } + return (rman_release_resource(r)); + } + return (cbb_release_resource(bus, child, type, rid, r)); +} +#endif + /************************************************************************/ /* PCI compat methods */ /************************************************************************/ @@ -829,8 +892,14 @@ /* bus methods */ DEVMETHOD(bus_read_ivar, cbb_read_ivar), DEVMETHOD(bus_write_ivar, cbb_write_ivar), +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + DEVMETHOD(bus_alloc_resource, cbb_pci_alloc_resource), + DEVMETHOD(bus_adjust_resource, cbb_pci_adjust_resource), + DEVMETHOD(bus_release_resource, cbb_pci_release_resource), +#else DEVMETHOD(bus_alloc_resource, cbb_alloc_resource), DEVMETHOD(bus_release_resource, cbb_release_resource), +#endif DEVMETHOD(bus_activate_resource, cbb_activate_resource), DEVMETHOD(bus_deactivate_resource, cbb_deactivate_resource), DEVMETHOD(bus_driver_added, cbb_driver_added), --- //depot/vendor/freebsd/src/sys/dev/pccbb/pccbbvar.h +++ //depot/projects/pci/sys/dev/pccbb/pccbbvar.h @@ -64,8 +64,7 @@ bus_space_handle_t bsh; uint32_t domain; unsigned int pribus; - unsigned int secbus; - unsigned int subbus; + struct pcib_secbus bus; struct mtx mtx; int cardok; u_int32_t flags; --- //depot/vendor/freebsd/src/sys/dev/pci/pci.c +++ //depot/projects/pci/sys/dev/pci/pci.c @@ -96,6 +96,9 @@ struct resource_list *rl, int force, int prefetch); static int pci_probe(device_t dev); static int pci_attach(device_t dev); +#ifdef PCI_RES_BUS +static int pci_detach(device_t dev); +#endif static void pci_load_vendor_data(void); static int pci_describe_parse_line(char **ptr, int *vendor, int *device, char **desc); @@ -130,7 +133,11 @@ /* Device interface */ DEVMETHOD(device_probe, pci_probe), DEVMETHOD(device_attach, pci_attach), +#ifdef PCI_RES_BUS + DEVMETHOD(device_detach, pci_detach), +#else DEVMETHOD(device_detach, bus_generic_detach), +#endif DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, pci_suspend), DEVMETHOD(device_resume, pci_resume), @@ -3320,10 +3332,22 @@ #ifdef PCI_DMA_BOUNDARY int error, tag_valid; #endif +#ifdef PCI_RES_BUS + int rid; +#endif sc = device_get_softc(dev); domain = pcib_get_domain(dev); busno = pcib_get_bus(dev); +#ifdef PCI_RES_BUS + rid = 0; + sc->sc_bus = bus_alloc_resource(dev, PCI_RES_BUS, &rid, busno, busno, + 1, 0); + if (sc->sc_bus == NULL) { + device_printf(dev, "failed to allocate bus number\n"); + return (ENXIO); + } +#endif if (bootverbose) device_printf(dev, "domain=%d, physical bus=%d\n", domain, busno); @@ -3368,6 +3392,21 @@ return (bus_generic_attach(dev)); } +#ifdef PCI_RES_BUS +static int +pci_detach(device_t dev) +{ + struct pci_softc *sc; + int error; + + error = bus_generic_detach(dev); + if (error) + return (error); + sc = device_get_softc(dev); + return (bus_release_resource(dev, PCI_RES_BUS, 0, sc->sc_bus)); +} +#endif + static void pci_set_power_children(device_t dev, device_t *devlist, int numdevs, int state) @@ -3865,6 +3904,10 @@ pci_printf(&dinfo->cfg, "Device leaked memory resources\n"); if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0) pci_printf(&dinfo->cfg, "Device leaked I/O resources\n"); +#ifdef PCI_RES_BUS + if (resource_list_release_active(rl, dev, child, PCI_RES_BUS) != 0) + pci_printf(&dinfo->cfg, "Device leaked PCI bus numbers\n"); +#endif pci_cfg_save(child, dinfo, 1); } @@ -4289,6 +4332,20 @@ rl = &dinfo->resources; cfg = &dinfo->cfg; switch (type) { +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + case PCI_RES_BUS: + /* + * If rid 0 is not already allocated, create a new + * resource list entry. + */ + if (*rid != 0) + return (NULL); + rle = resource_list_find(rl, type, *rid); + if (rle != NULL && rle->res != NULL) + return (NULL); + resource_list_add(rl, type, *rid, start, end, count); + break; +#endif case SYS_RES_IRQ: /* * Can't alloc legacy interrupt once MSI messages have --- //depot/vendor/freebsd/src/sys/dev/pci/pci_pci.c +++ //depot/projects/pci/sys/dev/pci/pci_pci.c @@ -113,6 +119,10 @@ { switch (type) { +#ifdef PCI_RES_BUS + case PCI_RES_BUS: + return (rman_is_region_manager(r, &sc->bus.rman)); +#endif case SYS_RES_IOPORT: return (rman_is_region_manager(r, &sc->io.rman)); case SYS_RES_MEMORY: @@ -504,6 +528,205 @@ } } +#ifdef PCI_RES_BUS +/* + * Allocate a suitable secondary bus for this bridge if needed and + * initialize the resource manager for the secondary bus range. + */ +void +pcib_setup_secbus(device_t dev, struct pcib_secbus *bus) +{ + char buf[64]; + int error, rid; + + bus->dev = dev; + bus->rman.rm_start = 0; + bus->rman.rm_end = PCI_BUSMAX; + bus->rman.rm_type = RMAN_ARRAY; + snprintf(buf, sizeof(buf), "%s bus numbers", device_get_nameunit(dev)); + bus->rman.rm_descr = strdup(buf, M_DEVBUF); + error = rman_init(&bus->rman); + if (error) + panic("Failed to initialize %s bus number rman", + device_get_nameunit(dev)); + +#if 0 + /* + * XXX: Should we reset subbus to secbus if it is < secbus? + * This would at least preserve the existing secbus if it is + * valid. + */ + if (bus->sub < bus->sec) + bus->sub = bus->sec; +#endif + + /* + * Allocate a resource for the existing secondary bus number + * range if it is valid. + */ + if (bus->sec != 0 && bus->sub >= bus->sec) { + rid = 0; + bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, bus->sec, + bus->sub, bus->sub - bus->sec + 1, 0); + if (bus->res == NULL) { + if (bootverbose || 1) + device_printf(dev, + "failed to allocate initial secbus range: %u-%u\n", + bus->sec, bus->sub); +#if 0 + /* XXX: Should we clear these on failure? */ + bus->sec = 0; + bus->sub = 0; +#endif + } + /* XXX */ + if (bus->res != NULL) + device_printf(dev, + "allocated initial secbus range %lu-%lu\n", + rman_get_start(bus->res), rman_get_end(bus->res)); + } + + /* + * If we don't have a valid resource, allocate a fresh resource + * for just this bus. + * + * XXX: Should we always start with a bus higher than our primary + * side bus number? I'm not sure it is required by the spec but + * it seems sensible. OTOH, the existing rmans in any parent + * PCI-PCI bridges should already enforce this. + */ + if (bus->res == NULL) { + /* + * This doesn't use bus_alloc_resource_any() as the + * count of 1 is explicit. + */ + rid = 0; + bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, + 1, 0); + if (bus->res != NULL) { + KASSERT(rman_get_size(bus->res) == 1, + ("more than one bus number")); + if (bootverbose || 1) + device_printf(bus->dev, + "allocated initial secbus %lu\n", + rman_get_start(bus->res)); + bus->sec = rman_get_start(bus->res); + bus->sub = rman_get_end(bus->res); + } else + device_printf(bus->dev, + "failed to allocate secondary bus number\n"); + } + + /* + * Add the initial resource to the rman and write updated + * secbus and subbus registers. + */ + if (bus->res != NULL) { + error = rman_manage_region(&bus->rman, rman_get_start(bus->res), + rman_get_end(bus->res)); + if (error) + panic("Failed to add resource to rman"); + } + pci_write_config(dev, bus->sec_reg, bus->sec, 1); + pci_write_config(dev, bus->sub_reg, bus->sub, 1); +} + +static struct resource * +pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *res; + + res = rman_reserve_resource(&bus->rman, start, end, count, flags, child); + if (res == NULL) + return (NULL); + + if (bootverbose) + device_printf(bus->dev, + "allocated bus range (%lu-%lu) for rid %d of %s\n", + rman_get_start(res), rman_get_end(res), *rid, + pcib_child_name(child)); + rman_set_rid(res, *rid); + return (res); +} + +/* + * Attempt to grow the secondary bus range. This is much simpler than + * for I/O windows as the range can only be grown by increasing + * subbus. + */ +static int +pcib_grow_subbus(struct pcib_secbus *bus, u_long new_end) +{ + u_long old_end; + int error; + + old_end = rman_get_end(bus->res); + KASSERT(new_end > old_end, ("attempt to shrink subbus")); + error = bus_adjust_resource(bus->dev, PCI_RES_BUS, bus->res, + rman_get_start(bus->res), new_end); + if (error) + return (error); + if (bootverbose || 1) + device_printf(bus->dev, "grew bus range to %lu-%lu\n", + rman_get_start(bus->res), rman_get_end(bus->res)); + error = rman_manage_region(&bus->rman, old_end + 1, + rman_get_end(bus->res)); + if (error) + panic("Failed to add resource to rman"); + bus->sub = rman_get_end(bus->res); + pci_write_config(bus->dev, bus->sub_reg, bus->sub, 1); + return (0); +} + +struct resource * +pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct resource *res; + u_long start_free, end_free, new_end; + + /* + * First, see if the request can be satisified by the existing + * bus range. + */ + res = pcib_suballoc_bus(bus, child, rid, start, end, count, flags); + if (res != NULL) + return (res); + + /* + * Figure out a range to grow the bus range. First, find the + * first bus number after the last allocated bus in the rman and + * enforce that as a minimum starting point for the range. + */ + if (rman_last_free_region(&bus->rman, &start_free, &end_free) != 0 || + end_free != bus->sub) + start_free = bus->sub + 1; + if (start_free < start) + start_free = start; + new_end = start_free + count - 1; + + /* + * See if this new range would satisfy the request if it + * succeeds. + */ + if (new_end > end) + return (NULL); + + /* Finally, attempt to grow the existing resource. */ + if (bootverbose || 1) { + device_printf(bus->dev, + "attempting to grow bus range for %lu buses\n", count); + printf("\tback candidate range: %lu-%lu\n", start_free, + new_end); + } + if (pcib_grow_subbus(bus, new_end) == 0) + return (pcib_suballoc_bus(bus, child, rid, start, end, count, + flags)); + return (NULL); +} +#endif + #else /* @@ -650,8 +873,8 @@ sc->command = pci_read_config(dev, PCIR_COMMAND, 2); sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); - sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); - sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); + sc->bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1); + sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); #ifndef NEW_PCIB @@ -674,8 +897,8 @@ pci_write_config(dev, PCIR_COMMAND, sc->command, 2); pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); - pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1); - pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1); + pci_write_config(dev, PCIR_SECBUS_1, sc->bus.sec, 1); + pci_write_config(dev, PCIR_SUBBUS_1, sc->bus.sub, 1); pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2); pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1); #ifdef NEW_PCIB @@ -721,6 +944,13 @@ pcib_cfg_save(sc); /* + * The primary bus register should always be the bus of the + * parent. + */ + sc->pribus = pci_get_bus(dev); + pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); + + /* * Setup sysctl reporting nodes */ sctx = device_get_sysctl_ctx(dev); @@ -730,9 +960,9 @@ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", - CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number"); + CTLFLAG_RD, &sc->bus.sec, 0, "Secondary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", - CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); + CTLFLAG_RD, &sc->bus.sub, 0, "Subordinate bus number"); /* * Quirk handling. @@ -744,8 +974,8 @@ supbus = pci_read_config(dev, 0x41, 1); if (supbus != 0xff) { - sc->secbus = supbus + 1; - sc->subbus = supbus + 1; + sc->bus.sec = supbus + 1; + sc->bus.sub = supbus + 1; } break; } @@ -781,9 +1011,9 @@ break; } freeenv(cp); - if (sc->subbus < 0xa) { + if (sc->bus.sub < 0xa) { pci_write_config(dev, PCIR_SUBBUS_1, 0xa, 1); - sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); + sc->bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); } break; } @@ -808,12 +1038,17 @@ sc->flags |= PCIB_SUBTRACTIVE; #ifdef NEW_PCIB +#ifdef PCI_RES_BUS + sc->bus.sec_reg = PCIR_SECBUS_1; + sc->bus.sub_reg = PCIR_SUBBUS_1; + pcib_setup_secbus(dev, &sc->bus); +#endif pcib_probe_windows(sc); #endif if (bootverbose) { device_printf(dev, " domain %d\n", sc->domain); - device_printf(dev, " secondary bus %d\n", sc->secbus); - device_printf(dev, " subordinate bus %d\n", sc->subbus); + device_printf(dev, " secondary bus %d\n", sc->bus.sec); + device_printf(dev, " subordinate bus %d\n", sc->bus.sub); #ifdef NEW_PCIB if (pcib_is_window_open(&sc->io)) device_printf(dev, " I/O decode 0x%jx-0x%jx\n", @@ -854,20 +1089,6 @@ } /* - * XXX If the secondary bus number is zero, we should assign a bus number - * since the BIOS hasn't, then initialise the bridge. A simple - * bus_alloc_resource with the a couple of busses seems like the right - * approach, but we don't know what busses the BIOS might have already - * assigned to other bridges on this bus that probe later than we do. - * - * If the subordinate bus number is less than the secondary bus number, - * we should pick a better value. One sensible alternative would be to - * pick 255; the only tradeoff here is that configuration transactions - * would be more widely routed than absolutely necessary. We could - * then do a walk of the tree later and fix it. - */ - - /* * Always enable busmastering on bridges so that transactions * initiated on the secondary bus are passed through to the * primary bus. @@ -883,8 +1104,8 @@ pcib_attach_common(dev); sc = device_get_softc(dev); - if (sc->secbus != 0) { - child = device_add_child(dev, "pci", sc->secbus); + if (sc->bus.sec != 0) { + child = device_add_child(dev, "pci", sc->bus.sec); if (child != NULL) return(bus_generic_attach(dev)); } @@ -934,7 +1155,7 @@ *result = sc->domain; return(0); case PCIB_IVAR_BUS: - *result = sc->secbus; + *result = sc->bus.sec; return(0); } return(ENOENT); @@ -943,14 +1164,12 @@ int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value) { - struct pcib_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: return(EINVAL); case PCIB_IVAR_BUS: - sc->secbus = value; - return(0); + return(EINVAL); } return(ENOENT); } @@ -1360,6 +1579,11 @@ } switch (type) { +#ifdef PCI_RES_BUS + case PCI_RES_BUS: + return (pcib_alloc_subbus(&sc->bus, child, rid, start, end, + count, flags)); +#endif case SYS_RES_IOPORT: if (pcib_is_isa_range(sc, start, end, count)) return (NULL); --- //depot/vendor/freebsd/src/sys/dev/pci/pci_private.h +++ //depot/projects/pci/sys/dev/pci/pci_private.h @@ -40,6 +40,9 @@ struct pci_softc { bus_dma_tag_t sc_dma_tag; +#ifdef PCI_RES_BUS + struct resource *sc_bus; +#endif }; extern int pci_do_power_resume; --- //depot/vendor/freebsd/src/sys/dev/pci/pci_subr.c +++ //depot/projects/pci/sys/dev/pci/pci_subr.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -151,7 +152,7 @@ /* * Some Host-PCI bridge drivers know which resource ranges they can * decode and should only allocate subranges to child PCI devices. - * This API provides a way to manage this. The bridge drive should + * This API provides a way to manage this. The bridge driver should * initialize this structure during attach and call * pcib_host_res_decodes() on each resource range it decodes. It can * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper @@ -183,7 +184,11 @@ struct resource_list_entry *rle; int rid; +#ifdef PCI_RES_BUS + if (bootverbose || type == PCI_RES_BUS) +#else if (bootverbose) +#endif device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, end); @@ -237,7 +242,11 @@ r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, new_start, new_end, count, flags); if (r != NULL) { +#ifdef PCI_RES_BUS + if (bootverbose || type == PCI_RES_BUS) +#else if (bootverbose) +#endif device_printf(hr->hr_pcib, "allocated type %d (%#lx-%#lx) for rid %x of %s\n", type, rman_get_start(r), rman_get_end(r), @@ -282,4 +291,102 @@ } return (ERANGE); } + +#ifdef PCI_RES_BUS +struct pci_domain { + int pd_domain; + struct rman pd_bus_rman; + TAILQ_ENTRY(pci_domain) pd_link; +}; + +static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains); + +/* + * Each PCI domain maintains its own resource manager for PCI bus + * numbers in that domain. Domain objects are created on first use. + * Host to PCI bridge drivers and PCI-PCI bridge drivers should + * allocate their bus ranges from their domain. + */ +static struct pci_domain * +pci_find_domain(int domain) +{ + struct pci_domain *d; + char buf[64]; + int error; + + TAILQ_FOREACH(d, &domains, pd_link) { + if (d->pd_domain == domain) + return (d); + } + + snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain); + d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO); + d->pd_domain = domain; + d->pd_bus_rman.rm_start = 0; + d->pd_bus_rman.rm_end = PCI_BUSMAX; + d->pd_bus_rman.rm_type = RMAN_ARRAY; + strcpy((char *)(d + 1), buf); + d->pd_bus_rman.rm_descr = (char *)(d + 1); + error = rman_init(&d->pd_bus_rman); + if (error == 0) + error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX); + if (error) + panic("Failed to initialize PCI domain %d rman", domain); + TAILQ_INSERT_TAIL(&domains, d, pd_link); + return (d); +} + +struct resource * +pci_domain_alloc_bus(int domain, device_t dev, int *rid, u_long start, + u_long end, u_long count, u_int flags) +{ + struct pci_domain *d; + struct resource *res; + + if (domain < 0 || domain > PCI_DOMAINMAX) + return (NULL); + d = pci_find_domain(domain); + res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags, + dev); + if (res == NULL) + return (NULL); + + rman_set_rid(res, *rid); + return (res); +} + +int +pci_domain_adjust_bus(int domain, device_t dev, struct resource *r, + u_long start, u_long end) +{ +#ifdef INVARIANTS + struct pci_domain *d; +#endif + + if (domain < 0 || domain > PCI_DOMAINMAX) + return (EINVAL); +#ifdef INVARIANTS + d = pci_find_domain(domain); + KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); +#endif + return (rman_adjust_resource(r, start, end)); +} + +int +pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r) +{ +#ifdef INVARIANTS + struct pci_domain *d; +#endif + + if (domain < 0 || domain > PCI_DOMAINMAX) + return (EINVAL); +#ifdef INVARIANTS + d = pci_find_domain(domain); + KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); +#endif + return (rman_release_resource(r)); +} +#endif /* PCI_RES_BUS */ + #endif /* NEW_PCIB */ --- //depot/vendor/freebsd/src/sys/dev/pci/pcib_private.h +++ //depot/projects/pci/sys/dev/pci/pcib_private.h @@ -83,6 +83,19 @@ }; #endif +struct pcib_secbus { + u_int sec; + u_int sub; +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + device_t dev; + struct rman rman; + struct resource *res; + const char *name; + int sec_reg; + int sub_reg; +#endif +}; + /* * Bridge-specific data. */ @@ -96,8 +109,7 @@ uint16_t command; /* command register */ u_int domain; /* domain number */ u_int pribus; /* primary bus number */ - u_int secbus; /* secondary bus number */ - u_int subbus; /* subordinate bus number */ + struct pcib_secbus bus; /* secondary bus numbers */ #ifdef NEW_PCIB struct pcib_window io; /* I/O port window */ struct pcib_window mem; /* memory window */ @@ -117,13 +129,25 @@ typedef uint32_t pci_read_config_fn(int b, int s, int f, int reg, int width); -#ifdef NEW_PCIB -const char *pcib_child_name(device_t child); -#endif int host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, uint8_t *busnum); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +struct resource *pci_domain_alloc_bus(int domain, device_t dev, int *rid, + u_long start, u_long end, u_long count, u_int flags); +int pci_domain_adjust_bus(int domain, device_t dev, + struct resource *r, u_long start, u_long end); +int pci_domain_release_bus(int domain, device_t dev, int rid, + struct resource *r); +struct resource *pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, + int *rid, u_long start, u_long end, u_long count, + u_int flags); +void pcib_setup_secbus(device_t dev, struct pcib_secbus *bus); +#endif int pcib_attach(device_t dev); void pcib_attach_common(device_t dev); +#ifdef NEW_PCIB +const char *pcib_child_name(device_t child); +#endif int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); int pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value); struct resource *pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, --- //depot/vendor/freebsd/src/sys/i386/include/resource.h +++ //depot/projects/pci/sys/i386/include/resource.h @@ -40,5 +40,8 @@ #define SYS_RES_DRQ 2 /* isa dma lines */ #define SYS_RES_MEMORY 3 /* i/o memory */ #define SYS_RES_IOPORT 4 /* i/o ports */ +#ifdef NEW_PCIB +#define PCI_RES_BUS 5 /* PCI bus numbers */ +#endif #endif /* !_MACHINE_RESOURCE_H_ */ --- //depot/vendor/freebsd/src/sys/sparc64/pci/apb.c +++ //depot/projects/pci/sys/sparc64/pci/apb.c @@ -177,9 +177,9 @@ pci_read_config(dev, PCIR_COMMAND, 2); sc->sc_bsc.ops_pcib_sc.pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); - sc->sc_bsc.ops_pcib_sc.secbus = + sc->sc_bsc.ops_pcib_sc.bus.sec = pci_read_config(dev, PCIR_SECBUS_1, 1); - sc->sc_bsc.ops_pcib_sc.subbus = + sc->sc_bsc.ops_pcib_sc.bus.sub = pci_read_config(dev, PCIR_SUBBUS_1, 1); sc->sc_bsc.ops_pcib_sc.bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); @@ -200,10 +200,10 @@ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0, "Primary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", - CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.secbus, 0, + CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sec, 0, "Secondary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", - CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.subbus, 0, + CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sub, 0, "Subordinate bus number"); ofw_pcib_gen_setup(dev); @@ -212,9 +212,9 @@ device_printf(dev, " domain %d\n", sc->sc_bsc.ops_pcib_sc.domain); device_printf(dev, " secondary bus %d\n", - sc->sc_bsc.ops_pcib_sc.secbus); + sc->sc_bsc.ops_pcib_sc.bus.sec); device_printf(dev, " subordinate bus %d\n", - sc->sc_bsc.ops_pcib_sc.subbus); + sc->sc_bsc.ops_pcib_sc.bus.sub); device_printf(dev, " I/O decode "); apb_map_print(sc->sc_iomap, APB_IO_SCALE); printf("\n"); --- //depot/vendor/freebsd/src/sys/x86/include/legacyvar.h +++ //depot/projects/pci/sys/x86/include/legacyvar.h @@ -57,6 +57,8 @@ uintptr_t value); struct resource *legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); +int legacy_pcib_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r); int legacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data); --- //depot/vendor/freebsd/src/sys/x86/pci/pci_bus.c +++ //depot/projects/pci/sys/x86/pci/pci_bus.c @@ -597,11 +597,39 @@ u_long start, u_long end, u_long count, u_int flags) { - start = hostb_alloc_start(type, start, end, count); - return (bus_generic_alloc_resource(dev, child, type, rid, start, end, - count, flags)); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + if (type == PCI_RES_BUS) + return (pci_domain_alloc_bus(0, child, rid, start, end, count, + flags)); +#endif + start = hostb_alloc_start(type, start, end, count); + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, + count, flags)); +} + +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static int +legacy_pcib_adjust_resource(device_t dev, device_t child, int type, + struct resource *r, u_long start, u_long end) +{ + + if (type == PCI_RES_BUS) + return (pci_domain_adjust_bus(0, child, r, start, end)); + return (bus_generic_adjust_resource(dev, child, type, r, start, end)); +} + +int +legacy_pcib_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + + if (type == PCI_RES_BUS) + return (pci_domain_release_bus(0, child, rid, r)); + return (bus_generic_release_resource(dev, child, type, rid, r)); } +#endif + static device_method_t legacy_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_identify, legacy_pcib_identify), @@ -615,8 +643,13 @@ DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + DEVMETHOD(bus_adjust_resource, legacy_pcib_adjust_resource), + DEVMETHOD(bus_release_resource, legacy_pcib_release_resource), +#else DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), +#endif DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), --- //depot/vendor/freebsd/src/sys/x86/x86/mptable_pci.c +++ //depot/projects/pci/sys/x86/x86/mptable_pci.c @@ -129,6 +129,11 @@ { struct mptable_hostb_softc *sc; +#ifdef PCI_RES_BUS + if (type == PCI_RES_BUS) + return (pci_domain_alloc_bus(0, child, rid, start, end, count, + flags)); +#endif sc = device_get_softc(dev); if (type == SYS_RES_IOPORT && start + count - 1 == end) { if (mptable_is_isa_range(start, end)) { @@ -165,6 +170,10 @@ { struct mptable_hostb_softc *sc; +#ifdef PCI_RES_BUS + if (type == PCI_RES_BUS) + return (pci_domain_adjust_bus(0, child, r, start, end)); +#endif sc = device_get_softc(dev); return (pcib_host_res_adjust(&sc->sc_host_res, child, type, r, start, end)); @@ -189,7 +198,11 @@ DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), #endif +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + DEVMETHOD(bus_release_resource, legacy_pcib_release_resource), +#else DEVMETHOD(bus_release_resource, bus_generic_release_resource), +#endif DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),