From: Ajay Kumar Gupta To: linux-usb@vger.kernel.org Cc: linux-omap@vger.kernel.org, david-b@pacbell.net, me@felipebalbi.com, Ajay Kumar Gupta Subject: [PATCH] MUSB: BULK request on different available endpoints Date: Tue, 7 Oct 2008 11:12:24 +0530 Fixes co-working issue of usb serial device with usb/net devices while oter endpoints are free and can be used.This patch implements the policy that if endpoint resources are available then different BULK request goes to different endpoint otherwise they are multiplexed to one reserved endpoint as currently done. NAK limit scheme has to be added for multiplexed BULK request scenario to avoid endpoint starvation due to usb/net devices. musb->periodic[] flag setting is also updated.It use to set this flag for an endpoint even when only rx or tx is used.Now flag setting is done on rx/tx basis of an endpoint. Signed-off-by: Ajay Kumar Gupta --- drivers/usb/musb/musb_host.c | 94 ++++++++++++++++++++++++------------------ drivers/usb/musb/musb_host.h | 1 + 2 files changed, 55 insertions(+), 40 deletions(-) --- /tmp/musb_host.c 2008-10-07 10:10:49.000000000 +0200 +++ git/drivers/usb/musb/musb_host.c 2008-10-07 10:13:59.000000000 +0200 @@ -378,27 +378,32 @@ switch (qh->type) { + case USB_ENDPOINT_XFER_CONTROL: + case USB_ENDPOINT_XFER_BULK: + /* fifo policy for these lists, except that NAKing + * should rotate a qh to the end (for fairness). + */ + if (qh->mux == 1) { + head = qh->ring.prev; + list_del(&qh->ring); + kfree(qh); + qh = first_qh(head); + break; + } case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: /* this is where periodic bandwidth should be * de-allocated if it's tracked and allocated; * and where we'd update the schedule tree... */ - musb->periodic[ep->epnum] = NULL; + if (is_in) + musb->periodic[2 * ep->epnum - 2] = NULL; + else + musb->periodic[2 * ep->epnum - 1] = NULL; kfree(qh); qh = NULL; break; - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - /* fifo policy for these lists, except that NAKing - * should rotate a qh to the end (for fairness). - */ - head = qh->ring.prev; - list_del(&qh->ring); - kfree(qh); - qh = first_qh(head); - break; } } return qh; @@ -1728,22 +1733,9 @@ u16 maxpacket; /* use fixed hardware for control and bulk */ - switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: + if (qh->type == USB_ENDPOINT_XFER_CONTROL) { head = &musb->control; hw_ep = musb->control_ep; - break; - case USB_ENDPOINT_XFER_BULK: - hw_ep = musb->bulk_ep; - if (is_in) - head = &musb->in_bulk; - else - head = &musb->out_bulk; - break; - } - if (head) { - idle = list_empty(head); - list_add_tail(&qh->ring, head); goto success; } @@ -1778,7 +1770,8 @@ for (epnum = 1; epnum < musb->nr_endpoints; epnum++) { int diff; - if (musb->periodic[epnum]) + if ((is_in && musb->periodic[2 * epnum - 2]) || + (!is_in && musb->periodic[2 * epnum - 1])) continue; hw_ep = &musb->endpoints[epnum]; if (hw_ep == musb->bulk_ep) @@ -1789,19 +1782,36 @@ else diff = hw_ep->max_packet_sz_tx - maxpacket; - if (diff > 0 && best_diff > diff) { + if (diff >= 0 && best_diff > diff) { best_diff = diff; best_end = epnum; } } - if (best_end < 0) + /* use bulk reserved ep1 if no other ep is free*/ + if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) { + hw_ep = musb->bulk_ep; + if (is_in) + head = &musb->in_bulk; + else + head = &musb->out_bulk; + goto success; + } else if (best_end < 0) return -ENOSPC; idle = 1; + qh->mux = 0; hw_ep = musb->endpoints + best_end; - musb->periodic[best_end] = qh; - DBG(4, "qh %p periodic slot %d\n", qh, best_end); + if (is_in) + musb->periodic[2 * best_end - 2] = qh; + else + musb->periodic[2 * best_end - 1] = qh; + DBG(4, "qh %p periodic slot %d%s\n", qh, best_end, is_in ? "Rx" : "Tx"); success: + if (head) { + idle = list_empty(head); + list_add_tail(&qh->ring, head); + qh->mux = 1; + } qh->hw_ep = hw_ep; qh->hep->hcpriv = qh; if (idle) @@ -2065,11 +2075,13 @@ sched = &musb->control; break; case USB_ENDPOINT_XFER_BULK: - if (usb_pipein(urb->pipe)) - sched = &musb->in_bulk; - else - sched = &musb->out_bulk; - break; + if (qh->mux == 1) { + if (usb_pipein(urb->pipe)) + sched = &musb->in_bulk; + else + sched = &musb->out_bulk; + break; + } default: /* REVISIT when we get a schedule tree, periodic * transfers won't always be at the head of a @@ -2131,11 +2143,13 @@ sched = &musb->control; break; case USB_ENDPOINT_XFER_BULK: - if (is_in) - sched = &musb->in_bulk; - else - sched = &musb->out_bulk; - break; + if (qh->mux == 1) { + if (is_in) + sched = &musb->in_bulk; + else + sched = &musb->out_bulk; + break; + } case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_INT: for (i = 0; i < musb->nr_endpoints; i++) { --- /tmp/musb_host.h 2008-10-07 08:59:38.000000000 +0200 +++ git/drivers/usb/musb/musb_host.h 2008-10-07 10:10:54.000000000 +0200 @@ -53,7 +53,8 @@ struct list_head ring; /* of musb_qh */ /* struct musb_qh *next; */ /* for periodic tree */ - + u8 mux; /* qh multiplexed to hw_ep */ + unsigned offset; /* in urb->transfer_buffer */ unsigned segsize; /* current xfer fragment */