Date: Wed, 1 Apr 2015 21:48:55 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r280970 - in stable/10/sys: amd64/include dev/acpica dev/cardbus dev/pccbb dev/pci i386/include sparc64/pci x86/include x86/pci x86/x86 Message-ID: <201504012148.t31LmtgR024472@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Wed Apr 1 21:48:54 2015 New Revision: 280970 URL: https://svnweb.freebsd.org/changeset/base/280970 Log: MFC 261790: Add support for managing PCI bus numbers. As with BARs and PCI-PCI bridge I/O windows, the default is to preserve the firmware-assigned resources. PCI bus numbers are only managed if NEW_PCIB is enabled and the architecture defines a PCI_RES_BUS resource type. - Add a helper API to create top-level PCI bus resource managers for each PCI domain/segment. Host-PCI bridge drivers use this API to allocate bus numbers from their associated domain. - Change the PCI bus and CardBus drivers to allocate a bus resource for their bus number from the parent PCI bridge device. - Change the PCI-PCI and PCI-CardBus bridge drivers to allocate the full range of bus numbers from secbus to subbus from their parent bridge. The drivers also always program their primary bus register. The bridge drivers also support growing their bus range by extending the bus resource and updating subbus to match the larger range. - Add support for managing PCI bus resources to the Host-PCI bridge drivers used for amd64 and i386 (acpi_pcib, mptable_pcib, legacy_pcib, and qpi_pcib). - Define a PCI_RES_BUS resource type for amd64 and i386. PR: 197076 Modified: stable/10/sys/amd64/include/resource.h stable/10/sys/dev/acpica/acpi_pcib_acpi.c stable/10/sys/dev/acpica/acpi_pcib_pci.c stable/10/sys/dev/cardbus/cardbus.c stable/10/sys/dev/cardbus/cardbusvar.h stable/10/sys/dev/pccbb/pccbb.c stable/10/sys/dev/pccbb/pccbb_isa.c stable/10/sys/dev/pccbb/pccbb_pci.c stable/10/sys/dev/pccbb/pccbbvar.h stable/10/sys/dev/pci/pci.c stable/10/sys/dev/pci/pci_pci.c stable/10/sys/dev/pci/pci_private.h stable/10/sys/dev/pci/pci_subr.c stable/10/sys/dev/pci/pcib_private.h stable/10/sys/i386/include/resource.h stable/10/sys/sparc64/pci/apb.c stable/10/sys/x86/include/legacyvar.h stable/10/sys/x86/pci/pci_bus.c stable/10/sys/x86/pci/qpi.c stable/10/sys/x86/x86/mptable_pci.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/amd64/include/resource.h ============================================================================== --- stable/10/sys/amd64/include/resource.h Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/amd64/include/resource.h Wed Apr 1 21:48:54 2015 (r280970) @@ -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_ */ Modified: stable/10/sys/dev/acpica/acpi_pcib_acpi.c ============================================================================== --- stable/10/sys/dev/acpica/acpi_pcib_acpi.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/acpica/acpi_pcib_acpi.c Wed Apr 1 21:48:54 2015 (r280970) @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <dev/acpica/acpivar.h> #include <machine/pci_cfgreg.h> +#include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcib_private.h> #include "pcib_if.h" @@ -96,6 +97,11 @@ static struct resource *acpi_pcib_acpi_a 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 @@ static device_method_t acpi_pcib_acpi_me #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 @@ acpi_pcib_producer_handler(ACPI_RESOURCE } #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_pcib_acpi_attach(device_t dev) 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,6 +418,39 @@ acpi_pcib_acpi_attach(device_t dev) } } +#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 @@ -399,6 +461,7 @@ acpi_pcib_acpi_attach(device_t dev) 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 @@ acpi_pcib_acpi_alloc_resource(device_t d #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 @@ acpi_pcib_acpi_adjust_resource(device_t 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 Modified: stable/10/sys/dev/acpica/acpi_pcib_pci.c ============================================================================== --- stable/10/sys/dev/acpica/acpi_pcib_pci.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/acpica/acpi_pcib_pci.c Wed Apr 1 21:48:54 2015 (r280970) @@ -120,7 +120,7 @@ acpi_pcib_pci_attach(device_t dev) 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 Modified: stable/10/sys/dev/cardbus/cardbus.c ============================================================================== --- stable/10/sys/dev/cardbus/cardbus.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/cardbus/cardbus.c Wed Apr 1 21:48:54 2015 (r280970) @@ -96,17 +96,36 @@ static int 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); } Modified: stable/10/sys/dev/cardbus/cardbusvar.h ============================================================================== --- stable/10/sys/dev/cardbus/cardbusvar.h Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/cardbus/cardbusvar.h Wed Apr 1 21:48:54 2015 (r280970) @@ -69,6 +69,9 @@ struct cardbus_devinfo struct cardbus_softc { device_t sc_dev; +#ifdef PCI_RES_BUS + struct resource *sc_bus; +#endif }; /* Modified: stable/10/sys/dev/pccbb/pccbb.c ============================================================================== --- stable/10/sys/dev/pccbb/pccbb.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pccbb/pccbb.c Wed Apr 1 21:48:54 2015 (r280970) @@ -97,6 +97,7 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> #include <dev/pccard/pccardreg.h> #include <dev/pccard/pccardvar.h> @@ -1548,7 +1549,7 @@ cbb_read_ivar(device_t brdev, device_t c *result = sc->domain; return (0); case PCIB_IVAR_BUS: - *result = sc->secbus; + *result = sc->bus.sec; return (0); } return (ENOENT); @@ -1557,14 +1558,12 @@ cbb_read_ivar(device_t brdev, device_t c 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); } Modified: stable/10/sys/dev/pccbb/pccbb_isa.c ============================================================================== --- stable/10/sys/dev/pccbb/pccbb_isa.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pccbb/pccbb_isa.c Wed Apr 1 21:48:54 2015 (r280970) @@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$"); #include <isa/isavar.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> + #include <dev/pccard/pccardreg.h> #include <dev/pccard/pccardvar.h> Modified: stable/10/sys/dev/pccbb/pccbb_pci.c ============================================================================== --- stable/10/sys/dev/pccbb/pccbb_pci.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pccbb/pccbb_pci.c Wed Apr 1 21:48:54 2015 (r280970) @@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> #include <dev/pccard/pccardreg.h> #include <dev/pccard/pccardvar.h> @@ -303,13 +304,15 @@ cbb_print_config(device_t dev) 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,13 @@ cbb_pci_attach(device_t brdev) 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); + pcib_setup_secbus(brdev, &sc->bus, 1); +#endif SLIST_INIT(&sc->rl); cbb_powerstate_d0(brdev); @@ -352,9 +359,9 @@ cbb_pci_attach(device_t brdev) 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 +373,16 @@ cbb_pci_attach(device_t brdev) 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 +390,14 @@ cbb_pci_attach(device_t brdev) 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 +476,8 @@ cbb_chipinit(struct cbb_softc *sc) /* 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_enable_busmaster(sc->dev); @@ -785,6 +794,58 @@ cbb_pci_filt(void *arg) 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 */ /************************************************************************/ @@ -828,8 +889,14 @@ static device_method_t cbb_methods[] = { /* 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), Modified: stable/10/sys/dev/pccbb/pccbbvar.h ============================================================================== --- stable/10/sys/dev/pccbb/pccbbvar.h Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pccbb/pccbbvar.h Wed Apr 1 21:48:54 2015 (r280970) @@ -64,8 +64,7 @@ struct cbb_softc { 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; Modified: stable/10/sys/dev/pci/pci.c ============================================================================== --- stable/10/sys/dev/pci/pci.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pci/pci.c Wed Apr 1 21:48:54 2015 (r280970) @@ -92,6 +92,9 @@ static int pci_add_map(device_t bus, de 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); @@ -127,7 +130,11 @@ static device_method_t pci_methods[] = { /* 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), @@ -361,6 +368,13 @@ TUNABLE_INT("hw.pci.clear_bars", &pci_cl SYSCTL_INT(_hw_pci, OID_AUTO, clear_bars, CTLFLAG_RDTUN, &pci_clear_bars, 0, "Ignore firmware-assigned resources for BARs."); +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static int pci_clear_buses; +TUNABLE_INT("hw.pci.clear_buses", &pci_clear_buses); +SYSCTL_INT(_hw_pci, OID_AUTO, clear_buses, CTLFLAG_RDTUN, &pci_clear_buses, 0, + "Ignore firmware-assigned bus numbers."); +#endif + static int pci_enable_ari = 1; TUNABLE_INT("hw.pci.enable_ari", &pci_enable_ari); SYSCTL_INT(_hw_pci, OID_AUTO, enable_ari, CTLFLAG_RDTUN, &pci_enable_ari, @@ -3226,6 +3240,164 @@ xhci_early_takeover(device_t self) bus_release_resource(self, SYS_RES_MEMORY, rid, res); } +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) +static void +pci_reserve_secbus(device_t bus, device_t dev, pcicfgregs *cfg, + struct resource_list *rl) +{ + struct resource *res; + char *cp; + u_long start, end, count; + int rid, sec_bus, sec_reg, sub_bus, sub_reg, sup_bus; + + switch (cfg->hdrtype & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + sec_reg = PCIR_SECBUS_1; + sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + sec_reg = PCIR_SECBUS_2; + sub_reg = PCIR_SUBBUS_2; + break; + default: + return; + } + + /* + * If the existing bus range is valid, attempt to reserve it + * from our parent. If this fails for any reason, clear the + * secbus and subbus registers. + * + * XXX: Should we reset sub_bus to sec_bus if it is < sec_bus? + * This would at least preserve the existing sec_bus if it is + * valid. + */ + sec_bus = PCI_READ_CONFIG(bus, dev, sec_reg, 1); + sub_bus = PCI_READ_CONFIG(bus, dev, sub_reg, 1); + + /* Quirk handling. */ + switch (pci_get_devid(dev)) { + case 0x12258086: /* Intel 82454KX/GX (Orion) */ + sup_bus = pci_read_config(dev, 0x41, 1); + if (sup_bus != 0xff) { + sec_bus = sup_bus + 1; + sub_bus = sup_bus + 1; + PCI_WRITE_CONFIG(bus, dev, sec_reg, sec_bus, 1); + PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1); + } + break; + + case 0x00dd10de: + /* Compaq R3000 BIOS sets wrong subordinate bus number. */ + if ((cp = getenv("smbios.planar.maker")) == NULL) + break; + if (strncmp(cp, "Compal", 6) != 0) { + freeenv(cp); + break; + } + freeenv(cp); + if ((cp = getenv("smbios.planar.product")) == NULL) + break; + if (strncmp(cp, "08A0", 4) != 0) { + freeenv(cp); + break; + } + freeenv(cp); + if (sub_bus < 0xa) { + sub_bus = 0xa; + PCI_WRITE_CONFIG(bus, dev, sub_reg, sub_bus, 1); + } + break; + } + + if (bootverbose) + printf("\tsecbus=%d, subbus=%d\n", sec_bus, sub_bus); + if (sec_bus > 0 && sub_bus >= sec_bus) { + start = sec_bus; + end = sub_bus; + count = end - start + 1; + + resource_list_add(rl, PCI_RES_BUS, 0, 0ul, ~0ul, count); + + /* + * If requested, clear secondary bus registers in + * bridge devices to force a complete renumbering + * rather than reserving the existing range. However, + * preserve the existing size. + */ + if (pci_clear_buses) + goto clear; + + rid = 0; + res = resource_list_reserve(rl, bus, dev, PCI_RES_BUS, &rid, + start, end, count, 0); + if (res != NULL) + return; + + if (bootverbose) + device_printf(bus, + "pci%d:%d:%d:%d secbus failed to allocate\n", + pci_get_domain(dev), pci_get_bus(dev), + pci_get_slot(dev), pci_get_function(dev)); + } + +clear: + PCI_WRITE_CONFIG(bus, dev, sec_reg, 0, 1); + PCI_WRITE_CONFIG(bus, dev, sub_reg, 0, 1); +} + +static struct resource * +pci_alloc_secbus(device_t dev, device_t child, int *rid, u_long start, + u_long end, u_long count, u_int flags) +{ + struct pci_devinfo *dinfo; + pcicfgregs *cfg; + struct resource_list *rl; + struct resource *res; + int sec_reg, sub_reg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + rl = &dinfo->resources; + switch (cfg->hdrtype & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + sec_reg = PCIR_SECBUS_1; + sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + sec_reg = PCIR_SECBUS_2; + sub_reg = PCIR_SUBBUS_2; + break; + default: + return (NULL); + } + + if (*rid != 0) + return (NULL); + + if (resource_list_find(rl, PCI_RES_BUS, *rid) == NULL) + resource_list_add(rl, PCI_RES_BUS, *rid, start, end, count); + if (!resource_list_reserved(rl, PCI_RES_BUS, *rid)) { + res = resource_list_reserve(rl, dev, child, PCI_RES_BUS, rid, + start, end, count, flags & ~RF_ACTIVE); + if (res == NULL) { + resource_list_delete(rl, PCI_RES_BUS, *rid); + device_printf(child, "allocating %lu bus%s failed\n", + count, count == 1 ? "" : "es"); + return (NULL); + } + if (bootverbose) + device_printf(child, + "Lazy allocation of %lu bus%s at %lu\n", count, + count == 1 ? "" : "es", rman_get_start(res)); + PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1); + PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1); + } + return (resource_list_alloc(rl, dev, child, PCI_RES_BUS, rid, start, + end, count, flags)); +} +#endif + void pci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) { @@ -3298,6 +3470,14 @@ pci_add_resources(device_t bus, device_t else if (pci_get_progif(dev) == PCIP_SERIALBUS_USB_UHCI) uhci_early_takeover(dev); } + +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + /* + * Reserve resources for secondary bus ranges behind bridge + * devices. + */ + pci_reserve_secbus(bus, dev, cfg, rl); +#endif } static struct pci_devinfo * @@ -3390,10 +3570,22 @@ pci_attach_common(device_t dev) #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); @@ -3438,6 +3630,21 @@ pci_attach(device_t dev) 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) @@ -3953,6 +4160,10 @@ pci_child_detached(device_t dev, device_ 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); } @@ -4369,6 +4580,11 @@ pci_alloc_resource(device_t dev, device_ rl = &dinfo->resources; cfg = &dinfo->cfg; switch (type) { +#if defined(NEW_PCIB) && defined(PCI_RES_BUS) + case PCI_RES_BUS: + return (pci_alloc_secbus(dev, child, rid, start, end, count, + flags)); +#endif case SYS_RES_IRQ: /* * Can't alloc legacy interrupt once MSI messages have Modified: stable/10/sys/dev/pci/pci_pci.c ============================================================================== --- stable/10/sys/dev/pci/pci_pci.c Wed Apr 1 21:16:33 2015 (r280969) +++ stable/10/sys/dev/pci/pci_pci.c Wed Apr 1 21:48:54 2015 (r280970) @@ -130,6 +130,10 @@ pcib_is_resource_managed(struct pcib_sof { 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: @@ -534,6 +538,173 @@ pcib_probe_windows(struct pcib_softc *sc } } +#ifdef PCI_RES_BUS +/* + * Allocate a suitable secondary bus for this bridge if needed and + * initialize the resource manager for the secondary bus range. Note + * that the minimum count is a desired value and this may allocate a + * smaller range. + */ +void +pcib_setup_secbus(device_t dev, struct pcib_secbus *bus, int min_count) +{ + char buf[64]; + int error, rid; + + switch (pci_read_config(dev, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_BRIDGE: + bus->sub_reg = PCIR_SUBBUS_1; + break; + case PCIM_HDRTYPE_CARDBUS: + bus->sub_reg = PCIR_SUBBUS_2; + break; + default: + panic("not a PCI bridge"); + } + 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)); + + /* + * Allocate a bus range. This will return an existing bus range + * if one exists, or a new bus range if one does not. + */ + rid = 0; + bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, + min_count, 0); + if (bus->res == NULL) { + /* + * Fall back to just allocating a range of a single bus + * number. + */ + bus->res = bus_alloc_resource(dev, PCI_RES_BUS, &rid, 0ul, ~0ul, + 1, 0); + } else if (rman_get_size(bus->res) < min_count) + /* + * Attempt to grow the existing range to satisfy the + * minimum desired count. + */ + (void)bus_adjust_resource(dev, PCI_RES_BUS, bus->res, + rman_get_start(bus->res), rman_get_start(bus->res) + + min_count - 1); + + /* + * Add the initial resource to the rman. + */ + 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"); + bus->sec = rman_get_start(bus->res); + bus->sub = rman_get_end(bus->res); + } +} + +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) + 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) { + 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 /* @@ -680,8 +851,8 @@ pcib_cfg_save(struct pcib_softc *sc) 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 @@ -704,8 +875,8 @@ pcib_cfg_restore(struct pcib_softc *sc) 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 @@ -751,6 +922,13 @@ pcib_attach_common(device_t dev) 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); @@ -760,25 +938,27 @@ pcib_attach_common(device_t dev) 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. */ switch (pci_get_devid(dev)) { +#if !defined(NEW_PCIB) && !defined(PCI_RES_BUS) case 0x12258086: /* Intel 82454KX/GX (Orion) */ { uint8_t supbus; 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; } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201504012148.t31LmtgR024472>