summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLuo Ji <ji.luo@nxp.com>2018-07-13 18:23:43 +0800
committerJi Luo <ji.luo@nxp.com>2018-08-20 21:31:58 +0800
commit41b5389845b8912689288d52b8cfc9f71dc115e0 (patch)
treef3a8b36172d9c6194580fc8fb6a4aaa336dbc22a /drivers
parent653135b657a7dddd537a008464e6791766bc32fa (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.c31
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;
}