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