PERFORCE change 113099 for review

Roman Divacky rdivacky at FreeBSD.org
Thu Jan 18 10:02:54 UTC 2007


http://perforce.freebsd.org/chv.cgi?CH=113099

Change 113099 by rdivacky at rdivacky_witten on 2007/01/18 10:02:38

	IFC

Affected files ...

.. //depot/projects/linuxolator/src/sys/amd64/include/md_var.h#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/arm/busdma_machdep.c#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/arm/vm_machdep.c#4 integrate
.. //depot/projects/linuxolator/src/sys/arm/include/bus_dma.h#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/include/md_var.h#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/include/pmap.h#4 integrate
.. //depot/projects/linuxolator/src/sys/arm/xscale/ixp425/if_npe.c#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/xscale/ixp425/ixp425.c#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/xscale/ixp425/ixp425_pci.c#2 integrate
.. //depot/projects/linuxolator/src/sys/arm/xscale/ixp425/ixp425var.h#2 integrate
.. //depot/projects/linuxolator/src/sys/compat/linux/linux_file.c#11 integrate
.. //depot/projects/linuxolator/src/sys/conf/files.sparc64#5 integrate
.. //depot/projects/linuxolator/src/sys/ddb/db_command.c#5 integrate
.. //depot/projects/linuxolator/src/sys/ddb/db_thread.c#2 integrate
.. //depot/projects/linuxolator/src/sys/dev/fb/creator.c#2 integrate
.. //depot/projects/linuxolator/src/sys/dev/fb/creatorreg.h#2 integrate
.. //depot/projects/linuxolator/src/sys/dev/mfi/mfi_pci.c#2 integrate
.. //depot/projects/linuxolator/src/sys/dev/mii/brgphy.c#6 integrate
.. //depot/projects/linuxolator/src/sys/dev/pci/pci.c#14 integrate
.. //depot/projects/linuxolator/src/sys/dev/pci/pcireg.h#4 integrate
.. //depot/projects/linuxolator/src/sys/dev/re/if_re.c#6 integrate
.. //depot/projects/linuxolator/src/sys/dev/sound/pci/hda/hdac_private.h#3 integrate
.. //depot/projects/linuxolator/src/sys/dev/usb/ums.c#2 integrate
.. //depot/projects/linuxolator/src/sys/fs/msdosfs/denode.h#3 integrate
.. //depot/projects/linuxolator/src/sys/fs/msdosfs/msdosfs_fat.c#2 integrate
.. //depot/projects/linuxolator/src/sys/i386/i386/pmap.c#6 integrate
.. //depot/projects/linuxolator/src/sys/i386/ibcs2/ibcs2_sysvec.c#2 integrate
.. //depot/projects/linuxolator/src/sys/kern/imgact_elf.c#3 integrate
.. //depot/projects/linuxolator/src/sys/kern/init_main.c#7 integrate
.. //depot/projects/linuxolator/src/sys/kern/kern_descrip.c#5 integrate
.. //depot/projects/linuxolator/src/sys/kern/kern_ktrace.c#5 integrate
.. //depot/projects/linuxolator/src/sys/kern/kern_resource.c#7 integrate
.. //depot/projects/linuxolator/src/sys/kern/kern_sig.c#7 integrate
.. //depot/projects/linuxolator/src/sys/kern/kern_subr.c#5 integrate
.. //depot/projects/linuxolator/src/sys/kern/subr_turnstile.c#3 integrate
.. //depot/projects/linuxolator/src/sys/kern/subr_witness.c#5 integrate
.. //depot/projects/linuxolator/src/sys/net/bridgestp.c#9 integrate
.. //depot/projects/linuxolator/src/sys/netinet6/icmp6.c#3 integrate
.. //depot/projects/linuxolator/src/sys/pci/if_rlreg.h#3 integrate
.. //depot/projects/linuxolator/src/sys/pci/intpm.c#4 integrate
.. //depot/projects/linuxolator/src/sys/sparc64/creator/creator.h#2 delete
.. //depot/projects/linuxolator/src/sys/sparc64/creator/creator_upa.c#2 delete
.. //depot/projects/linuxolator/src/sys/sparc64/sparc64/ofw_machdep.c#2 integrate
.. //depot/projects/linuxolator/src/sys/sparc64/sparc64/upa.c#1 branch
.. //depot/projects/linuxolator/src/sys/ufs/ffs/ffs_alloc.c#3 integrate
.. //depot/projects/linuxolator/src/sys/ufs/ufs/ufs_vnops.c#7 integrate
.. //depot/projects/linuxolator/src/sys/vm/vm_object.c#5 integrate
.. //depot/projects/linuxolator/src/sys/vm/vm_pageout.c#3 integrate

