PERFORCE change 129954 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sat Dec 1 18:27:24 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=129954

Change 129954 by hselasky at hselasky_laptop001 on 2007/12/02 02:26:59

	
	Bugfixes:
	
	1) The "usbd_get_page()" function should only be used after
	that a virtual buffer has been loaded into DMA.
	
	2) Recursive locking in BUS-DMA callback.

Affected files ...

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

Differences ...

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

@@ -1776,6 +1776,9 @@
 
 /*------------------------------------------------------------------------*
  *  usbd_get_page - lookup DMA-able memory for the given offset
+ *
+ * NOTE: Only call this function when the "page_cache" structure has
+ * been properly initialized !
  *------------------------------------------------------------------------*/
 void
 usbd_get_page(struct usbd_page_cache *pc, uint32_t offset,
@@ -1787,6 +1790,8 @@
 
 	offset += pc->page_offset_buf;
 
+	/* range check */
+
 	if ((offset >= pc->page_offset_end) ||
 	    (offset < pc->page_offset_buf)) {
 
@@ -1801,22 +1806,13 @@
 
 	page = pc->page_start;
 
-	if (page) {
+	page += (offset / USB_PAGE_SIZE);
 
-		page += (offset / USB_PAGE_SIZE);
+	offset %= USB_PAGE_SIZE;
 
-		offset %= USB_PAGE_SIZE;
+	res->length = USB_PAGE_SIZE - offset;
+	res->physaddr = page->physaddr + offset;
 
-		res->length = USB_PAGE_SIZE - offset;
-		res->physaddr = page->physaddr + offset;
-
-	} else {
-
-		offset %= USB_PAGE_SIZE;
-
-		res->length = USB_PAGE_SIZE - offset;
-		res->physaddr = 0;
-	}
 	return;
 }
 
@@ -1827,25 +1823,10 @@
 usbd_copy_in(struct usbd_page_cache *cache, uint32_t offset,
     const void *ptr, uint32_t len)
 {
-	struct usbd_page_search res;
+	void *dst;
 
-	while (len) {
-
-		usbd_get_page(cache, offset, &res);
-
-		if (res.length == 0) {
-			panic("%s:%d invalid offset!\n",
-			    __FUNCTION__, __LINE__);
-		}
-		if (res.length > len) {
-			res.length = len;
-		}
-		bcopy(ptr, res.buffer, res.length);
-
-		offset += res.length;
-		len -= res.length;
-		ptr = USBD_ADD_BYTES(ptr, res.length);
-	}
+	dst = USBD_ADD_BYTES(cache->buffer, offset);
+	bcopy(ptr, dst, len);
 	return;
 }
 
@@ -1889,33 +1870,10 @@
 usbd_uiomove(struct usbd_page_cache *pc, struct uio *uio,
     uint32_t pc_offset, uint32_t len)
 {
-	struct usbd_page_search res;
-	int error = 0;
+	void *ptr;
 
-	while (len > 0) {
-
-		usbd_get_page(pc, pc_offset, &res);
-
-		if (res.length == 0) {
-			panic("%s:%d invalid offset!\n",
-			    __FUNCTION__, __LINE__);
-		}
-		if (res.length > len) {
-			res.length = len;
-		}
-		/*
-		 * "uiomove()" can sleep so one needs to make a wrapper,
-		 * exiting the mutex and checking things
-		 */
-		error = uiomove(res.buffer, len, uio);
-
-		if (error) {
-			break;
-		}
-		pc_offset += res.length;
-		len -= res.length;
-	}
-	return (error);
+	ptr = USBD_ADD_BYTES(pc->buffer, pc_offset);
+	return (uiomove(ptr, len, uio));
 }
 
 /*------------------------------------------------------------------------*
@@ -1925,25 +1883,10 @@
 usbd_copy_out(struct usbd_page_cache *cache, uint32_t offset,
     void *ptr, uint32_t len)
 {
-	struct usbd_page_search res;
+	void *src;
 
-	while (len) {
-
-		usbd_get_page(cache, offset, &res);
-
-		if (res.length == 0) {
-			panic("%s:%d invalid offset!\n",
-			    __FUNCTION__, __LINE__);
-		}
-		if (res.length > len) {
-			res.length = len;
-		}
-		bcopy(res.buffer, ptr, res.length);
-
-		offset += res.length;
-		len -= res.length;
-		ptr = USBD_ADD_BYTES(ptr, res.length);
-	}
+	src = USBD_ADD_BYTES(cache->buffer, offset);
+	bcopy(src, ptr, len);
 	return;
 }
 
@@ -1953,24 +1896,10 @@
 void
 usbd_bzero(struct usbd_page_cache *cache, uint32_t offset, uint32_t len)
 {
-	struct usbd_page_search res;
+	void *ptr;
 
-	while (len) {
-
-		usbd_get_page(cache, offset, &res);
-
-		if (res.length == 0) {
-			panic("%s:%d invalid offset!\n",
-			    __FUNCTION__, __LINE__);
-		}
-		if (res.length > len) {
-			res.length = len;
-		}
-		bzero(res.buffer, res.length);
-
-		offset += res.length;
-		len -= res.length;
-	}
+	ptr = USBD_ADD_BYTES(cache->buffer, offset);
+	bzero(ptr, len);
 	return;
 }
 
@@ -2029,21 +1958,30 @@
 	struct usbd_page_cache *pc;
 	struct usbd_page *pg;
 	uint32_t rem;
+	uint8_t owned;
 
+	pc = arg;
 	xfer = pc->xfer;
 
-	/* XXX sometimes recursive locking here */
+	/*
+	 * XXX There is sometimes recursive locking here.
+	 * XXX We should try to find a better solution.
+	 * XXX Until further the "owned" variable does
+	 * XXX the trick.
+	 */
 
 	if (error) {
 		if (xfer) {
-			mtx_lock(xfer->priv_mtx);
+			owned = mtx_owned(xfer->priv_mtx);
+			if (!owned)
+				mtx_lock(xfer->priv_mtx);
 			xfer->usb_root->dma_error = 1;
 			usbd_bdma_done_event(xfer->usb_root);
-			mtx_unlock(xfer->priv_mtx);
+			if (!owned)
+				mtx_unlock(xfer->priv_mtx);
 		}
 		return;
 	}
-	pc = arg;
 	pg = pc->page_start;
 	pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1);
 	rem = segs->ds_addr & (USB_PAGE_SIZE - 1);
@@ -2059,9 +1997,12 @@
 	}
 
 	if (xfer) {
-		mtx_lock(xfer->priv_mtx);
+		owned = mtx_owned(xfer->priv_mtx);
+		if (!owned)
+			mtx_lock(xfer->priv_mtx);
 		usbd_bdma_done_event(xfer->usb_root);
-		mtx_unlock(xfer->priv_mtx);
+		if (!owned)
+			mtx_unlock(xfer->priv_mtx);
 	}
 	return;
 }


More information about the p4-projects mailing list