Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 29 Dec 2012 00:21:02 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r244803 - in projects/physbio/sys: arm/arm ia64/ia64 kern mips/mips powerpc/powerpc sparc64/include sparc64/sparc64 sys x86/x86
Message-ID:  <201212290021.qBT0L25j034158@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Sat Dec 29 00:21:02 2012
New Revision: 244803
URL: http://svnweb.freebsd.org/changeset/base/244803

Log:
   - Don't use an anonymous union in bus_dma_memory_t.  Older versions of gcc
     don't support it.
   - Restructure the busdma implementations to support loading physical
     addresses.  This does not yet support bouncing.  It does enforce
     boundaries, maximum segment sizes, and segment counts.  Bouncing will
     come next.
  
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  projects/physbio/sys/arm/arm/busdma_machdep-v6.c
  projects/physbio/sys/arm/arm/busdma_machdep.c
  projects/physbio/sys/ia64/ia64/busdma_machdep.c
  projects/physbio/sys/kern/subr_busdma.c
  projects/physbio/sys/mips/mips/busdma_machdep.c
  projects/physbio/sys/powerpc/powerpc/busdma_machdep.c
  projects/physbio/sys/sparc64/include/bus_dma.h
  projects/physbio/sys/sparc64/sparc64/bus_machdep.c
  projects/physbio/sys/sparc64/sparc64/iommu.c
  projects/physbio/sys/sys/bus_dma.h
  projects/physbio/sys/x86/x86/busdma_machdep.c