Differences ...

==== //depot/projects/linuxolator/src/sys/amd64/include/md_var.h#2 (text+ko) ====

@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/amd64/include/md_var.h,v 1.78 2006/06/19 22:36:01 davidxu Exp $
+ * $FreeBSD: src/sys/amd64/include/md_var.h,v 1.80 2007/01/18 05:46:32 rodrigc Exp $
  */
 
 #ifndef _MACHINE_MD_VAR_H_

==== //depot/projects/linuxolator/src/sys/arm/arm/busdma_machdep.c#2 (text+ko) ====

@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/arm/arm/busdma_machdep.c,v 1.27 2006/08/25 15:10:45 cognet Exp $");
+__FBSDID("$FreeBSD: src/sys/arm/arm/busdma_machdep.c,v 1.28 2007/01/17 00:53:05 cognet Exp $");
 
 /*
  * MacPPC bus dma support routines
@@ -48,6 +48,7 @@
 #include <sys/uio.h>
 #include <sys/ktr.h>
 #include <sys/kernel.h>
+#include <sys/sysctl.h>
 
 #include <vm/vm.h>
 #include <vm/vm_page.h>
@@ -56,7 +57,14 @@
 #include <machine/atomic.h>
 #include <machine/bus.h>
 #include <machine/cpufunc.h>
+#include <machine/md_var.h>
 
+#define MAX_BPAGES 64
+#define BUS_DMA_COULD_BOUNCE	BUS_DMA_BUS3
+#define BUS_DMA_MIN_ALLOC_COMP	BUS_DMA_BUS4
+
+struct bounce_zone;
+
 struct bus_dma_tag {
 	bus_dma_tag_t		parent;
 	bus_size_t		alignment;
@@ -81,8 +89,47 @@
 	 */
 	struct arm32_dma_range	*ranges;
 	int			_nranges;
+	struct bounce_zone *bounce_zone;
 };
 
+struct bounce_page {
+	vm_offset_t	vaddr;		/* kva of bounce buffer */
+	vm_offset_t	vaddr_nocache;	/* kva of bounce buffer uncached */
+	bus_addr_t	busaddr;	/* Physical address */
+	vm_offset_t	datavaddr;	/* kva of client data */
+	bus_size_t	datacount;	/* client data count */
+	STAILQ_ENTRY(bounce_page) links;
+};
+
+int busdma_swi_pending;
+
+struct bounce_zone {
+	STAILQ_ENTRY(bounce_zone) links;
+	STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
+	int		total_bpages;
+	int		free_bpages;
+	int		reserved_bpages;
+	int		active_bpages;
+	int		total_bounced;
+	int		total_deferred;
+	bus_size_t	alignment;
+	bus_size_t	boundary;
+	bus_addr_t	lowaddr;
+	char		zoneid[8];
+	char		lowaddrid[20];
+	struct sysctl_ctx_list sysctl_tree;
+	struct sysctl_oid *sysctl_tree_top;
+};
+
+static struct mtx bounce_lock;
+static int total_bpages;
+static int busdma_zonecount;
+static STAILQ_HEAD(, bounce_zone) bounce_zone_list;
+
+SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters");
+SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0,
+	   "Total bounce pages");
+
 #define DMAMAP_LINEAR		0x1
 #define DMAMAP_MBUF		0x2
 #define DMAMAP_UIO		0x4
@@ -90,6 +137,9 @@
 #define DMAMAP_TYPE_MASK	(DMAMAP_LINEAR|DMAMAP_MBUF|DMAMAP_UIO)
 #define DMAMAP_COHERENT		0x8
 struct bus_dmamap {
+	struct bp_list	bpages;
+	int		pagesneeded;
+	int		pagesreserved;
         bus_dma_tag_t	dmat;
 	int		flags;
 	void 		*buffer;
@@ -97,8 +147,15 @@
 	void		*allocbuffer;
 	TAILQ_ENTRY(bus_dmamap)	freelist;
 	int		len;
+	STAILQ_ENTRY(bus_dmamap) links;
+	bus_dmamap_callback_t *callback;
+	void		      *callback_arg;
+
 };
 
