PERFORCE change 163628 for review

Andrew Thompson thompsa at FreeBSD.org
Sat Jun 6 04:33:11 UTC 2009


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

Change 163628 by thompsa at thompsa_burger on 2009/06/06 04:32:19

	- Allocate multiple urbs
	- Add urb list functions

Affected files ...

.. //depot/projects/usb_buf/src/sys/dev/usb/usb_transfer.c#14 edit
.. //depot/projects/usb_buf/src/sys/dev/usb/usbdi.h#5 edit

Differences ...

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

@@ -61,6 +61,11 @@
 #include <dev/usb/usb_controller.h>
 #include <dev/usb/usb_bus.h>
 
+enum {
+	REQ_SIZE = 8,
+	MIN_PKT = 8,
+};
+
 struct usb2_std_packet_size {
 	struct {
 		uint16_t min;		/* inclusive */
@@ -114,6 +119,9 @@
 static void	usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, 
 		    uint8_t type, enum usb_dev_speed speed);
 static void	usb_submit_urb_flags(struct usb_urb *, int);
+static struct usb_urb *urb_alloc(struct usb_pipe *, struct usb_setup_params *,
+		    uint8_t, usb_frcount_t, usb_frcount_t);
+static void	urb_free(struct usb_urb *);
 
 
 /*------------------------------------------------------------------------*
@@ -297,6 +305,101 @@
 }
 #endif
 
+static struct usb_urb *
+urb_alloc(struct usb_pipe *pipe, struct usb_setup_params *parm,
+    uint8_t type, usb_frcount_t n_frlengths, usb_frcount_t n_frbuffers)
+{
+	const struct usb_config *setup = parm->curr_setup;
+	struct usb_urb *urb;
+	usb_frlength_t bufsiz;
+	usb_frcount_t x;
+
+	bufsiz = setup->flags.ext_buffer == 1 ? 0 : parm->bufsize;
+
+	urb = malloc(sizeof(struct usb_urb) + bufsiz, M_USB,
+	    M_WAITOK | M_ZERO);
+	urb->ub_pipe = pipe;
+	urb->ub_buflen = bufsiz;
+	urb->local_buffer = urb + 1;
+
+	urb->frlengths = malloc(sizeof(usb_frlength_t) * n_frlengths,
+	    M_USB, M_WAITOK | M_ZERO);
+	urb->frbuffers = malloc(sizeof(struct usb_page_cache) * n_frbuffers,
+	    M_USB, M_WAITOK | M_ZERO);
+
+#if USB_HAVE_BUSDMA
+	if (pipe->flags_int.bdma_enable) {
+		/*
+		 * Setup "dma_page_ptr".
+		 *
+		 * Proof for formula below:
+		 *
+		 * Assume there are three USB frames having length "a",
+		 * "b" and "c". These USB frames will at maximum need
+		 * "z" "usb_page" structures. "z" is given by:
+		 *
+		 * z = ((a / USB_PAGE_SIZE) + 2) +
+		 *	((b / USB_PAGE_SIZE) + 2) +
+		 *	((c / USB_PAGE_SIZE) + 2);
+		 *
+		 * Constraining "a", "b" and "c" like this:
+		 *
+		 * (a + b + c) <= parm->bufsize
+		 *
+		 * We know that:
+		 *
+		 * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
+		 *
+		 * Here is the general formula:
+		 */
+		urb->dma_page_ptr = malloc(sizeof(struct usb_page) *
+		    ((2 * n_frbuffers) + (parm->bufsize / USB_PAGE_SIZE)),
+		    M_USB, M_WAITOK | M_ZERO);
+	}
+#endif
+	/* initialize frame buffers */
+	for (x = 0; x < n_frbuffers; x++) {
+		urb->frbuffers[x].tag_parent =
+		&pipe->xroot->dma_parent_tag;
+#if USB_HAVE_BUSDMA
+		if (pipe->flags_int.bdma_enable &&
+		    (parm->bufsize_max > 0)) {
+
+			if (usb2_pc_dmamap_create(
+				    urb->frbuffers + x,
+				    parm->bufsize_max)) {
+				goto error;
+			}
+		}
+#endif
+	}
+
+	if (bufsiz > 0) {
+		usb2_set_frame_offset(urb, 0, 0);
+		if ((type == UE_CONTROL) && (n_frbuffers > 1))
+			usb2_set_frame_offset(urb, REQ_SIZE, 1);
+	}
+	/* initialize max frame count */
+	urb->max_frame_count = pipe->nframes;
+	urb->nframes = pipe->nframes;
+
+	return (urb);
+
+error:
+	urb_free(urb);
+	return (NULL);
+}
+
+static void
+urb_free(struct usb_urb *urb)
+{
+
+	free(urb->dma_page_ptr, M_USB);
+	free(urb->frbuffers, M_USB);
+	free(urb->frlengths, M_USB);
+	free(urb, M_USB);
+}
+
 /*------------------------------------------------------------------------*
  *	usb2_transfer_setup_sub - transfer setup subroutine
  *
@@ -309,10 +412,6 @@
 void
 usb2_transfer_setup_sub(struct usb_setup_params *parm)
 {
-	enum {
-		REQ_SIZE = 8,
-		MIN_PKT = 8,
-	};
 	struct usb_pipe *pipe = parm->curr_pipe;
 	const struct usb_config *setup = parm->curr_setup;
 	struct usb_endpoint_descriptor *edesc;
@@ -320,9 +419,9 @@
 	struct usb_urb *urb;
 	usb_frcount_t n_frlengths;
 	usb_frcount_t n_frbuffers;
-	usb_frcount_t x;
 	uint8_t type;
 	uint8_t zmps;
+	int i;
 
 	/*
 	 * Sanity check. The following parameters must be initialized before
@@ -338,15 +437,9 @@
 
 	type = (edesc->bmAttributes & UE_XFERTYPE);
 
-	/* XXX */
 	TAILQ_INIT(&pipe->urb_hc_q);
 	TAILQ_INIT(&pipe->urb_pending_q);
 	TAILQ_INIT(&pipe->urb_free_q);
