NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: port-amd64/42980: satalink DMA fails under amd64
On Fri, Mar 19, 2010 at 04:41:16PM +0100, Manuel Bouyer wrote:
> On Fri, Mar 19, 2010 at 09:47:39AM -0400, Julian Bourne wrote:
> > I applied the patch to 5.0.2 (hope that was right - it
> > applied cleanly) and rebuilt my xen dom0 target.
> >
> > It hit a __kern_assert() in uvm_pglistalloc():403
> > called from xen_bus_dmamem_alloc_range():
> >
> > (boundary & (boundary - 1) == 0) failed
>
> that's strange, because in xen_bus_dmamem_alloc_range() this could be either
> boundary (and this check is already done in xen_bus_dmamem_alloc_range())
> or size (which is rounded to PAGE_SIZE). Could you print the
> values for boundary and size here ?
ignore this, rounding up to PAGE_SIZE is not enough to make it a power of 2.
The attached patch should be correct (at last I hope so, it's becoming more
complex than I'd like ...)
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: x86/x86/bus_dma.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/bus_dma.c,v
retrieving revision 1.45
diff -u -p -u -r1.45 bus_dma.c
--- x86/x86/bus_dma.c 28 Jun 2008 17:23:01 -0000 1.45
+++ x86/x86/bus_dma.c 19 Mar 2010 16:05:28 -0000
@@ -155,14 +155,28 @@ _bus_dmamem_alloc_range(bus_dma_tag_t t,
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 @@ _bus_dmamem_alloc_range(bus_dma_tag_t t,
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: xen/x86/xen_bus_dma.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/x86/xen_bus_dma.c,v
retrieving revision 1.11.8.1
diff -u -p -u -r1.11.8.1 xen_bus_dma.c
--- xen/x86/xen_bus_dma.c 30 Jan 2010 19:14:20 -0000 1.11.8.1
+++ xen/x86/xen_bus_dma.c 19 Mar 2010 16:05:28 -0000
@@ -61,7 +61,7 @@ static inline int get_order(unsigned lon
}
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 @@ _xen_alloc_contig(bus_size_t size, bus_s
/*
* 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);
@@ -244,21 +244,32 @@ _xen_bus_dmamem_alloc_range(bus_dma_tag_
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);
@@ -282,14 +293,18 @@ again:
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;
}
@@ -343,7 +358,7 @@ dorealloc:
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