+static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
+static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
+
 static TAILQ_HEAD(,bus_dmamap) dmamap_freelist = 
 	TAILQ_HEAD_INITIALIZER(dmamap_freelist);
 
@@ -109,6 +166,45 @@
 
 MTX_SYSINIT(busdma_mtx, &busdma_mtx, "busdma lock", MTX_DEF);
 
+static void init_bounce_pages(void *dummy);
+static int alloc_bounce_zone(bus_dma_tag_t dmat);
+static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages);
+static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+				int commit);
+static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map,
+				   vm_offset_t vaddr, bus_size_t size);
+static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
+
+/* Default tag, as most drivers provide no parent tag. */
+bus_dma_tag_t arm_root_dma_tag;
+
+/*
+ * Return true if a match is made.
+ *
+ * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'.
+ *
+ * If paddr is within the bounds of the dma tag then call the filter callback
+ * to check for a match, if there is no filter callback then assume a match.
+ */
+static int
+run_filter(bus_dma_tag_t dmat, bus_addr_t paddr)
+{
+	int retval;
+
+	retval = 0;
+
+	do {
+		if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr)
+		 || ((paddr & (dmat->alignment - 1)) != 0))
+		 && (dmat->filter == NULL
+		  || (*dmat->filter)(dmat->filterarg, paddr) != 0))
+			retval = 1;
+
+		dmat = dmat->parent;		
+	} while (retval == 0 && dmat != NULL);
+	return (retval);
+}
+
 static void
 arm_dmamap_freelist_init(void *dummy)
 {
@@ -129,6 +225,19 @@
     bus_dmamap_t map, void *buf, bus_size_t buflen, struct pmap *pmap,
     int flags, vm_offset_t *lastaddrp, int *segp);
 
+static __inline int
+_bus_dma_can_bounce(vm_offset_t lowaddr, vm_offset_t highaddr)
+{
+	int i;
+	for (i = 0; phys_avail[i] && phys_avail[i + 1]; i += 2) {
+		if ((lowaddr >= phys_avail[i] && lowaddr <= phys_avail[i + 1])
+		    || (lowaddr < phys_avail[i] && 
+		    highaddr > phys_avail[i]))
+			return (1);
+	}
+	return (0);
+}
+
 static __inline struct arm32_dma_range *
 _bus_dma_inrange(struct arm32_dma_range *ranges, int nranges,
     bus_addr_t curaddr)
@@ -195,11 +304,12 @@
 		TAILQ_REMOVE(&dmamap_freelist, map, freelist);
 	mtx_unlock(&busdma_mtx);
 	if (!map) {
-		map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
+		map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
 		if (map)
 			map->flags = DMAMAP_ALLOCATED;
 	} else
 		map->flags = 0;
+	STAILQ_INIT(&map->bpages);
 	return (map);
 }
 
@@ -232,6 +342,8 @@
 	int error = 0;
 	/* Return a NULL tag on failure */
 	*dmat = NULL;
+	if (!parent)
+		parent = arm_root_dma_tag;
 
 	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
 	if (newtag == NULL) {
@@ -273,6 +385,9 @@
 		else if (parent->boundary != 0)
                 	newtag->boundary = min(parent->boundary,
 					       newtag->boundary);
+		if ((newtag->filter != NULL) ||
+		    ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0))
+			newtag->flags |= BUS_DMA_COULD_BOUNCE;
                 if (newtag->filter == NULL) {
                         /*
                          * Short circuit looking at our parent directly
@@ -285,8 +400,38 @@
 		if (newtag->parent != NULL)
 			atomic_add_int(&parent->ref_count, 1);
 	}
+	if (_bus_dma_can_bounce(newtag->lowaddr, newtag->highaddr)
+	 || newtag->alignment > 1)
+		newtag->flags |= BUS_DMA_COULD_BOUNCE;
+
+	if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+	    (flags & BUS_DMA_ALLOCNOW) != 0) {
+		struct bounce_zone *bz;
+
+		/* Must bounce */
+
+		if ((error = alloc_bounce_zone(newtag)) != 0) {
+			free(newtag, M_DEVBUF);
+			return (error);
+		}
+		bz = newtag->bounce_zone;
 
-	*dmat = newtag;
+		if (ptoa(bz->total_bpages) < maxsize) {
+			int pages;
+
+			pages = atop(maxsize) - bz->total_bpages;
+
+			/* Add pages to our bounce pool */
+			if (alloc_bounce_pages(newtag, pages) < pages)
+				error = ENOMEM;
+		}
+		/* Performed initial allocation */
+		newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
+	}
+	if (error != 0)
+		free(newtag, M_DEVBUF);
+	else
+		*dmat = newtag;
 	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
 	    __func__, newtag, (newtag != NULL ? newtag->flags : 0), error);
 
