svn commit: r244535 - head/sys/dev/usb

Hans Petter Selasky hselasky at FreeBSD.org
Fri Dec 21 14:17:40 UTC 2012


Author: hselasky
Date: Fri Dec 21 14:17:39 2012
New Revision: 244535
URL: http://svnweb.freebsd.org/changeset/base/244535

Log:
  Regression issue:
  Use a boundary of zero, hence a PAGE_SIZE boundary
  is implied by all memory allocations.
  
  Background:
  Busdma has problems to allocate more than PAGE_SIZE
  bytes when the boundary is PAGE_SIZE bytes too.
  Initially it was thought that a boundary of PAGE_SIZE
  bytes will only affect loading of DMA memory, so that
  segments get split correctly, but it also affects
  allocation of DMA'able memory.
  
  Solution:
  USB can detect big segments and split them as required
  by the USB code.
  
  MFC after:	1 week
  Reported by:	gonzo

Modified:
  head/sys/dev/usb/usb_busdma.c

Modified: head/sys/dev/usb/usb_busdma.c
==============================================================================
--- head/sys/dev/usb/usb_busdma.c	Fri Dec 21 13:14:12 2012	(r244534)
+++ head/sys/dev/usb/usb_busdma.c	Fri Dec 21 14:17:39 2012	(r244535)
@@ -358,8 +358,7 @@ usb_dma_tag_create(struct usb_dma_tag *u
 	if (bus_dma_tag_create
 	    ( /* parent    */ udt->tag_parent->tag,
 	     /* alignment */ align,
-	     /* boundary  */ (align == 1) ?
-	    USB_PAGE_SIZE : 0,
+	     /* boundary  */ 0,
 	     /* lowaddr   */ (2ULL << (udt->tag_parent->dma_bits - 1)) - 1,
 	     /* highaddr  */ BUS_SPACE_MAXADDR,
 	     /* filter    */ NULL,
@@ -418,6 +417,7 @@ usb_pc_common_mem_cb(void *arg, bus_dma_
 	struct usb_page_cache *pc;
 	struct usb_page *pg;
 	usb_size_t rem;
+	bus_size_t off;
 	uint8_t owned;
 
 	pc = arg;
@@ -433,6 +433,8 @@ usb_pc_common_mem_cb(void *arg, bus_dma_
 	if (error) {
 		goto done;
 	}
+
+	off = 0;
 	pg = pc->page_start;
 	pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
 	rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
@@ -450,10 +452,16 @@ usb_pc_common_mem_cb(void *arg, bus_dma_
 	}
 #endif
 	while (nseg > 0) {
-		nseg--;
-		segs++;
+		off += USB_PAGE_SIZE;
+		if (off >= (segs->ds_len + rem)) {
+			/* page crossing */
+			nseg--;
+			segs++;
+			off = 0;
+			rem = 0;
+		}
 		pg++;
-		pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
+		pg->physaddr = (segs->ds_addr + off) & ~(USB_PAGE_SIZE - 1);
 	}
 
 done:


More information about the svn-src-head mailing list