Modified: projects/physbio/sys/arm/arm/busdma_machdep-v6.c
==============================================================================
--- projects/physbio/sys/arm/arm/busdma_machdep-v6.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/arm/arm/busdma_machdep-v6.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -706,6 +706,107 @@ _bus_dmamap_count_pages(bus_dma_tag_t dm
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+		   bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->boundary - 1);
+	if (dmat->boundary > 0) {
+		baddr = (curaddr + dmat->boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+
+	if (dmat->ranges) {
+		struct arm32_dma_range *dr;
+
+		dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
+		    curaddr);
+		if (dr == NULL) {
+			_bus_dmamap_unload(dmat, map);
+			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
+	 * previous segment if possible.
+	 */
+	seg = *segp;
+	if (seg == -1) {
+		seg = 0;
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	} else {
+		if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+		    (dmat->boundary == 0 ||
+		     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
+			segs[seg].ds_len += sgsize;
+		else {
+			if (++seg >= dmat->nsegments)
+				return (0);
+			segs[seg].ds_addr = curaddr;
+			segs[seg].ds_len = sgsize;
+		}
+	}
+	*segp = seg;
+	return (sgsize);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat,
+		      bus_dmamap_t map,
+		      vm_paddr_t buf, bus_size_t buflen,
+		      int flags,
+		      bus_dma_segment_t *segs,
+		      int *segp)
+{
+	bus_addr_t curaddr;
+	bus_size_t sgsize;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	curaddr = buf;
+	while (buflen > 0) {
+		sgsize = MIN(buflen, dmat->maxsegsz);
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		curaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	if (buflen != 0) {
+		_bus_dmamap_unload(dmat, map);
+		return (EFBIG); /* XXX better return value here? */
+	}
+	return (0);
+}
+
+/*
  * Utility function to load a linear buffer.  segp contains
  * the starting segment on entrace, and the ending segment on exit.
  */
@@ -719,10 +820,10 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			int *segp)
 {
 	bus_size_t sgsize;
-	bus_addr_t curaddr, baddr, bmask;
+	bus_addr_t curaddr;
 	vm_offset_t vaddr;
 	struct sync_list *sl;
-	int seg, error;
+	int error;
 
 	if (segs == NULL)
 		segs = dmat->segments;
@@ -735,10 +836,9 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 
 	sl = NULL;
 	vaddr = (vm_offset_t)buf;
-	bmask = ~(dmat->boundary - 1);
 	map->pmap = pmap;
 
-	for (seg = *segp; buflen > 0 ; ) {
+	while (buflen > 0) {
 		/*
 		 * Get the physical address for this segment.
 		 */
@@ -756,15 +856,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 		if (buflen < sgsize)
 			sgsize = buflen;
 
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			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);
@@ -781,57 +872,21 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			} else
 				sl->datacount += sgsize;
 		}
-
-		if (dmat->ranges) {
-			struct arm32_dma_range *dr;
-
-			dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
-			    curaddr);
-			if (dr == NULL) {
-				_bus_dmamap_unload(dmat, map);
-				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
-		 * previous segment if possible.
-		 */
-		if (seg == -1) {
-			seg = 0;
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-		} else {
-			if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
-			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-			    (dmat->boundary == 0 ||
-			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
-				segs[seg].ds_len += sgsize;
-			else {
-				if (++seg >= dmat->nsegments)
-					break;
-				segs[seg].ds_addr = curaddr;
-				segs[seg].ds_len = sgsize;
-			}
-		}
-
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+					    segp);
+		if (sgsize == 0)
+			break;
 		vaddr += sgsize;
 		buflen -= sgsize;
 	}
 
-	*segp = seg;
 cleanup:
 	/*
 	 * Did we fit?
 	 */
 	if (buflen != 0) {
 		_bus_dmamap_unload(dmat, map);
-		return(EFBIG); /* XXX better return value here? */
+		return (EFBIG); /* XXX better return value here? */
 	}
 	return (0);
 }

Modified: projects/physbio/sys/arm/arm/busdma_machdep.c
==============================================================================
--- projects/physbio/sys/arm/arm/busdma_machdep.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/arm/arm/busdma_machdep.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -752,6 +752,95 @@ _bus_dmamap_count_pages(bus_dma_tag_t dm
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->boundary - 1);
+	if (dmat->boundary > 0) {
+		baddr = (curaddr + dmat->boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+	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;
+					
+	}
+
+	seg = *segp;
+	/*
+	 * Insert chunk into a segment, coalescing with
+	 * the previous segment if possible.
+	 */
+	if (seg >= 0 &&
+	    curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+	    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+	    (dmat->boundary == 0 ||
+	     (segs[seg].ds_addr & bmask) == (curaddr & bmask))) {
+		segs[seg].ds_len += sgsize;
+	} else {
+		if (++seg >= dmat->nsegments)
+			return (EFBIG);
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	}
+	*segp = seg;
+	return (0);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
+    bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
+{
+	bus_size_t sgsize;
+	bus_addr_t curaddr;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	curaddr = buf;
+	while (buflen > 0) {
+		sgsize = MIN(buflen, dmat->maxsegsz);
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		curaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	if (buflen != 0) {
+		_bus_dmamap_unload(dmat, map);
+		return (EFBIG); /* XXX better return value here? */
+	}
+	return (0);
+}
+/*
  * Utility function to load a linear buffer.  segp contains
  * the starting segment on entrance, and the ending segment on exit.
  */
@@ -761,17 +850,14 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
     int *segp)
 {
 	bus_size_t sgsize;
-	bus_addr_t curaddr, baddr, bmask;
+	bus_addr_t curaddr;
 	struct sync_list *sl;
 	vm_offset_t vaddr = (vm_offset_t)buf;
-	int seg;
 	int error = 0;
 	pd_entry_t *pde;
 	pt_entry_t pte;
 	pt_entry_t *ptep;
 
-	bmask = ~(dmat->boundary - 1);
-
 	if (segs == NULL)
 		segs = dmat->segments;
 
@@ -784,7 +870,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 	CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, "
 	    "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment);
 
-	for (seg = *segp; buflen > 0 ; ) {
+	while (buflen > 0) {
 		/*
 		 * Get the physical address for this segment.
 		 *
@@ -842,14 +928,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 		if (buflen < sgsize)
 			sgsize = buflen;
 
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			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);
@@ -866,57 +944,23 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			} else
 				sl->datacount += 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 == segs[seg].ds_addr + segs[seg].ds_len &&
-		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-		    (dmat->boundary == 0 ||
-		     (segs[seg].ds_addr & bmask) ==
-		     (curaddr & bmask))) {
-			segs[seg].ds_len += sgsize;
-			goto segdone;
-		} else {
-			if (++seg >= dmat->nsegments)
-				break;
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-		}
-		if (error)
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
 			break;
-segdone:
 		vaddr += sgsize;
 		buflen -= sgsize;
 	}
 
-	*segp = seg;
 cleanup:
 	/*
 	 * Did we fit?
 	 */
 	if (buflen != 0) {
 		_bus_dmamap_unload(dmat, map);
-		error = EFBIG; /* XXX better return value here? */
+		return (EFBIG); /* XXX better return value here? */
 	}
-	return (error);
+	return (0);
 }
 
 void

Modified: projects/physbio/sys/ia64/ia64/busdma_machdep.c
==============================================================================
--- projects/physbio/sys/ia64/ia64/busdma_machdep.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/ia64/ia64/busdma_machdep.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -478,6 +478,86 @@ bus_dmamem_free(bus_dma_tag_t dmat, void
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->boundary - 1);
+	if (dmat->boundary > 0) {
+		baddr = (curaddr + dmat->boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+
+	/*
+	 * Insert chunk into a segment, coalescing with
+	 * previous segment if possible.
+	 */
+	seg = *segp;
+	if (seg == -1) {
+		seg = 0;
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	} else {
+		if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+		    (dmat->boundary == 0 ||
+		    (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
+			segs[seg].ds_len += sgsize;
+		else {
+			if (++seg >= dmat->nsegments)
+				return (0);
+			segs[seg].ds_addr = curaddr;
+			segs[seg].ds_len = sgsize;
+		}
+	}
+	*segp = seg;
+	return (sgsize);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
+    vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	bus_addr_t curaddr;
+	bus_size_t sgsize;
+
+	if (map == NULL)
+		map = &nobounce_dmamap;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	curaddr = buf;
+	while (buflen > 0) {
+		sgsize = MIN(buflen, dmat->maxsegsz);
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		curaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+}
+/*
  * Utility function to load a linear buffer.  segp contains
  * the starting segment on entrace, and the ending segment on exit.
  */
@@ -487,10 +567,9 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
     bus_dma_segment_t *segs, int *segp)
 {
 	bus_size_t sgsize;
-	bus_addr_t curaddr, baddr, bmask;
+	bus_addr_t curaddr;
 	vm_offset_t vaddr;
 	bus_addr_t paddr;
-	int seg;
 
 	if (map == NULL)
 		map = &nobounce_dmamap;
@@ -543,9 +622,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 		mtx_unlock(&bounce_lock);
 	}
 
-	bmask = ~(dmat->boundary - 1);
-
-	for (seg = *segp; buflen > 0 ; ) {
+	while (buflen > 0) {
 		/*
 		 * Get the physical address for this segment.
 		 */
@@ -563,46 +640,18 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 		if (buflen < sgsize)
 			sgsize = buflen;
 
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			if (sgsize > (baddr - curaddr))
-				sgsize = (baddr - curaddr);
-		}
-
 		if (map->pagesneeded != 0 && run_filter(dmat, curaddr, sgsize))
 			curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
 
-		/*
-		 * Insert chunk into a segment, coalescing with
-		 * previous segment if possible.
-		 */
-		if (seg == -1) {
-			seg = 0;
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-		} else {
-			if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
-			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-			    (dmat->boundary == 0 ||
-			    (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
-				segs[seg].ds_len += sgsize;
-			else {
-				if (++seg >= dmat->nsegments)
-					break;
-				segs[seg].ds_addr = curaddr;
-				segs[seg].ds_len = sgsize;
-			}
-		}
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
 
 		vaddr += sgsize;
 		buflen -= sgsize;
 	}
 
-	*segp = seg;
-
 	/*
 	 * Did we fit?
 	 */

Modified: projects/physbio/sys/kern/subr_busdma.c
==============================================================================
--- projects/physbio/sys/kern/subr_busdma.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/kern/subr_busdma.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -394,37 +394,38 @@ bus_dmamap_load_mem(bus_dma_tag_t dmat, 
 		_bus_dmamap_waitok(dmat, map, *mem, callback, callback_arg);
 
 	nsegs = -1;
+	error = 0;
 	switch (mem->dm_type) {
 	case BUS_DMAMEM_VADDR:
-		error = _bus_dmamap_load_buffer(dmat, map, mem->dm_vaddr,
+		error = _bus_dmamap_load_buffer(dmat, map, mem->u.dm_vaddr,
 		    mem->dm_opaque, kernel_pmap, flags, NULL, &nsegs);
 		break;
 	case BUS_DMAMEM_PADDR:
-		error = _bus_dmamap_load_phys(dmat, map, mem->dm_paddr,
+		error = _bus_dmamap_load_phys(dmat, map, mem->u.dm_paddr,
 		    mem->dm_opaque, flags, NULL, &nsegs);
 		break;
 	case BUS_DMAMEM_VLIST:
-		error = _bus_dmamap_load_vlist(dmat, map, mem->dm_list,
+		error = _bus_dmamap_load_vlist(dmat, map, mem->u.dm_list,
 		    mem->dm_opaque, kernel_pmap, &nsegs, flags);
 		break;
 	case BUS_DMAMEM_PLIST:
-		error = _bus_dmamap_load_plist(dmat, map, mem->dm_list,
+		error = _bus_dmamap_load_plist(dmat, map, mem->u.dm_list,
 		    mem->dm_opaque, &nsegs, flags);
 		break;
 	case BUS_DMAMEM_BIO:
-		error = _bus_dmamap_load_bio(dmat, map, mem->dm_bio,
+		error = _bus_dmamap_load_bio(dmat, map, mem->u.dm_bio,
 		    &nsegs, flags);
 		break;
 	case BUS_DMAMEM_UIO:
-		error = _bus_dmamap_load_uio(dmat, map, mem->dm_uio,
+		error = _bus_dmamap_load_uio(dmat, map, mem->u.dm_uio,
 		    /*XXX*/kernel_pmap, &nsegs, flags);
 		break;
 	case BUS_DMAMEM_MBUF:
-		error = _bus_dmamap_load_mbuf_sg(dmat, map, mem->dm_mbuf, NULL,
-		    &nsegs, flags);
+		error = _bus_dmamap_load_mbuf_sg(dmat, map, mem->u.dm_mbuf,
+		    NULL, &nsegs, flags);
 		break;
 	case BUS_DMAMEM_CCB:
-		error = _bus_dmamap_load_ccb(dmat, map, mem->dm_ccb, &nsegs,
+		error = _bus_dmamap_load_ccb(dmat, map, mem->u.dm_ccb, &nsegs,
 		    flags);
 		break;
 	}

Modified: projects/physbio/sys/mips/mips/busdma_machdep.c
==============================================================================
--- projects/physbio/sys/mips/mips/busdma_machdep.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/mips/mips/busdma_machdep.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -750,6 +750,82 @@ _bus_dmamap_count_pages(bus_dma_tag_t dm
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->boundary - 1);
+	if (dmat->boundary > 0) {
+		baddr = (curaddr + dmat->boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+	/*
+	 * Insert chunk into a segment, coalescing with
+	 * the previous segment if possible.
+	 */
+	seg = *segp;
+	if (seg >= 0 &&
+	    curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+	    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+	    (dmat->boundary == 0 ||
+	     (segs[seg].ds_addr & bmask) == (curaddr & bmask))) {
+		segs[seg].ds_len += sgsize;
+	} else {
+		if (++seg >= dmat->nsegments)
+			return (0);
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	}
+	*segp = seg;
+	return (sgsize);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
+    vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
+    int *segp)
+{
+	bus_addr_t curaddr;
+	bus_size_t sgsize;
+
+	if (segs == NULL)
+		segs = dmat->segments;
+
+	curaddr = buf;
+	while (buflen > 0) {
+		sgsize = MIN(buflen, dmat->maxsegsz);
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		curaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	if (buflen != 0) {
+		_bus_dmamap_unload(dmat, map);
+		return (EFBIG); /* XXX better return value here? */
+	}
+	return (0);
+}
+
+/*
  * Utility function to load a linear buffer.  segp contains
  * the starting segment on entrance, and the ending segment on exit.
  * first indicates if this is the first invocation of this function.
@@ -760,13 +836,11 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
     int *segp)
 {
 	bus_size_t sgsize;
-	bus_addr_t curaddr, baddr, bmask;
+	bus_addr_t curaddr;
 	struct sync_list *sl;
 	vm_offset_t vaddr = (vm_offset_t)buf;
-	int seg;
 	int error = 0;
 
-	bmask = ~(dmat->boundary - 1);
 
 	if (segs == NULL)
 		segs = dmat->segments;
@@ -780,7 +854,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 	CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, "
 	    "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment);
 
-	for (seg = *segp; buflen > 0 ; ) {
+	while (buflen > 0) {
 		/*
 		 * Get the physical address for this segment.
 		 *
@@ -799,14 +873,6 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 		if (buflen < sgsize)
 			sgsize = buflen;
 
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			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);
@@ -823,33 +889,14 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			} else
 				sl->datacount += sgsize;
 		}
-
-		/*
-		 * Insert chunk into a segment, coalescing with
-		 * the previous segment if possible.
-		 */
-		if (seg >= 0 &&
-		    curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
-		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-		    (dmat->boundary == 0 ||
-		     (segs[seg].ds_addr & bmask) == 
-		     (curaddr & bmask))) {
-			segs[seg].ds_len += sgsize;
-			goto segdone;
-		} else {
-			if (++seg >= dmat->nsegments)
-				break;
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-		}
-		if (error)
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
 			break;
-segdone:
 		vaddr += sgsize;
 		buflen -= sgsize;
 	}
 
-	*segp = seg;
 cleanup:
 	/*
 	 * Did we fit?

Modified: projects/physbio/sys/powerpc/powerpc/busdma_machdep.c
==============================================================================
--- projects/physbio/sys/powerpc/powerpc/busdma_machdep.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/powerpc/powerpc/busdma_machdep.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -123,8 +123,7 @@ struct bus_dmamap {
 	int		       pagesneeded;
 	int		       pagesreserved;
 	bus_dma_tag_t	       dmat;
-	void		      *buf;		/* unmapped buffer pointer */
-	bus_size_t	       buflen;		/* unmapped buffer length */
+	bus_dma_memory_t       mem;
 	bus_dma_segment_t     *segments;
 	int		       nsegs;
 	bus_dmamap_callback_t *callback;
@@ -563,6 +562,87 @@ bus_dmamem_free(bus_dma_tag_t dmat, void
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+_bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+		   bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+
+	/*
+	 * Make sure we don't cross any boundaries.
+	 */
+	bmask = ~(dmat->boundary - 1);
+	if (dmat->boundary > 0) {
+		baddr = (curaddr + dmat->boundary) & bmask;
+		if (sgsize > (baddr - curaddr))
+			sgsize = (baddr - curaddr);
+	}
+
+	/*
+	 * Insert chunk into a segment, coalescing with
+	 * previous segment if possible.
+	 */
+	seg = *segp;
+	if (seg == -1) {
+		seg = 0;
+		segs[seg].ds_addr = curaddr;
+		segs[seg].ds_len = sgsize;
+	} else {
+		if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
+		    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+		    (dmat->boundary == 0 ||
+		     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
+			segs[seg].ds_len += sgsize;
+		else {
+			if (++seg >= dmat->nsegments)
+				return (0);
+			segs[seg].ds_addr = curaddr;
+			segs[seg].ds_len = sgsize;
+		}
+	}
+	*segp = seg;
+	return (sgsize);
+}
+
+/*
+ * Utility function to load a physical buffer.  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ */
+int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat,
+		      bus_dmamap_t map,
+		      vm_paddr_t buf, bus_size_t buflen,
+		      int flags,
+		      bus_dma_segment_t *segs,
+		      int *segp)
+{
+	bus_addr_t curaddr;
+	bus_size_t sgsize;
+
+	if (segs == NULL)
+		segs = map->segments;
+
+	curaddr = buf;
+	while (buflen > 0) {
+		sgsize = MIN(buflen, dmat->maxsegsz);
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
+		curaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	/*
+	 * Did we fit?
+	 */
+	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+}
+
+/*
  * Utility function to load a linear buffer.  segp contains
  * the starting segment on entrance, and the ending segment on exit.
  */
@@ -576,10 +656,9 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			int *segp)
 {
 	bus_size_t sgsize;
-	bus_addr_t curaddr, baddr, bmask;
+	bus_addr_t curaddr;
 	vm_offset_t vaddr;
 	bus_addr_t paddr;
-	int seg;
 
 	if (segs == NULL)
 		segs = map->segments;
@@ -636,9 +715,8 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 	}
 
 	vaddr = (vm_offset_t)buf;
-	bmask = ~(dmat->boundary - 1);
 
-	for (seg = *segp; buflen > 0 ; ) {
+	while (buflen > 0) {
 		bus_size_t max_sgsize;
 
 		/*
@@ -662,43 +740,14 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 			sgsize = MIN(sgsize, max_sgsize);
 		}
 
-		/*
-		 * Make sure we don't cross any boundaries.
-		 */
-		if (dmat->boundary > 0) {
-			baddr = (curaddr + dmat->boundary) & bmask;
-			if (sgsize > (baddr - curaddr))
-				sgsize = (baddr - curaddr);
-		}
-
-		/*
-		 * Insert chunk into a segment, coalescing with
-		 * previous segment if possible.
-		 */
-		if (seg == -1) {
-			seg = 0;
-			segs[seg].ds_addr = curaddr;
-			segs[seg].ds_len = sgsize;
-		} else {
-			if (curaddr == segs[seg].ds_addr + segs[seg].ds_len &&
-			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
-			    (dmat->boundary == 0 ||
-			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
-				segs[seg].ds_len += sgsize;
-			else {
-				if (++seg >= dmat->nsegments)
-					break;
-				segs[seg].ds_addr = curaddr;
-				segs[seg].ds_len = sgsize;
-			}
-		}
-
+		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+		    segp);
+		if (sgsize == 0)
+			break;
 		vaddr += sgsize;
 		buflen -= sgsize;
 	}
 
-	*segp = seg;
-
 	/*
 	 * Did we fit?
 	 */

Modified: projects/physbio/sys/sparc64/include/bus_dma.h
==============================================================================
--- projects/physbio/sys/sparc64/include/bus_dma.h	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/sparc64/include/bus_dma.h	Sat Dec 29 00:21:02 2012	(r244803)
@@ -78,6 +78,9 @@
 struct bus_dma_methods {
 	int	(*dm_dmamap_create)(bus_dma_tag_t, int, bus_dmamap_t *);
 	int	(*dm_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t);
+	int	(*dm_dmamap_load_phys)(bus_dma_tag_t dmat, bus_dmamap_t map,
+	    vm_paddr_t buf, bus_size_t buflen, int flags,
+	    bus_dma_segment_t *segs, int *segp);
 	int	(*dm_dmamap_load_buffer)(bus_dma_tag_t dmat, bus_dmamap_t map,
 	    void *buf, bus_size_t buflen, struct pmap *pmap, int flags,
 	    bus_dma_segment_t *segs, int *segp);
@@ -124,6 +127,9 @@ struct bus_dma_tag {
 	((t)->dt_mt->dm_dmamap_create((t), (f), (p)))
 #define	bus_dmamap_destroy(t, p)					\
 	((t)->dt_mt->dm_dmamap_destroy((t), (p)))
+#define	_bus_dmamap_load_phys(t, m, b, l, f, s, sp)			\
+	((t)->dt_mt->dm_dmamap_load_buffer((t), (m), (b), (l),		\
+	    (f), (s), (sp)))
 #define	_bus_dmamap_load_buffer(t, m, b, l, p, f, s, sp)		\
 	((t)->dt_mt->dm_dmamap_load_buffer((t), (m), (b), (l), (p),	\
 	    (f), (s), (sp)))

Modified: projects/physbio/sys/sparc64/sparc64/bus_machdep.c
==============================================================================
--- projects/physbio/sys/sparc64/sparc64/bus_machdep.c	Sat Dec 29 00:06:26 2012	(r244802)
+++ projects/physbio/sys/sparc64/sparc64/bus_machdep.c	Sat Dec 29 00:21:02 2012	(r244803)
@@ -324,6 +324,83 @@ nexus_dmamap_destroy(bus_dma_tag_t dmat,
 }
 
 /*
+ * Add a single contiguous physical range to the segment list.
+ */
+static int
+nexus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr,
+    bus_size_t sgsize, bus_dma_segment_t *segs, int *segp)
+{
+	bus_addr_t baddr, bmask;
+	int seg;
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212290021.qBT0L25j034158>