PERFORCE change 130895 for review

Hans Petter Selasky hselasky at FreeBSD.org
Fri Dec 14 14:14:52 PST 2007


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

Change 130895 by hselasky at hselasky_laptop001 on 2007/12/14 22:13:56

	
	This commit is device side related, but also affects the host side.
	
	Create one interrupt thread per "struct usbd_memory_info" that
	will handle USB callbacks outside the main interrupt thread. This
	should also increase parallellism.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#74 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#69 edit

Differences ...

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

@@ -68,6 +68,7 @@
 m(USBD_DMA_LOAD_FAILED,)\
 m(USBD_BAD_CONTEXT,)\
 m(USBD_NO_ROOT_HUB,)\
+m(USBD_NO_INTR_THREAD,)\
 					/**/
 
 MAKE_ENUM(USBD_STATUS,
@@ -565,7 +566,10 @@
 
 struct usbd_memory_info {
 	LIST_HEAD(, usbd_xfer) dma_head;
+	LIST_HEAD(, usbd_xfer) done_head;
+	struct mtx done_mtx;		/* mutex protecting "done_head" */
 
+	void   *done_cookie;		/* software interrupt thread cookie */
 	void   *memory_base;
 	struct mtx *priv_mtx;
 	struct mtx *usb_mtx;

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

@@ -43,6 +43,8 @@
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
 
 #include <dev/usb/usb_port.h>
 #include <dev/usb/usb.h>
@@ -61,6 +63,8 @@
 static void usbd_bdma_cancel_event(struct usbd_xfer *xfer);
 static void usbd_callback_wrapper(struct usbd_xfer *xfer, uint8_t context);
 static usbd_status_t usbd_handle_request(struct usbd_xfer *xfer);
+static driver_intr_t usbd_callback_intr_td;
+static void usbd_transfer_unsetup_sub(struct usbd_memory_info *info);
 
 #ifdef USB_DEBUG
 void
@@ -763,8 +767,10 @@
 	struct usbd_xfer *xfer;
 	void *buf = NULL;
 	uint16_t n;
+	uint16_t refcount;
 
 	parm.err = 0;
+	refcount = 0;
 
 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
 	    "usbd_transfer_setup can sleep!");
@@ -827,6 +833,19 @@
 			info->dma_tag_p = parm.dma_tag_p;
 			info->dma_tag_max = parm.dma_tag_max;
 
+			LIST_INIT(&(info->done_head));
+
+			/* initialize mutex */
+			mtx_init(&(info->done_mtx), "USB done queue lock",
+			    NULL, MTX_DEF);
+
+			/* create our interrupt thread */
+			if (swi_add(NULL, "usbcb", &usbd_callback_intr_td,
+			    info, SWI_CAMBIO, INTR_MPSAFE, &(info->done_cookie))) {
+				info->done_cookie = NULL;
+				parm.err = USBD_NO_INTR_THREAD;
+				goto done;
+			}
 		} else {
 			info = NULL;
 		}
@@ -882,6 +901,7 @@
 				/* dummy xfer */
 				xfer = &dummy;
 				bzero(&dummy, sizeof(dummy));
+				refcount++;
 			}
 
 			parm.size[0] += sizeof(xfer[0]);
@@ -904,6 +924,10 @@
 		if (buf || parm.err) {
 			goto done;
 		}
+		if (refcount == 0) {
+			/* no transfers - nothing to do ! */
+			goto done;
+		}
 		/* align data to 8 byte boundary */
 		parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN - 1));
 
@@ -983,6 +1007,12 @@
 	}
 
 done:
+	if (buf) {
+		if (info->setup_refcount == 0) {
+			/* something went wrong */
+			usbd_transfer_unsetup_sub(info);
+		}
+	}
 	if (parm.err) {
 		usbd_transfer_unsetup(ppxfer, n_setup);
 	}
@@ -1011,6 +1041,62 @@
 	return;
 }
 
