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