Module Name:    src
Committed By:   riz
Date:           Fri Nov 19 23:19:13 UTC 2010

Modified Files:
        src/sys/arch/x86/x86 [netbsd-5]: bus_dma.c
        src/sys/arch/xen/x86 [netbsd-5]: xen_bus_dma.c

Log Message:
Pull up following revision(s) (requested by bouyer in ticket #1348):
        sys/arch/x86/x86/bus_dma.c: revision 1.54
        sys/arch/xen/x86/xen_bus_dma.c: revision 1.21
bus_dmamem_alloc() may not get a boundary smaller than size, but
it's perfectly valid for bus_dmamap_create() to do so (a contigous
transfers will then split in multiple segment).
Fix _xen_bus_dmamem_alloc_range() and _bus_dmamem_alloc_range() to
allow a boundary limit smaller than size:
- compute appropriate boundary for uvm_pglistalloc(), wich doesn't
  accept boundary < size
- also take care of boundary when deciding to start a new segment.
While there, remove useless boundary argument to _xen_alloc_contig().
Fix the boundary-related issue of PR port-amd64/42980


To generate a diff of this commit:
cvs rdiff -u -r1.45 -r1.45.6.1 src/sys/arch/x86/x86/bus_dma.c
cvs rdiff -u -r1.11.8.2 -r1.11.8.3 src/sys/arch/xen/x86/xen_bus_dma.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/bus_dma.c
diff -u src/sys/arch/x86/x86/bus_dma.c:1.45 src/sys/arch/x86/x86/bus_dma.c:1.45.6.1
--- src/sys/arch/x86/x86/bus_dma.c:1.45	Sat Jun 28 17:23:01 2008
+++ src/sys/arch/x86/x86/bus_dma.c	Fri Nov 19 23:19:12 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_dma.c,v 1.45 2008/06/28 17:23:01 bouyer Exp $	*/
+/*	$NetBSD: bus_dma.c,v 1.45.6.1 2010/11/19 23:19:12 riz Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2007 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.45 2008/06/28 17:23:01 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.45.6.1 2010/11/19 23:19:12 riz Exp $");
 
 /*
  * The following is included because _bus_dma_uiomove is derived from
@@ -155,14 +155,28 @@
 	struct vm_page *m;
 	struct pglist mlist;
 	int curseg, error;
+	bus_size_t uboundary;
 
 	/* Always round the size. */
 	size = round_page(size);
 