+static void
+usbd_transfer_unsetup_sub(struct usbd_memory_info *info)
+{
+	struct usbd_page_cache *pc;
+	int error;
+
+	/*
+	 * wait for any USB callbacks to
+	 * return
+	 */
+
+	while (info->memory_refcount > 0) {
+		error = mtx_sleep(info, info->usb_mtx, 0,
+		    "usb_mem_wait", 0);
+	}
+
+	mtx_unlock(info->usb_mtx);
+
+	/* free DMA'able memory, if any */
+	pc = info->dma_page_cache_start;
+	while (pc != info->dma_page_cache_end) {
+		usbd_pc_free_mem(pc);
+		pc++;
+	}
+
+	/*
+	 * free DMA maps in all
+	 * "xfer->frbuffers"
+	 */
+	pc = info->xfer_page_cache_start;
+	while (pc != info->xfer_page_cache_end) {
+		usbd_pc_dmamap_destroy(pc);
+		pc++;
+	}
+
+	/* free all DMA tags */
+	usbd_dma_tag_unsetup(info->dma_tag_p,
+	    info->dma_tag_max);
+
+	/* teardown the interrupt thread, if any */
+	if (info->done_cookie) {
+		swi_remove(info->done_cookie);
+	}
+	/* destroy done queue mutex */
+	mtx_destroy(&(info->done_mtx));
+
+	/*
+	 * free the "memory_base" last,
+	 * hence the "info" structure is
+	 * contained within the
+	 * "memory_base"!
+	 */
+	free(info->memory_base, M_USB);
+	return;
+}
+
 /*------------------------------------------------------------------------*
  *	usbd_transfer_unsetup - unsetup/free an array of USB transfers
  *
@@ -1023,8 +1109,6 @@
 {
 	struct usbd_xfer *xfer;
 	struct usbd_memory_info *info;
-	struct usbd_page_cache *pc;
-	int error;
 
 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
 	    "usbd_transfer_unsetup can sleep!");
@@ -1092,48 +1176,7 @@
 				info->setup_refcount--;
 
 				if (info->setup_refcount == 0) {
-
-					/*
-					 * wait for any USB callbacks to
-					 * return
-					 */
-
-					while (info->memory_refcount > 0) {
-						error = mtx_sleep(info, info->usb_mtx, 0,
-						    "usb_mem_wait", 0);
-					}
-
-					mtx_unlock(info->usb_mtx);
-
-					/* free DMA'able memory, if any */
-					pc = info->dma_page_cache_start;
-					while (pc != info->dma_page_cache_end) {
-						usbd_pc_free_mem(pc);
-						pc++;
-					}
-
-					/*
-					 * free DMA maps in all
-					 * "xfer->frbuffers"
-					 */
-					pc = info->xfer_page_cache_start;
-					while (pc != info->xfer_page_cache_end) {
-						usbd_pc_dmamap_destroy(pc);
-						pc++;
-					}
-
-					/* free all DMA tags */
-					usbd_dma_tag_unsetup(info->dma_tag_p,
-					    info->dma_tag_max);
-
-					/*
-					 * free the "memory_base" last,
-					 * hence the "info" structure is
-					 * contained within the
-					 * "memory_base"!
-					 */
-					free(info->memory_base, M_USB);
-
+					usbd_transfer_unsetup_sub(info);
 				} else {
 					mtx_unlock(info->usb_mtx);
 				}
@@ -1443,6 +1486,23 @@
 	return (1);
 }
 
+/*------------------------------------------------------------------------*
+ *	usbd_callback_intr_td
+ *
+ * This is the USB callback interrupt thread. Every time a callback
+ * cannot be called directly we go through the callback interrupt
+ * thread.
+ *------------------------------------------------------------------------*/
+static void
+usbd_callback_intr_td(void *arg)
+{
+#if 0
+	struct usbd_memory_info *info = arg;
+
+#endif
+	return;
+}
+
 static void
 usbd_premature_callback(struct usbd_xfer *xfer, usbd_status_t error)
 {


More information about the p4-projects mailing list