@@ -327,6 +472,7 @@
         return (0);
 }
 
+#include <sys/kdb.h>
 /*
  * Allocate a handle for mapping from kva/uva/physical
  * address space into bus device space.
@@ -335,9 +481,7 @@
 bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
 {
 	bus_dmamap_t newmap;
-#ifdef KTR
 	int error = 0;
-#endif
 
 	newmap = _busdma_alloc_dmamap();
 	if (newmap == NULL) {
@@ -349,6 +493,52 @@
 	newmap->allocbuffer = NULL;
 	dmat->map_count++;
 
+	/*
+	 * Bouncing might be required if the driver asks for an active
+	 * exclusion region, a data alignment that is stricter than 1, and/or
+	 * an active address boundary.
+	 */
+	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
+
+		/* Must bounce */
+		struct bounce_zone *bz;
+		int maxpages;
+
+		if (dmat->bounce_zone == NULL) {
+			if ((error = alloc_bounce_zone(dmat)) != 0) {
+				_busdma_free_dmamap(newmap);
+				*mapp = NULL;
+				return (error);
+			}
+		}
+		bz = dmat->bounce_zone;
+
+		/* Initialize the new map */
+		STAILQ_INIT(&((*mapp)->bpages));
+
+		/*
+		 * Attempt to add pages to our pool on a per-instance
+		 * basis up to a sane limit.
+		 */
+		maxpages = MAX_BPAGES;
+		if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
+		 || (dmat->map_count > 0 && bz->total_bpages < maxpages)) {
+			int pages;
+
+			pages = MAX(atop(dmat->maxsize), 1);
+			pages = MIN(maxpages - bz->total_bpages, pages);
+			pages = MAX(pages, 1);
+			if (alloc_bounce_pages(dmat, pages) < pages)
+				error = ENOMEM;
+
+			if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) {
+				if (error == 0)
+					dmat->flags |= BUS_DMA_MIN_ALLOC_COMP;
+			} else {
+				error = 0;
+			}
+		}
+	}
 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
 	    __func__, dmat, dmat->flags, error);
 
@@ -364,6 +554,11 @@
 {
 
 	_busdma_free_dmamap(map);
+	if (STAILQ_FIRST(&map->bpages) != NULL) {
+		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+		    __func__, dmat, EBUSY);
+		return (EBUSY);
+	}
         dmat->map_count--;
 	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
         return (0);
@@ -399,7 +594,9 @@
 	*mapp = newmap;
 	newmap->dmat = dmat;
 	