+	KASSERT(boundary >= PAGE_SIZE || boundary == 0);
+
 	/*
 	 * Allocate pages from the VM system.
-	 */
-	error = uvm_pglistalloc(size, low, high, alignment, boundary,
+	 * We accept boundaries < size, splitting in multiple segments
+	 * if needed. uvm_pglistalloc does not, so compute an appropriate
+         * boundary: next power of 2 >= size
+         */
+
+	if (boundary == 0)
+		uboundary = 0;
+	else {
+		uboundary = boundary;
+		while (uboundary < size)
+			uboundary = uboundary << 1;
+	}
+	error = uvm_pglistalloc(size, low, high, alignment, uboundary,
 	    &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
 	if (error)
 		return (error);
@@ -186,10 +200,13 @@
 			panic("_bus_dmamem_alloc_range");
 		}
 #endif
-		if (curaddr == (lastaddr + PAGE_SIZE))
+		if (curaddr == (lastaddr + PAGE_SIZE) &&
+		    (lastaddr & boundary) == (curaddr & boundary)) {
 			segs[curseg].ds_len += PAGE_SIZE;
-		else {
+		} else {
 			curseg++;
+			if (curseg >= nsegs)
+				return EFBIG;
 			segs[curseg].ds_addr = curaddr;
 			segs[curseg].ds_len = PAGE_SIZE;
 		}

Index: src/sys/arch/xen/x86/xen_bus_dma.c
diff -u src/sys/arch/xen/x86/xen_bus_dma.c:1.11.8.2 src/sys/arch/xen/x86/xen_bus_dma.c:1.11.8.3
--- src/sys/arch/xen/x86/xen_bus_dma.c:1.11.8.2	Mon Mar 29 00:23:12 2010
+++ src/sys/arch/xen/x86/xen_bus_dma.c	Fri Nov 19 23:19:12 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: xen_bus_dma.c,v 1.11.8.2 2010/03/29 00:23:12 snj Exp $	*/
+/*	$NetBSD: xen_bus_dma.c,v 1.11.8.3 2010/11/19 23:19:12 riz Exp $	*/
 /*	NetBSD bus_dma.c,v 1.21 2005/04/16 07:53:35 yamt Exp */
 
 /*-
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xen_bus_dma.c,v 1.11.8.2 2010/03/29 00:23:12 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xen_bus_dma.c,v 1.11.8.3 2010/11/19 23:19:12 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -61,7 +61,7 @@
 }
 
 static int
-_xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary,
+_xen_alloc_contig(bus_size_t size, bus_size_t alignment,
     struct pglist *mlistp, int flags, bus_addr_t low, bus_addr_t high)
 {
 	int order, i;
@@ -75,9 +75,9 @@
 
 	/*
 	 * When requesting a contigous memory region, the hypervisor will
-	 * return a memory range aligned on size. This will automagically
-	 * handle "boundary", but the only way to enforce alignment
-	 * is to request a memory region of size max(alignment, size).
+	 * return a memory range aligned on size. 
+	 * The only way to enforce alignment is to request a memory region
+	 * of size max(alignment, size).
 	 */
 	order = max(get_order(size), get_order(alignment));
 	npages = (1 << order);
@@ -245,21 +245,32 @@
 	struct pglist mlist;
 	int curseg, error;
 	int doingrealloc = 0;
+	bus_size_t uboundary;
 
 	/* Always round the size. */
 	size = round_page(size);
 
 	KASSERT((alignment & (alignment - 1)) == 0);
 	KASSERT((boundary & (boundary - 1)) == 0);
+	KASSERT(boundary >= PAGE_SIZE || boundary == 0);
+		    
 	if (alignment < PAGE_SIZE)
 		alignment = PAGE_SIZE;
-	if (boundary != 0 && boundary < size)
-		return (EINVAL);
 
 	/*
 	 * Allocate pages from the VM system.
+	 * We accept boundaries < size, splitting in multiple segments
+	 * if needed. uvm_pglistalloc does not, so compute an appropriate
+	 * boundary: next power of 2 >= size
 	 */
-	error = uvm_pglistalloc(size, 0, avail_end, alignment, boundary,
+	if (boundary == 0)
+		uboundary = 0;
+	else {
+		uboundary = boundary;
+		while (uboundary < size)
+			uboundary = uboundary << 1;
+	}
+	error = uvm_pglistalloc(size, 0, avail_end, alignment, uboundary,
 	    &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
 	if (error)
 		return (error);
@@ -283,14 +294,18 @@
 		curaddr = _BUS_VM_PAGE_TO_BUS(m);
 		if (curaddr < low || curaddr >= high)
 			goto badaddr;
-		if (curaddr == (lastaddr + PAGE_SIZE)) {
+		if (curaddr == (lastaddr + PAGE_SIZE) &&
+		    (lastaddr & boundary) == (curaddr & boundary)) {
 			segs[curseg].ds_len += PAGE_SIZE;
-			if ((lastaddr & boundary) != (curaddr & boundary))
-				goto dorealloc;
 		} else {
 			curseg++;
-			if (curseg >= nsegs || (curaddr & (alignment - 1)) != 0)
-				goto dorealloc;
+			if (curseg >= nsegs ||
+			    (curaddr & (alignment - 1)) != 0) {
+				if (doingrealloc)
+					return EFBIG;
+				else
+					goto dorealloc;
+			}
 			segs[curseg].ds_addr = curaddr;
 			segs[curseg].ds_len = PAGE_SIZE;
 		}
@@ -344,7 +359,7 @@
 		segs[curseg].ds_len = 0;
 	}
 	error = _xen_alloc_contig(size, alignment,
-	    boundary, &mlist, flags, low, high);
+	    &mlist, flags, low, high);
 	if (error)
 		return error;
 	goto again;

Reply via email to