Index: kern/subr_bus.c =================================================================== --- kern/subr_bus.c (revision 237008) +++ kern/subr_bus.c (working copy) @@ -3714,9 +3714,12 @@ struct resource *r, u_long start, u_long end) { /* Propagate up the bus hierarchy until someone handles it. */ - if (dev->parent) + if (dev->parent) { + device_printf(dev, "bus_adjust_resource(%s, %#x, %#lx, %#lx)\n", + device_get_nameunit(child), rman_get_rid(r), start, end); return (BUS_ADJUST_RESOURCE(dev->parent, child, type, r, start, end)); + } return (EINVAL); } Index: dev/pci/pci_pci.c =================================================================== --- dev/pci/pci_pci.c (revision 237008) +++ dev/pci/pci_pci.c (working copy) @@ -103,6 +103,13 @@ DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); #ifdef NEW_PCIB +SYSCTL_DECL(_hw_pci); + +static int pcib_clear; +TUNABLE_INT("hw.pci.pcib_clear", &pcib_clear); +SYSCTL_INT(_hw_pci, OID_AUTO, pcib_clear, CTLFLAG_RDTUN, &pcib_clear, 0, + "Clear firmware-assigned resources for PCI-PCI bridge I/O windows."); + /* * XXX Todo: * - properly handle the ISA enable bit. If it is set, we should change @@ -113,23 +120,27 @@ /* * Is a resource from a child device sub-allocated from one of our - * resource managers? + * resource managers? If so, return the associated window. */ -static int +static struct pcib_window * pcib_is_resource_managed(struct pcib_softc *sc, int type, struct resource *r) { switch (type) { case SYS_RES_IOPORT: - return (rman_is_region_manager(r, &sc->io.rman)); + if (rman_is_region_manager(r, &sc->io.rman)) + return (&sc->io); + break; case SYS_RES_MEMORY: /* Prefetchable resources may live in either memory rman. */ if (rman_get_flags(r) & RF_PREFETCHABLE && rman_is_region_manager(r, &sc->pmem.rman)) - return (1); - return (rman_is_region_manager(r, &sc->mem.rman)); + return (&sc->pmem); + if (rman_is_region_manager(r, &sc->mem.rman)) + return (&sc->mem); + break; } - return (0); + return (NULL); } static int @@ -249,6 +260,21 @@ dev = sc->dev; + /* XXX: Gross hack, disable all windows for testing. */ + if (pcib_clear) { + device_printf(dev, "Clearing windows\n"); + pci_write_config(dev, PCIR_IOBASEL_1, 0xff, 1); + pci_write_config(dev, PCIR_IOBASEH_1, 0xffff, 2); + pci_write_config(dev, PCIR_IOLIMITL_1, 0, 1); + pci_write_config(dev, PCIR_IOLIMITH_1, 0, 2); + pci_write_config(dev, PCIR_MEMBASE_1, 0xffff, 2); + pci_write_config(dev, PCIR_MEMLIMIT_1, 0, 2); + pci_write_config(dev, PCIR_PMBASEL_1, 0xffff, 2); + pci_write_config(dev, PCIR_PMBASEH_1, 0xffffffff, 4); + pci_write_config(dev, PCIR_PMLIMITL_1, 0, 2); + pci_write_config(dev, PCIR_PMLIMITH_1, 0, 4); + } + /* Determine if the I/O port window is implemented. */ val = pci_read_config(dev, PCIR_IOBASEL_1, 1); if (val == 0) { @@ -822,12 +848,18 @@ * Clamp the desired resource range to the maximum address * this window supports. Reject impossible requests. */ - if (!w->valid) + if (!w->valid) { + device_printf(sc->dev, "growing invalid window\n"); return (EINVAL); + } if (end > w->rman.rm_end) end = w->rman.rm_end; - if (start + count - 1 > end || start + count < start) + if (start + count - 1 > end || start + count < start) { + device_printf(sc->dev, + "bad start, count, end (%#lx, %#lx, %#lx)\n", + start, count, end); return (EINVAL); + } /* * If there is no resource at all, just try to allocate enough @@ -871,6 +903,10 @@ goto updatewin; } + /* Nothing to do if the request fits in the current window. */ + if (start >= rman_get_start(w->res) && end <= rman_get_end(w->res)) + return (ENOSPC); + /* * See if growing the window would help. Compute the minimum * amount of address space needed on both the front and back @@ -881,6 +917,10 @@ * edge of the window, grow from the inner edge of the free * region. Otherwise grow from the window boundary. * + * As a special case, if the new region is an exact region + * that is a superset of the current window, align the ends + * and make a single adjust request to our parent. + * * XXX: Special case: if w->res is completely empty and the * request size is larger than w->res, we should find the * optimal aligned buffer containing w->res and allocate that. @@ -890,6 +930,16 @@ "attempting to grow %s window for (%#lx-%#lx,%#lx)\n", w->name, start, end, count); align = 1ul << RF_ALIGNMENT(flags); + if (start + count - 1 == end && start <= rman_get_start(w->res) && + end >= rman_get_end(w->res)) { + start &= (1ul << w->step) - 1; + end = roundup2(end + 1, 1ul << w->step) - 1; + if (bootverbose) + printf("\twide candidate range: %#lx-%#lx\n", + start, end); + error = bus_adjust_resource(sc->dev, type, w->res, start, end); + goto adjusted; + } if (start < rman_get_start(w->res)) { if (rman_first_free_region(&w->rman, &start_free, &end_free) != 0 || start_free != rman_get_start(w->res)) @@ -914,6 +964,8 @@ printf("\tfront candidate range: %#lx-%#lx\n", front, end_free); front &= ~(1ul << w->step) - 1; + if (bootverbose) + printf("\taligned front: %#lx\n", front); front = rman_get_start(w->res) - front; } else front = 0; @@ -941,7 +993,9 @@ if (bootverbose) printf("\tback candidate range: %#lx-%#lx\n", start_free, back); - back = roundup2(back + 1, 1ul << w->step) - 1; + back |= (1ul << w->step) - 1; + if (bootverbose) + printf("\taligned back: %#lx\n", back); back -= rman_get_end(w->res); } else back = 0; @@ -955,6 +1009,10 @@ error = ENOSPC; while (front != 0 || back != 0) { if (front != 0 && (front <= back || back == 0)) { + device_printf(sc->dev, + "bus_adjust_resource(%#lx, %#lx)\n", + rman_get_start(w->res) - front, + rman_get_end(w->res)); error = bus_adjust_resource(sc->dev, type, w->res, rman_get_start(w->res) - front, rman_get_end(w->res)); @@ -962,6 +1020,10 @@ break; front = 0; } else { + device_printf(sc->dev, + "bus_adjust_resource(%#lx, %#lx)\n", + rman_get_start(w->res), + rman_get_end(w->res) + back); error = bus_adjust_resource(sc->dev, type, w->res, rman_get_start(w->res), rman_get_end(w->res) + back); @@ -971,6 +1033,7 @@ } } +adjusted: if (error) return (error); if (bootverbose) @@ -1099,10 +1162,28 @@ u_long start, u_long end) { struct pcib_softc *sc; + struct pcib_window *w; + int error; sc = device_get_softc(bus); - if (pcib_is_resource_managed(sc, type, r)) - return (rman_adjust_resource(r, start, end)); + w = pcib_is_resource_managed(sc, type, r); + if (w != NULL) { + device_printf(bus, "Trying first adjust for %s:%#x\n", + device_get_nameunit(child), rman_get_rid(r)); + error = rman_adjust_resource(r, start, end); + if (error == 0) + return (error); + + /* + * If the initial adjustment fails, try to grow the + * window that backs this resource. + */ + device_printf(bus, "Trying to grow window for adjustment\n"); + if (pcib_grow_window(sc, w, type, start, end, end - start + 1, + rman_get_flags(r)) == 0) + error = rman_adjust_resource(r, start, end); + return (error); + } return (bus_generic_adjust_resource(bus, child, type, r, start, end)); } @@ -1114,7 +1195,7 @@ int error; sc = device_get_softc(dev); - if (pcib_is_resource_managed(sc, type, r)) { + if (pcib_is_resource_managed(sc, type, r) != NULL) { if (rman_get_flags(r) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, r); if (error) Index: x86/x86/nexus.c =================================================================== --- x86/x86/nexus.c (revision 237008) +++ x86/x86/nexus.c (working copy) @@ -409,6 +409,8 @@ { struct rman *rm; + device_printf(bus, "bus_adjust_resource(%s, %#x, %#lx, %#lx)\n", + device_get_nameunit(child), rman_get_rid(r), start, end); rm = nexus_rman(type); if (rm == NULL) return (ENXIO);