-	urb = &pipe->urb0;
-	urb->ub_pipe = pipe;
-	TAILQ_INSERT_TAIL(&pipe->urb_free_q, urb, ub_next);
-	pipe->urb_nfree = 1;
-	pipe->urb_nurb = 1;
 
 	pipe->flags = setup->flags;
 	pipe->nframes = setup->frames;
@@ -602,80 +695,30 @@
 		}
 		pipe->max_data_length -= REQ_SIZE;
 	}
-	/* setup "frlengths" */
-
-	pipe->urb0.frlengths = parm->xfer_length_ptr;
 
-	parm->xfer_length_ptr += n_frlengths;
-
-	/* setup "frbuffers" */
-
-	pipe->urb0.frbuffers = parm->xfer_page_cache_ptr;
-
-	parm->xfer_page_cache_ptr += n_frbuffers;
-
 	/*
-	 * check if we need to setup
-	 * a local buffer:
+	 * Compute maximum buffer size
 	 */
 
-	if (!pipe->flags.ext_buffer) {
+	if (parm->bufsize_max < parm->bufsize) {
+		parm->bufsize_max = parm->bufsize;
+	}
 
-		/* align data */
-		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
-
-		if (parm->buf) {
-
-			pipe->urb0.local_buffer =
-			    USB_ADD_BYTES(parm->buf, parm->size[0]);
-
-			usb2_set_frame_offset(pipe, 0, 0);
-
-			if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
-				usb2_set_frame_offset(pipe, REQ_SIZE, 1);
+	/* Allocate the URBs */
+	if (parm->buf) {
+		pipe->urb_nurb = setup->urb_count ? setup->urb_count : 1;
+		for (i = 0; i < pipe->urb_nurb; i++) {
+			urb = urb_alloc(pipe, parm, type, n_frlengths,
+			    n_frbuffers);
+			if (urb == NULL) {
+				parm->err = USB_ERR_NOMEM;
+				goto done;
 			}
+			TAILQ_INSERT_TAIL(&pipe->urb_free_q, urb, ub_next);
+			pipe->urb_nfree++;
 		}
-		parm->size[0] += parm->bufsize;
-
-		/* align data again */
-		parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
 	}
-	/*
-	 * Compute maximum buffer size
-	 */
 
-	if (parm->bufsize_max < parm->bufsize) {
-		parm->bufsize_max = parm->bufsize;
-	}
-#if USB_HAVE_BUSDMA
-	if (pipe->flags_int.bdma_enable) {
-		/*
-		 * Setup "dma_page_ptr".
-		 *
-		 * Proof for formula below:
-		 *
-		 * Assume there are three USB frames having length "a", "b" and
-		 * "c". These USB frames will at maximum need "z"
-		 * "usb_page" structures. "z" is given by:
-		 *
-		 * z = ((a / USB_PAGE_SIZE) + 2) + ((b / USB_PAGE_SIZE) + 2) +
-		 * ((c / USB_PAGE_SIZE) + 2);
-		 *
-		 * Constraining "a", "b" and "c" like this:
-		 *
-		 * (a + b + c) <= parm->bufsize
-		 *
-		 * We know that:
-		 *
-		 * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
-		 *
-		 * Here is the general formula:
-		 */
-		pipe->urb0.dma_page_ptr = parm->dma_page_ptr;
-		parm->dma_page_ptr += (2 * n_frbuffers);
-		parm->dma_page_ptr += (parm->bufsize / USB_PAGE_SIZE);
-	}
-#endif
 	if (zmps) {
 		/* correct maximum data length */
 		pipe->max_data_length = 0;
@@ -690,31 +733,7 @@
 		parm->err = USB_ERR_INVAL;
 		goto done;
 	}
-	/* initialize max frame count */
 
-	pipe->urb0.max_frame_count = pipe->nframes;
-
-	/* initialize frame buffers */
-
-	if (parm->buf) {
-		for (x = 0; x != n_frbuffers; x++) {
-			pipe->urb0.frbuffers[x].tag_parent =
-			    &pipe->xroot->dma_parent_tag;
-#if USB_HAVE_BUSDMA
-			if (pipe->flags_int.bdma_enable &&
-			    (parm->bufsize_max > 0)) {
-
-				if (usb2_pc_dmamap_create(
-				    pipe->urb0.frbuffers + x,
-				    parm->bufsize_max)) {
-					parm->err = USB_ERR_NOMEM;
-					goto done;
-				}
-			}
-#endif
-		}
-	}
-	pipe->urb0.nframes = pipe->nframes;
 done:
 	if (parm->err) {
 		/*
@@ -724,8 +743,6 @@
 		pipe->max_frame_size = 1;
 		pipe->max_packet_size = 1;
 		pipe->max_data_length = 0;
-		pipe->urb0.nframes = 0;
-		pipe->urb0.max_frame_count = 0;
 	}
 }
 
@@ -783,6 +800,10 @@
 			parm.err = USB_ERR_BAD_BUFSIZE;
 			DPRINTF("invalid bufsize\n");
 		}
+		if (setup->urb_count > 4) {
+			parm.err = USB_ERR_BAD_BUFSIZE;
+			DPRINTF("too many urbs requested\n");
+		}
 		if (setup->callback == NULL) {
 			parm.err = USB_ERR_NO_CALLBACK;
 			DPRINTF("no callback\n");
@@ -1128,6 +1149,7 @@
 usb_pipe_close(struct usb_pipe **pxfer, int n_setup)
 {
 	struct usb_pipe *pipe;
+	struct usb_urb *urb;
 	struct usb_xfer_root *info;
 	uint8_t needs_delay = 0;
 
@@ -1171,6 +1193,11 @@
 		KASSERT (pipe->urb_nfree == pipe->urb_nurb,
 		    ("leaked %d urbs", pipe->urb_nurb - pipe->urb_nfree));
 
+		while ((urb = TAILQ_FIRST(&pipe->urb_free_q)) != NULL) {
+			TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
+			urb_free(urb);
+		}
+
 #if USB_HAVE_BUSDMA
 		if (pipe->flags_int.bdma_enable)
 			needs_delay = 1;
@@ -1421,8 +1448,6 @@
 		printf("pipe halted, queuing %p\n", urb);
 		TAILQ_INSERT_TAIL(&pipe->urb_pending_q, urb, ub_next);
 		return;
-	} else {
-		KASSERT(TAILQ_FIRST(&pipe->urb_pending_q) == NULL, ("odd"));
 	}
 
 	/* Only open the USB transfer once! */
@@ -1657,6 +1682,10 @@
 usb_pipe_halt(struct usb_pipe *pipe)
 {
 
+	if (pipe == NULL) {
+		printf("%s: null pipe!!?!\n", __func__);
+		return;
+	}
 	USB_PIPE_LOCK(pipe);
 
 	pipe->flags_int.halted = 1;
@@ -1742,10 +1771,10 @@
  * than zero gives undefined results!
  *------------------------------------------------------------------------*/
 void
-usb2_set_frame_data(struct usb_pipe *pipe, void *ptr, usb_frcount_t frindex)
+usb2_set_frame_data(struct usb_urb *urb, void *ptr, usb_frcount_t frindex)
 {
 	/* set virtual address to load and length */
-	(&pipe->urb0)->frbuffers[frindex].buffer = ptr;
+	urb->frbuffers[frindex].buffer = ptr;
 }
 
 /*------------------------------------------------------------------------*
@@ -1755,15 +1784,19 @@
  * of the USB DMA buffer allocated for this USB transfer.
  *------------------------------------------------------------------------*/
 void
-usb2_set_frame_offset(struct usb_pipe *pipe, usb_frlength_t offset,
+usb2_set_frame_offset(struct usb_urb *urb, usb_frlength_t offset,
     usb_frcount_t frindex)
 {
+	struct usb_pipe *pipe = urb->ub_pipe;
+
 	USB_ASSERT(!pipe->flags.ext_buffer, ("Cannot offset data frame "
 	    "when the USB buffer is external!\n"));
+	/* USB_ASSERT(offset < urb->ub_buflen,
+	    ("frame overflow %d > %d", offset, urb->ub_buflen)); */
 
 	/* set virtual address to load */
-	(&pipe->urb0)->frbuffers[frindex].buffer =
-	    USB_ADD_BYTES((&pipe->urb0)->local_buffer, offset);
+	urb->frbuffers[frindex].buffer =
+			USB_ADD_BYTES(urb->local_buffer, offset);
 }
 
 /*------------------------------------------------------------------------*
@@ -2743,15 +2776,14 @@
 
 	USB_PIPE_LOCK(pipe);
 	urb = TAILQ_FIRST(&pipe->urb_free_q);
-	if (urb == NULL)
-		panic("out of urbs");
+	if (urb != NULL) {
+		TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
+		pipe->urb_nfree--;
+		KASSERT(pipe->urb_nfree >= 0, ("negative count"));
 
-	TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
-	pipe->urb_nfree--;
-	KASSERT(pipe->urb_nfree >= 0, ("negative count"));
+		usb_init_urb(urb);
+	}
 	USB_PIPE_UNLOCK(pipe);
-
-	usb_init_urb(urb);
 	return (urb);
 }
 
@@ -2808,7 +2840,7 @@
 	if (ptr != NULL)
 		*ptr = urb->frbuffers->buffer;
 	if (len != NULL)
-		*len = urb->sumlen;
+		*len = urb->ub_pipe->max_data_length;
 	if (alen != NULL)
 		*alen = urb->actlen;
 	if (err != NULL)
@@ -2816,8 +2848,52 @@
 }
 
 void
-urb_set_framelen(struct usb_urb *urb, int frame, int len)
+urb_set_framelen(struct usb_urb *urb, usb_frcount_t frame, usb_frlength_t len)
 {
-	/* XXX checking */
+	KASSERT(len <= urb->ub_pipe->max_data_length,
+	    ("%s: urb buffer overflow", __func__));
 	urb->frlengths[frame] = len;
 }
+
+void
+urb_list_init(usb_urb_list *list)
+{
+
+	TAILQ_INIT(&list->head);
+	list->count = 0;
+}
+
+void
+urb_list_insert(usb_urb_list *list, struct usb_urb *urb)
+{
+
+	KASSERT(urb->on_queue == 0, ("urb already qeueued"));
+	TAILQ_INSERT_TAIL(&list->head, urb, ub_next);
+	list->count++;
+	urb->on_queue = 1;
+}
+
+void
+urb_list_remove(usb_urb_list *list, struct usb_urb *urb)
+{
+
+	KASSERT(urb->on_queue == 1, ("urb not on qeueue"));
+	KASSERT(list->count > 0, ("list count corrupt"));
+	TAILQ_REMOVE(&list->head, urb, ub_next);
+	list->count--;
+	urb->on_queue = 0;
+}
+
+struct usb_urb *
+urb_list_dequeue(usb_urb_list *list)
+{
+	struct usb_urb *urb;
+
+	urb = TAILQ_FIRST(&list->head);
+	if (urb != NULL)
+		urb_list_remove(list, urb);
+
+	KASSERT(urb != NULL || list->count == 0, ("list count corrupt"));
+
+	return (urb);
+}

==== //depot/projects/usb_buf/src/sys/dev/usb/usbdi.h#5 (text+ko) ====

@@ -93,6 +93,11 @@
 typedef usb_error_t (usb_handle_req_t)(struct usb_device *,
     struct usb_device_request *, const void **, uint16_t *);
 
+typedef struct {
+	TAILQ_HEAD(, usb_urb)	head;
+	int			count;
+} usb_urb_list;
+
 /*
  * The following structure defines a set of USB transfer flags.
  */
@@ -132,6 +137,7 @@
 	uint8_t	direction;		/* pipe direction */
 	uint8_t	ep_index;		/* pipe index match to use */
 	uint8_t	if_index;		/* "ifaces" index to use */
+	uint8_t	urb_count;		/* number if urbs avaialble */
 };
 
 /*
@@ -300,7 +306,13 @@
 void	*urb_get_softc(struct usb_urb *urb);
 void	*urb_get_priv(struct usb_urb *urb);
 void	urb_set_priv(struct usb_urb *urb, void *);
-void	urb_set_framelen(struct usb_urb *urb, int frame, int len);
+void	urb_set_framelen(struct usb_urb *urb, usb_frcount_t frame,
+	    usb_frlength_t len);
+
+void	urb_list_init(usb_urb_list *);
+void	urb_list_insert(usb_urb_list *, struct usb_urb *);
+void	urb_list_remove(usb_urb_list *, struct usb_urb *);
+struct usb_urb *urb_list_dequeue(usb_urb_list *);
 
 void	device_set_usb_desc(device_t dev);
 void	usb_pause_mtx(struct mtx *mtx, int _ticks);


More information about the p4-projects mailing list