diff options
author | Luo Ji <ji.luo@nxp.com> | 2018-07-13 18:23:43 +0800 |
---|---|---|
committer | Ji Luo <ji.luo@nxp.com> | 2018-08-20 21:31:58 +0800 |
commit | 41b5389845b8912689288d52b8cfc9f71dc115e0 (patch) | |
tree | f3a8b36172d9c6194580fc8fb6a4aaa336dbc22a /drivers | |
parent | 653135b657a7dddd537a008464e6791766bc32fa (diff) |
MA-12160 Check the request status in dequeue for cdns3 driver
"fastboot reboot bootloader" fails to transmit "OKAY" back to host on
imx8qm because fastboot_tx_write_str() will dequeue the IN request
first before queue it, cdns3 usb driver will always invoke the complete
callback in dequeue, so if we are going to do_reset() in the complete
callback, the device will reboot before we can transmit "OKAY" back to
host in queue.
Check the request status in dequeue first before invoke the complete
callback, this is basically ported from kernel.
Test: No error messages when run "fastboot reboot bootloader" on
imx8qm_mek.
Change-Id: I085df3bd0f37480b8636585cc1068d5fcae331c1
Signed-off-by: Luo Ji <ji.luo@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/cdns3/gadget.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index b2bfadcfa4..e5158fae20 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1044,6 +1044,7 @@ static void cdns_check_ep0_interrupt_proceed(struct usb_ss_dev *usb_ss, int dir) dev_dbg(&usb_ss->dev, "IOC(%02X) %d\n", dir ? USB_DIR_IN : USB_DIR_OUT, usb_ss->actual_ep0_request->actual); + list_del_init(&usb_ss->actual_ep0_request->list); } if (usb_ss->actual_ep0_request && @@ -1371,7 +1372,7 @@ static int usb_ss_gadget_ep0_queue(struct usb_ep *ep, usb_ss->actual_ep0_request = request; cdns_ep0_run_transfer(usb_ss, request->dma, request->length, 1); - + list_add_tail(&request->list, &usb_ss_ep->request_list); spin_unlock_irqrestore(&usb_ss->lock, flags); return 0; @@ -1702,6 +1703,7 @@ static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep, struct usb_ss_endpoint *usb_ss_ep = to_usb_ss_ep(ep); struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss; + struct usb_request *req, *req_temp; unsigned long flags; spin_lock_irqsave(&usb_ss->lock, flags); @@ -1713,17 +1715,22 @@ static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep, } dev_dbg(&usb_ss->dev, "DEQUEUE(%02X) %d\n", usb_ss_ep->address, request->length); - usb_gadget_unmap_request(&usb_ss->gadget, request, - usb_ss_ep->address & USB_DIR_IN); - request->status = -ECONNRESET; - if (usb_ss_ep->address) - list_del(&request->list); - - if (request->complete) { - spin_unlock(&usb_ss->lock); - request->complete(ep, request); - spin_lock(&usb_ss->lock); + list_for_each_entry_safe(req, req_temp, + &usb_ss_ep->request_list, list) { + if (request == req) { + request->status = -ECONNRESET; + usb_gadget_unmap_request(&usb_ss->gadget, request, + usb_ss_ep->address & USB_DIR_IN); + list_del_init(&request->list); + if (request->complete) { + spin_unlock(&usb_ss->lock); + usb_gadget_giveback_request + (&usb_ss_ep->endpoint, request); + spin_lock(&usb_ss->lock); + } + break; + } } spin_unlock_irqrestore(&usb_ss->lock, flags); @@ -2069,8 +2076,8 @@ static int usb_ss_init_ep0(struct usb_ss_dev *usb_ss) ep0->caps.dir_out = 1; ep0->endpoint.name = ep0->name; ep0->endpoint.desc = &cdns3_gadget_ep0_desc; - usb_ss->gadget.ep0 = &ep0->endpoint; + INIT_LIST_HEAD(&ep0->request_list); return 0; } |