PERFORCE change 191047 for review
John Baldwin
jhb at FreeBSD.org
Mon Apr 4 20:26:43 UTC 2011
http://p4web.freebsd.org/@@191047?ac=10
Change 191047 by jhb at 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 */
More information about the p4-projects
mailing list