-        if (dmat->maxsize <= PAGE_SIZE) {
+        if (dmat->maxsize <= PAGE_SIZE &&
+	   (dmat->alignment < dmat->maxsize) &&
+	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) {
                 *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags);
         } else {
                 /*
@@ -452,7 +649,9 @@
 		vaddr = map->origbuffer;
 		arm_unmap_nocache(map->allocbuffer, dmat->maxsize);
 	}
-        if (dmat->maxsize <= PAGE_SIZE)
+        if (dmat->maxsize <= PAGE_SIZE &&
+	   dmat->alignment < dmat->maxsize &&
+	    !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr))
 		free(vaddr, M_DEVBUF);
         else {
 		contigfree(vaddr, dmat->maxsize, M_DEVBUF);
@@ -462,6 +661,64 @@
 	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
 }
 
+static int
+_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
+			bus_size_t buflen, int flags, int *nb)
+{
+	vm_offset_t vaddr;
+	vm_offset_t vendaddr;
+	bus_addr_t paddr;
+	int needbounce = *nb;
+
+	if ((map->pagesneeded == 0)) {
+		CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
+		    "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem),
+		    dmat->boundary, dmat->alignment);
+		CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d",
+		    map, &nobounce_dmamap, map->pagesneeded);
+		/*
+		 * Count the number of bounce pages
+		 * needed in order to complete this transfer
+		 */
+		vaddr = trunc_page((vm_offset_t)buf);
+		vendaddr = (vm_offset_t)buf + buflen;
+
+		while (vaddr < vendaddr) {
+			paddr = pmap_kextract(vaddr);
+			if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+			    run_filter(dmat, paddr) != 0) {
+				needbounce = 1;
+				map->pagesneeded++;
+			}
+			vaddr += PAGE_SIZE;
+		}
+		CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
+	}
+
+	/* Reserve Necessary Bounce Pages */
+	if (map->pagesneeded != 0) {
+		mtx_lock(&bounce_lock);
+		if (flags & BUS_DMA_NOWAIT) {
+			if (reserve_bounce_pages(dmat, map, 0) != 0) {
+				mtx_unlock(&bounce_lock);
+				return (ENOMEM);
+			}
+		} else {
+			if (reserve_bounce_pages(dmat, map, 1) != 0) {
+				/* Queue us for resources */
+				STAILQ_INSERT_TAIL(&bounce_map_waitinglist,
+				    map, links);
+				mtx_unlock(&bounce_lock);
+				return (EINPROGRESS);
+			}
+		}
+		mtx_unlock(&bounce_lock);
+	}
+
+	*nb = needbounce;
+	return (0);
+}
+
 /*
  * Utility function to load a linear buffer.  lastaddrp holds state
  * between invocations (for multiple-buffer loads).  segp contains
@@ -481,10 +738,17 @@
 	pd_entry_t *pde;
 	pt_entry_t pte;
 	pt_entry_t *ptep;
+	int needbounce = 0;
 
 	lastaddr = *lastaddrp;
 	bmask = ~(dmat->boundary - 1);
 
+	if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) {
+		error = _bus_dmamap_count_pages(dmat, map, buf, buflen, flags,
+		    &needbounce);
+		if (error)
+			return (error);
+	}
 	CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, "
 	    "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment);
 
@@ -531,20 +795,6 @@
 			map->flags &= ~DMAMAP_COHERENT;
 		}
 
-		if (dmat->ranges) {
-			struct arm32_dma_range *dr;
-
-			dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
-			    curaddr);
-			if (dr == NULL)
-				return (EINVAL);
-			/*
-		     	 * In a valid DMA range.  Translate the physical
-			 * memory address to an address in the DMA window.
-			 */
-			curaddr = (curaddr - dr->dr_sysbase) + dr->dr_busbase;
-						
-		}
 		/*
 		 * Compute the segment size, and adjust counts.
 		 */
@@ -560,12 +810,30 @@
 			if (sgsize > (baddr - curaddr))
 				sgsize = (baddr - curaddr);
 		}
+		if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+		    map->pagesneeded != 0 && run_filter(dmat, curaddr))
+			curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
+
+		if (dmat->ranges) {
+			struct arm32_dma_range *dr;
 
+			dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
+			    curaddr);
+			if (dr == NULL)
+				return (EINVAL);
+			/*
+		     	 * In a valid DMA range.  Translate the physical
+			 * memory address to an address in the DMA window.
+			 */
+			curaddr = (curaddr - dr->dr_sysbase) + dr->dr_busbase;
+						
+		}
+
 		/*
 		 * Insert chunk into a segment, coalescing with
 		 * the previous segment if possible.
 		 */
