Module Name:    src
Committed By:   bouyer
Date:           Mon Mar 22 22:03:30 UTC 2010

Modified Files:
        src/sys/arch/x86/x86: bus_dma.c
        src/sys/arch/xen/x86: xen_bus_dma.c

Log Message:
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.53 -r1.54 src/sys/arch/x86/x86/bus_dma.c
cvs rdiff -u -r1.20 -r1.21 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.53 src/sys/arch/x86/x86/bus_dma.c:1.54
--- src/sys/arch/x86/x86/bus_dma.c:1.53	Fri Feb 26 19:25:07 2010
+++ src/sys/arch/x86/x86/bus_dma.c	Mon Mar 22 22:03:30 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: bus_dma.c,v 1.53 2010/02/26 19:25:07 jym Exp $	*/
+/*	$NetBSD: bus_dma.c,v 1.54 2010/03/22 22:03:30 bouyer 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.53 2010/02/26 19:25:07 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.54 2010/03/22 22:03:30 bouyer 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.20 src/sys/arch/xen/x86/xen_bus_dma.c:1.21
--- src/sys/arch/xen/x86/xen_bus_dma.c:1.20	Tue Mar  9 23:12:06 2010
+++ src/sys/arch/xen/x86/xen_bus_dma.c	Mon Mar 22 22:03:30 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: xen_bus_dma.c,v 1.20 2010/03/09 23:12:06 jym Exp $	*/
+/*	$NetBSD: xen_bus_dma.c,v 1.21 2010/03/22 22:03:30 bouyer 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.20 2010/03/09 23:12:06 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xen_bus_dma.c,v 1.21 2010/03/22 22:03:30 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -60,7 +60,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;
@@ -72,9 +72,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);
@@ -206,21 +206,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);
@@ -244,14 +255,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;
 		}
@@ -293,7 +308,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