summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnish Trivedi <anish@freescale.com>2011-09-01 17:20:42 -0500
committerAnish Trivedi <anish@freescale.com>2011-09-07 11:21:41 -0500
commit0013fae0e8ab01d99018ce2c6c4552e958c9de71 (patch)
treec219a96af4e82437d29e56bc4600ff10d736b17c
parentdc2a5b4d598da41ddc9144786ccca5ca9fd7cead (diff)
ENGR00155880 USB device: Fix RNDIS Full Speed hang during initialization
When setup irq is received, the status phase of the transfer is primed on ep0 before the data phase. The usb requests are added to the list of transfer descriptors (maintained by driver) in reverse of their expected completion order. Completion order is data followed by status, however the list of tds contains status followed by data. Upon completion of the data request, the irq handler proceeds to check the 1st td in the list -- the status request. In full speed mode, the status phase has not yet completed at this time, so the td's ACTIVE bit is still set. This leads irq handler to ignore the completion interrupt without checking the actual td for the data request that caused the interrupt. In high speed mode, this issue does not bear itself out because the status request also completes by the time the irq handler goes to process the data completion interrupt. The simple fix for this issue is to prime the status request AFTER the data request, so that the list of tds maintained by the driver contains the tds in the order of expected completion. Signed-off-by: Anish Trivedi <anish@freescale.com>
-rw-r--r--drivers/usb/gadget/arcotg_udc.c20
1 files changed, 8 insertions, 12 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index 23d736b1f646..fe08b0df6a0a 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -1575,17 +1575,6 @@ static void setup_received_irq(struct fsl_udc *udc,
unsigned mA = 500;
udc_reset_ep_queue(udc, 0);
- if (wLength) {
- int dir;
- dir = EP_DIR_IN;
- if (setup->bRequestType & USB_DIR_IN) {
- dir = EP_DIR_OUT;
- }
- spin_unlock(&udc->lock);
- if (ep0_prime_status(udc, dir))
- ep0stall(udc);
- spin_lock(&udc->lock);
- }
/* We process some stardard setup requests here */
switch (setup->bRequest) {
case USB_REQ_GET_STATUS:
@@ -1687,9 +1676,16 @@ static void setup_received_irq(struct fsl_udc *udc,
spin_unlock(&udc->lock);
if (udc->driver->setup(&udc->gadget,
&udc->local_setup_buff) < 0) {
- /* cancel status phase */
+ /* cancel all requests on ep0 */
udc_reset_ep_queue(udc, 0);
ep0stall(udc);
+ } else {
+ /* prime the status phase */
+ int dir = EP_DIR_IN;
+ if (setup->bRequestType & USB_DIR_IN)
+ dir = EP_DIR_OUT;
+ if (ep0_prime_status(udc, dir))
+ ep0stall(udc);
}
} else {
/* No data phase, IN status from gadget */