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