Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch bus_dmamem_alloc() may not get a boundary smaller t...



details:   https://anonhg.NetBSD.org/src/rev/cc041b82d8e7
branches:  trunk
changeset: 753317:cc041b82d8e7
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Mon Mar 22 22:03:30 2010 +0000

description:
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

diffstat:

 sys/arch/x86/x86/bus_dma.c     |  29 +++++++++++++++++++++-----
 sys/arch/xen/x86/xen_bus_dma.c |  45 ++++++++++++++++++++++++++++--------------
 2 files changed, 53 insertions(+), 21 deletions(-)

diffs (174 lines):

diff -r ff3c1fe42d7b -r cc041b82d8e7 sys/arch/x86/x86/bus_dma.c
--- a/sys/arch/x86/x86/bus_dma.c        Mon Mar 22 22:00:37 2010 +0000
+++ b/sys/arch/x86/x86/bus_dma.c        Mon Mar 22 22:03:30 2010 +0000
@@ -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;
                }
diff -r ff3c1fe42d7b -r cc041b82d8e7 sys/arch/xen/x86/xen_bus_dma.c
--- a/sys/arch/xen/x86/xen_bus_dma.c    Mon Mar 22 22:00:37 2010 +0000
+++ b/sys/arch/xen/x86/xen_bus_dma.c    Mon Mar 22 22:03:30 2010 +0000
@@ -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;



Home | Main Index | Thread Index | Old Index