Date: Mon, 4 Apr 2011 20:26:42 GMT From: John Baldwin <jhb@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 191047 for review Message-ID: <201104042026.p34KQg8I050072@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@191047?ac=10 Change 191047 by jhb@jhb_jhbbsd on 2011/04/04 20:25:44 Checkpoint. Have routines for suballocating from the window and for growing the window if needed. Next up is writing a new pcib_alloc_resource() based on these routines. We will need special handling for ISA resources similar to the special handling for VGA resources I think. Affected files ... .. //depot/projects/pci/sys/dev/pci/pci_pci.c#6 edit .. //depot/projects/pci/sys/dev/pci/pcib_private.h#5 edit Differences ... ==== //depot/projects/pci/sys/dev/pci/pci_pci.c#6 (text+ko) ==== @@ -53,12 +53,6 @@ #include "pcib_if.h" -#ifdef NEW_PCIB -#define WIN_IO 0x1 -#define WIN_MEM 0x2 -#define WIN_PMEM 0x4 -#endif - static int pcib_probe(device_t dev); static int pcib_suspend(device_t dev); static int pcib_resume(device_t dev); @@ -144,7 +138,7 @@ static void pcib_alloc_window(struct pcib_softc *sc, struct pcib_window *w, int type, - int reg, int flags, const char *name, pci_addr_t max_address) + int flags, const char *name, pci_addr_t max_address) { int error, rid; @@ -169,7 +163,7 @@ "initial %s window has too many bits, ignoring\n", name); return; } - rid = reg; + rid = w->reg; w->res = bus_alloc_resource(sc->dev, type, &rid, w->base, w->limit, w->limit - w->base + 1, flags); if (w->res == NULL) { @@ -215,6 +209,9 @@ /* Read the existing I/O port window. */ if (sc->io.valid) { + sc->io.reg = PCIR_IOBASEL_1; + sc->io.step = 12; + sc->io.mask = WIN_IO; if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { sc->io.base = PCI_PPBIOBASE( pci_read_config(dev, PCIR_IOBASEH_1, 2), val); @@ -228,18 +225,21 @@ pci_read_config(dev, PCIR_IOLIMITL_1, 1)); max = 0xffff; } - pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, PCIR_IOBASEL_1, - 0, "I/O port", max); + pcib_alloc_window(sc, &sc->io, SYS_RES_IOPORT, 0, "I/O port", + max); } /* Read the existing memory window. */ sc->mem.valid = 1; + sc->mem.reg = PCIR_MEMBASE_1; + sc->mem.step = 20; + sc->mem.mask = WIN_MEM; sc->mem.base = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); sc->mem.limit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); - pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, PCIR_MEMBASE_1, 0, - "memory", 0xffffffff); + pcib_alloc_window(sc, &sc->mem, SYS_RES_MEMORY, 0, "memory", + 0xffffffff); /* Determine if the prefetchable memory window is implemented. */ val = pci_read_config(dev, PCIR_PMBASEL_1, 2); @@ -258,6 +258,9 @@ /* Read the existing prefetchable memory window. */ if (sc->pmem.valid) { + sc->pmem.reg = PCIR_PMBASEL_1; + sc->pmem.step = 20; + sc->omem.mask = WIN_PMEM; if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { sc->pmem.base = PCI_PPBMEMBASE( pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); @@ -271,7 +274,7 @@ pci_read_config(dev, PCIR_PMLIMITL_1, 2)); max = 0xffffffff; } - pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, PCIR_PMBASEL_1, + pcib_alloc_window(sc, &sc->pmem, SYS_RES_MEMORY, RF_PREFETCHABLE, "prefetchable memory", max); } } @@ -780,9 +783,138 @@ /* * Attempt to grow a window to make room for a given resource request. + * The 'step' parameter is log_2 of the desired I/O window's alignment. */ static int -pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w +pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, u_long start, + u_long end, u_long count, u_int flags) +{ + u_long align, start_free, end_free, front, back; + int error, rid; + + /* + * If there is no resource at all, just try to allocate enough + * aligned space for this resource. + */ + if (w->res == NULL) { + if (RF_ALIGNMENT(flags) < w->step) { + flags &= ~RF_ALIGNMENT_MASK; + flags |= RF_ALIGNMENT_LOG2(w->step); + } + start &= ((1ul << w->step) - 1); + end |= ((1ul << w->step) - 1); + if (count < (1ul << w->step)) + count = 1ul << w->step; + rid = w->reg; + w->res = bus_alloc_resource(sc->dev, w == &sc->io ? + SYS_RES_IOPORT : SYS_RES_MEMORY, &rid, start, end, count, + flags); + if (w->res == NULL) + return (ENXIO); + goto updatewin; + } + + /* + * See if growing the window would help. Compute the minimum + * amount of address space needed on both the front and back + * ends of the existing window to satisfy the allocation. + * + * For each end, build a candidate region adjusting for the + * required alignment, etc. If there is a free region at the + * edge of the window, grow from the inner edge of the free + * region. Otherwise grow from the window boundary. + * + * 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. + */ + align = 1ul << RF_ALIGNMENT_MASK(flags); + if (start < rman_get_start(w->res)) { + if (rman_first_free_region(&w->rm, &start_free, &end_free) != + 0 || start_free != rman_get_start(w->res)) + end_free = rman_get_start(w->res) - 1; + if (end_free > end) + end_free = end; + + /* Move end_free down until it is properly aligned. */ + end_free &= (align - 1); + front = end_free - count; + + /* + * The resource would now be allocated at (front, + * end_free). Ensure that fits in the (start, end) + * bounds. end_free is checked above. If 'front' is + * ok, ensure it is properly aligned for this window. + */ + if (front >= start) { + front &= (1ul << w->step) - 1; + front = rman_get_start(w->res) - front; + } else + front = 0; + } else + front = 0; + if (end > rman_get_end(w->res)) { + if (rman_last_free_region(&w->rm, &start_free, &end_free) != + 0 || end_free != rman_get_end(w->res)) + start_free = rman_get_end(w->res) + 1; + if (start_free < start) + start_free = start; + + /* Move start_free up until it is properly aligned. */ + start_free = roundup2(start_free, align); + back = start_free + count; + + /* + * The resource would now be allocated at (start_free, + * back). Ensure that fits in the (start, end) + * bounds. start_free is checked above. If 'back' is + * ok, ensure it is properly aligned for this window. + */ + if (back <= end) { + back = roundup2(back, w->step) - 1; + back -= rman_get_end(w->res); + } else + back = 0; + } else + back = 0; + + /* + * Try to allocate the smallest needed region first. + * If that fails, fall back to the other region. + */ + error = ENOSPC; + while (front != 0 || back != 0) { + if (front != 0 && (front <= back || back == 0)) { + error = bus_adjust_resource(sc->dev, w->type, w->res, + rman_get_start(w->res) - front, + rman_get_end(w->res)); + if (error == 0) + break; + front = 0; + } else { + error = bus_adjust_resource(sc->dev, w->type, w->res, + rman_get_start(w->res), + rman_get_end(w->res) + back); + if (error == 0) + break; + back = 0; + } + } + + if (error) + return (error); + +updatewin: + /* Save the new window. */ + w->base = rman_get_start(w->res); + w->limit = rman_get_end(w->res); + KASSERT((w->base & ((1ul << w->step) - 1)) == 0, + ("start address is not aligned")); + KASSERT((w->end & ((1ul << w->step) - 1)) == (1ul << w->step) - 1, + ("end address is not aligned")); + pcib_write_windows(sc, w->mask); + return (0); +} /* * We have to trap resource allocation requests and ensure that the bridge ==== //depot/projects/pci/sys/dev/pci/pcib_private.h#5 (text+ko) ==== @@ -40,12 +40,19 @@ DECLARE_CLASS(pcib_driver); #ifdef NEW_PCIB +#define WIN_IO 0x1 +#define WIN_MEM 0x2 +#define WIN_PMEM 0x4 + struct pcib_window { - pci_addr_t base; - pci_addr_t limit; + pci_addr_t base; /* base address */ + pci_addr_t limit; /* topmost address */ struct rman rman; struct resource *res; + int reg; /* resource id from parent */ int valid; + int mask; /* WIN_* bitmask of this window */ + int step; /* log_2 of window granularity */ }; #endif @@ -64,10 +71,9 @@ u_int secbus; /* secondary bus number */ u_int subbus; /* subordinate bus number */ #ifdef NEW_PCIB - u_int valid_windows; + struct pcib_window io; /* I/O port window */ + struct pcib_window mem; /* memory window */ struct pcib_window pmem; /* prefetchable memory window */ - struct pcib_window mem; /* memory window */ - struct pcib_window io; /* I/O port window */ #else pci_addr_t pmembase; /* base address of prefetchable memory */ pci_addr_t pmemlimit; /* topmost address of prefetchable memory */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104042026.p34KQg8I050072>
