Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 13 Jan 2008 14:58:21 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 133192 for review
Message-ID:  <200801131458.m0DEwLim022888@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=133192

Change 133192 by hselasky@hselasky_laptop001 on 2008/01/13 14:58:20

	
	Important patch. Sometimes the BUS-DMA framework
	will not report all segments, even if the virtual
	memory we load is crossing a segment! Because BUS-DMA
	starts counting "maxsegsz" from the "aligned" memory
	location, and when align=1 byte we are in for trouble.
	
	I'm not sure sure if this is a bug in BUS-DMA.
	
	Solution: Manually extend the last segment.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#86 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/usb_subr.c#86 (text+ko) ====

@@ -2269,6 +2269,7 @@
 	struct usbd_page *pg;
 	uint32_t rem;
 	uint8_t owned;
+	uint8_t ext_seg;		/* extend last segment */
 
 	pc = arg;
 	xfer = pc->xfer;
@@ -2297,6 +2298,12 @@
 	rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
 	pc->page_offset_buf = rem;
 	pc->page_offset_end += rem;
+	if (nseg < ((pc->page_offset_end +
+	    (USB_PAGE_SIZE - 1)) / USB_PAGE_SIZE)) {
+		ext_seg = 1;
+	} else {
+		ext_seg = 0;
+	}
 	nseg--;
 
 	while (nseg > 0) {
@@ -2306,6 +2313,14 @@
 		pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
 	}
 
+	/*
+	 * XXX The segments we get from BUS-DMA are not aligned,
+	 * XXX so we need to extend the last segment if we are
+	 * XXX unaligned and cross the segment boundary!
+	 */
+	if (ext_seg) {
+		(pg + 1)->physaddr = pg->physaddr + USB_PAGE_SIZE;
+	}
 	if (xfer) {
 		owned = mtx_owned(xfer->priv_mtx);
 		if (!owned)
@@ -2572,6 +2587,7 @@
 	struct usbd_page *pg;
 	uint32_t rem;
 	uint8_t owned;
+	uint8_t ext_seg;		/* extend last segment */
 
 	xfer = pc->xfer;
 
@@ -2599,6 +2615,12 @@
 	rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
 	pc->page_offset_buf = rem;
 	pc->page_offset_end += rem;
+	if (nseg < ((pc->page_offset_end +
+	    (USB_PAGE_SIZE - 1)) / USB_PAGE_SIZE)) {
+		ext_seg = 1;
+	} else {
+		ext_seg = 0;
+	}
 	nseg--;
 
 	while (nseg > 0) {
@@ -2608,6 +2630,14 @@
 		pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
 	}
 
+	/*
+	 * XXX The segments we get from BUS-DMA are not aligned,
+	 * XXX so we need to extend the last segment if we are
+	 * XXX unaligned and cross the segment boundary!
+	 */
+	if (ext_seg) {
+		(pg + 1)->physaddr = pg->physaddr + USB_PAGE_SIZE;
+	}
 	if (xfer) {
 		owned = mtx_owned(xfer->priv_mtx);
 		if (!owned)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801131458.m0DEwLim022888>