-		if (seg >= 0 && curaddr == lastaddr &&
+		if (needbounce == 0 && seg >= 0 && curaddr == lastaddr &&
 		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
 		    (dmat->boundary == 0 ||
 		     (segs[seg].ds_addr & bmask) == 
@@ -615,6 +883,8 @@
 
 	KASSERT(dmat != NULL, ("dmatag is NULL"));
 	KASSERT(map != NULL, ("dmamap is NULL"));
+	map->callback = callback;
+	map->callback_arg = callback_arg;
 	map->flags &= ~DMAMAP_TYPE_MASK;
 	map->flags |= DMAMAP_LINEAR|DMAMAP_COHERENT;
 	map->buffer = buf;
@@ -622,6 +892,8 @@
 	error = bus_dmamap_load_buffer(dmat,
 	    dm_segments, map, buf, buflen, kernel_pmap,
 	    flags, &lastaddr, &nsegs);
+	if (error == EINPROGRESS)
+		return (error);
 	if (error)
 		(*callback)(callback_arg, NULL, 0, error);
 	else
@@ -797,26 +1069,93 @@
 void
 _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
 {
+	struct bounce_page *bpage;
+
 	map->flags &= ~DMAMAP_TYPE_MASK;
+	while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
+		STAILQ_REMOVE_HEAD(&map->bpages, links);
+		free_bounce_page(dmat, bpage);
+	}
 	return;
 }
 
 static __inline void
 bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op)
 {
+	char _tmp_cl[arm_dcache_align], _tmp_clend[arm_dcache_align];
 
 	if (op & BUS_DMASYNC_PREWRITE)
 		cpu_dcache_wb_range((vm_offset_t)buf, len);
-	if (op & BUS_DMASYNC_PREREAD) {
+	if (op & BUS_DMASYNC_POSTREAD) {
+		if ((vm_offset_t)buf & arm_dcache_align_mask)
+			memcpy(_tmp_cl, (void *)((vm_offset_t)buf & ~
+			    arm_dcache_align_mask),
+			    (vm_offset_t)buf - ((vm_offset_t)buf &~
+			    arm_dcache_align_mask));
+		if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
+			memcpy(_tmp_cl, (void *)((vm_offset_t)buf & ~
+			    arm_dcache_align_mask),
+			    (vm_offset_t)buf - ((vm_offset_t)buf &~
+			    arm_dcache_align_mask));
+		if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
+			memcpy(_tmp_clend, (void *)(((vm_offset_t)buf + len) & ~
+			    arm_dcache_align_mask),
+			    (vm_offset_t)buf +len - (((vm_offset_t)buf + len) &~
+			    arm_dcache_align_mask));
+		cpu_dcache_inv_range((vm_offset_t)buf, len);
 		if ((vm_offset_t)buf & arm_dcache_align_mask)
-			cpu_dcache_wbinv_range((vm_offset_t)buf &
-			    ~arm_dcache_align_mask, arm_dcache_align);
+			memcpy((void *)((vm_offset_t)buf &
+			    ~arm_dcache_align_mask),
+			    _tmp_cl, 
+			    (vm_offset_t)buf - ((vm_offset_t)buf &~
+			    arm_dcache_align_mask));
 		if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
-			cpu_dcache_wbinv_range(((vm_offset_t)buf + len) & 
-			    ~arm_dcache_align_mask, arm_dcache_align);
+			memcpy((void *)(((vm_offset_t)buf + len) & ~
+			    arm_dcache_align_mask), _tmp_clend,
+			    (vm_offset_t)buf +len - (((vm_offset_t)buf + len) &~
+			    arm_dcache_align_mask));
+	}
+}
+
+static void
+_bus_dmamap_sync_bp(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
+{
+	struct bounce_page *bpage;
+
+	STAILQ_FOREACH(bpage, &map->bpages, links) {
+		if (op & BUS_DMASYNC_PREWRITE) {
+			bcopy((void *)bpage->datavaddr,
+			    (void *)(bpage->vaddr_nocache != 0 ? 
+				     bpage->vaddr_nocache : bpage->vaddr),
+			    bpage->datacount);
+			if (bpage->vaddr_nocache == 0)
+				cpu_dcache_wb_range(bpage->vaddr,
+				    bpage->datacount);
+		}
+		if (op & BUS_DMASYNC_POSTREAD) {
+			if (bpage->vaddr_nocache == 0)
+				cpu_dcache_inv_range(bpage->vaddr,
+				    bpage->datacount);
+			bcopy((void *)(bpage->vaddr_nocache != 0 ? 
+	       		    bpage->vaddr_nocache : bpage->vaddr),
+			    (void *)bpage->datavaddr, bpage->datacount);
+		}
+	}
+}
+
+static __inline int
+_bus_dma_buf_is_in_bp(bus_dmamap_t map, void *buf, int len)
+{
+	struct bounce_page *bpage;
+
+	STAILQ_FOREACH(bpage, &map->bpages, links) {
+		if ((vm_offset_t)buf >= bpage->datavaddr &&
+		    (vm_offset_t)buf + len < bpage->datavaddr + 
+		    bpage->datacount)
+			return (1);
 	}
-	if (op & BUS_DMASYNC_POSTREAD) 
-		cpu_dcache_inv_range((vm_offset_t)buf, len);
+	return (0);
+
 }
 
 void
@@ -829,6 +1168,8 @@
 	
 	if (op == BUS_DMASYNC_POSTWRITE)
 		return;
+	if (STAILQ_FIRST(&map->bpages))
+		_bus_dmamap_sync_bp(dmat, map, op);
 	if (map->flags & DMAMAP_COHERENT)
 		return;
 	if ((op && BUS_DMASYNC_POSTREAD) && (map->len >= 2 * PAGE_SIZE)) {
@@ -838,12 +1179,14 @@
 	CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags);
 	switch(map->flags & DMAMAP_TYPE_MASK) {
 	case DMAMAP_LINEAR:
-		bus_dmamap_sync_buf(map->buffer, map->len, op);
+		if (!(_bus_dma_buf_is_in_bp(map, map->buffer, map->len)))
+			bus_dmamap_sync_buf(map->buffer, map->len, op);
 		break;
 	case DMAMAP_MBUF:
 		m = map->buffer;
 		while (m) {
-			if (m->m_len > 0)
+			if (m->m_len > 0 &&
+			    !(_bus_dma_buf_is_in_bp(map, m->m_data, m->m_len)))
 				bus_dmamap_sync_buf(m->m_data, m->m_len, op);
 			m = m->m_next;
 		}
@@ -856,8 +1199,10 @@
 			bus_size_t minlen = resid < iov[i].iov_len ? resid :
 			    iov[i].iov_len;
 			if (minlen > 0) {
-				bus_dmamap_sync_buf(iov[i].iov_base, minlen, 
-				    op);
+				if (!_bus_dma_buf_is_in_bp(map, iov[i].iov_base,
+				    minlen))
+					bus_dmamap_sync_buf(iov[i].iov_base,
+					    minlen, op);
 				resid -= minlen;
 			}
 		}
@@ -867,3 +1212,247 @@
 	}
 	cpu_drain_writebuf();
 }
+
+static void
+init_bounce_pages(void *dummy __unused)
+{
+
+	total_bpages = 0;
+	STAILQ_INIT(&bounce_zone_list);
+	STAILQ_INIT(&bounce_map_waitinglist);
+	STAILQ_INIT(&bounce_map_callbacklist);
+	mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF);
+}
+SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL);
+
+static struct sysctl_ctx_list *
+busdma_sysctl_tree(struct bounce_zone *bz)
+{
+	return (&bz->sysctl_tree);
+}
+
+static struct sysctl_oid *
+busdma_sysctl_tree_top(struct bounce_zone *bz)
+{
+	return (bz->sysctl_tree_top);
+}
+
+static int
+alloc_bounce_zone(bus_dma_tag_t dmat)
+{
+	struct bounce_zone *bz;
+
+	/* Check to see if we already have a suitable zone */
+	STAILQ_FOREACH(bz, &bounce_zone_list, links) {
+		if ((dmat->alignment <= bz->alignment)
+		 && (dmat->boundary <= bz->boundary)
+		 && (dmat->lowaddr >= bz->lowaddr)) {
+			dmat->bounce_zone = bz;
+			return (0);
+		}
+	}
+
+	if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF,
+	    M_NOWAIT | M_ZERO)) == NULL)
+		return (ENOMEM);
+
+	STAILQ_INIT(&bz->bounce_page_list);
+	bz->free_bpages = 0;
+	bz->reserved_bpages = 0;
+	bz->active_bpages = 0;
+	bz->lowaddr = dmat->lowaddr;
+	bz->alignment = dmat->alignment;
+	bz->boundary = dmat->boundary;
+	snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount);
+	busdma_zonecount++;
+	snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr);
+	STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links);
+	dmat->bounce_zone = bz;
+
+	sysctl_ctx_init(&bz->sysctl_tree);
+	bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree,
+	    SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid,
+	    CTLFLAG_RD, 0, "");
+	if (bz->sysctl_tree_top == NULL) {
+		sysctl_ctx_free(&bz->sysctl_tree);
+		return (0);	/* XXX error code? */
+	}
+
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0,
+	    "Total bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0,
+	    "Free bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0,
+	    "Reserved bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0,
+	    "Active bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0,
+	    "Total bounce requests");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0,
+	    "Total bounce requests that were deferred");
+	SYSCTL_ADD_STRING(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, "");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "alignment", CTLFLAG_RD, &bz->alignment, 0, "");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "boundary", CTLFLAG_RD, &bz->boundary, 0, "");
+
+	return (0);
+}
+
+static int
+alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages)
+{
+	struct bounce_zone *bz;
+	int count;
+
+	bz = dmat->bounce_zone;
+	count = 0;
+	while (numpages > 0) {
+		struct bounce_page *bpage;
+
+		bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF,
+						     M_NOWAIT | M_ZERO);
+
+		if (bpage == NULL)
+			break;
+		bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF,
+							 M_NOWAIT, 0ul,
+							 bz->lowaddr,
+							 PAGE_SIZE,
+							 bz->boundary);
+		if (bpage->vaddr == 0) {
+			free(bpage, M_DEVBUF);
+			break;
+		}
+		bpage->busaddr = pmap_kextract(bpage->vaddr);
+		bpage->vaddr_nocache = (vm_offset_t)arm_remap_nocache(
+		    (void *)bpage->vaddr, PAGE_SIZE);
+		mtx_lock(&bounce_lock);
+		STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links);
+		total_bpages++;
+		bz->total_bpages++;
+		bz->free_bpages++;
+		mtx_unlock(&bounce_lock);
+		count++;
+		numpages--;
+	}
+	return (count);
+}
+
+static int
+reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit)
+{
+	struct bounce_zone *bz;
+	int pages;
+
+	mtx_assert(&bounce_lock, MA_OWNED);
+	bz = dmat->bounce_zone;
+	pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved);
+	if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages))
+		return (map->pagesneeded - (map->pagesreserved + pages));
+	bz->free_bpages -= pages;
+	bz->reserved_bpages += pages;
+	map->pagesreserved += pages;
+	pages = map->pagesneeded - map->pagesreserved;
+
+	return (pages);
+}
+
+static bus_addr_t
+add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
+		bus_size_t size)
+{
+	struct bounce_zone *bz;
+	struct bounce_page *bpage;
+
+	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
+	KASSERT(map != NULL && map != &nobounce_dmamap,
+	    ("add_bounce_page: bad map %p", map));
+
+	bz = dmat->bounce_zone;
+	if (map->pagesneeded == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesneeded--;
+
+	if (map->pagesreserved == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesreserved--;
+
+	mtx_lock(&bounce_lock);
+	bpage = STAILQ_FIRST(&bz->bounce_page_list);
+	if (bpage == NULL)
+		panic("add_bounce_page: free page list is empty");
+
+	STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links);
+	bz->reserved_bpages--;
+	bz->active_bpages++;
+	mtx_unlock(&bounce_lock);
+
+	bpage->datavaddr = vaddr;
+	bpage->datacount = size;
+	STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
+	return (bpage->busaddr);
+}
+
+static void
+free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
+{
+	struct bus_dmamap *map;
+	struct bounce_zone *bz;
+
+	bz = dmat->bounce_zone;
+	bpage->datavaddr = 0;
+	bpage->datacount = 0;
+
+	mtx_lock(&bounce_lock);
+	STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);
+	bz->free_bpages++;
+	bz->active_bpages--;
+	if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) {
+		if (reserve_bounce_pages(map->dmat, map, 1) == 0) {
+			STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links);
+			STAILQ_INSERT_TAIL(&bounce_map_callbacklist,
+					   map, links);
+			busdma_swi_pending = 1;
+			bz->total_deferred++;
+			swi_sched(vm_ih, 0);
+		}
+	}
+	mtx_unlock(&bounce_lock);
+}
+
+void
+busdma_swi(void)
+{
+	bus_dma_tag_t dmat;
+	struct bus_dmamap *map;
+
+	mtx_lock(&bounce_lock);
+	while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
+		STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
+		mtx_unlock(&bounce_lock);
+		dmat = map->dmat;
+		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK);
+		bus_dmamap_load(map->dmat, map, map->buffer, map->len,
+		    map->callback, map->callback_arg, /*flags*/0);
+		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK);
+		mtx_lock(&bounce_lock);
+	}
+	mtx_unlock(&bounce_lock);
+}

==== //depot/projects/linuxolator/src/sys/arm/arm/vm_machdep.c#4 (text+ko) ====

@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/arm/arm/vm_machdep.c,v 1.29 2006/11/07 22:35:30 cognet Exp $");
+__FBSDID("$FreeBSD: src/sys/arm/arm/vm_machdep.c,v 1.30 2007/01/17 00:53:05 cognet Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -70,6 +70,8 @@
 #include <vm/uma.h>
 #include <vm/uma_int.h>
 
+#include <machine/md_var.h>
+
 #ifndef NSFBUFS
 #define NSFBUFS		(512 + maxusers * 16)
 #endif
@@ -371,6 +373,9 @@
 void  
 swi_vm(void *dummy)
 {
+	
+	if (busdma_swi_pending)
+		busdma_swi();
 }
 
 void

==== //depot/projects/linuxolator/src/sys/arm/include/bus_dma.h#2 (text+ko) ====

@@ -67,7 +67,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list