]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: dwc3: gadget: Resume pending requests after CLEAR_STALL
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Thu, 3 Sep 2020 01:42:58 +0000 (18:42 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Nov 2020 10:51:39 +0000 (11:51 +0100)
commit c503672abe1348f10f5a54a662336358c6e1a297 upstream.

The function driver may queue new requests right after halting the
endpoint (i.e. queue new requests while the endpoint is stalled).
There's no restriction preventing it from doing so. However, dwc3
currently drops those requests after CLEAR_STALL. The driver should only
drop started requests. Keep the pending requests in the pending list to
resume and process them after the host issues ClearFeature(Halt) to the
endpoint.

Cc: stable@vger.kernel.org
Fixes: cb11ea56f37a ("usb: dwc3: gadget: Properly handle ClearFeature(halt)")
Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/gadget.c

index 97793838ad75d85bddc45e08a2e30b2e2c32b74e..af649940c4240be493aca181e082228524d203d1 100644 (file)
@@ -1628,8 +1628,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
        if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)
                return 0;
 
-       /* Start the transfer only after the END_TRANSFER is completed */
-       if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
+       /*
+        * Start the transfer only after the END_TRANSFER is completed
+        * and endpoint STALL is cleared.
+        */
+       if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
+           (dep->flags & DWC3_EP_WEDGE) ||
+           (dep->flags & DWC3_EP_STALL)) {
                dep->flags |= DWC3_EP_DELAY_START;
                return 0;
        }
@@ -1836,13 +1841,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
                list_for_each_entry_safe(req, tmp, &dep->started_list, list)
                        dwc3_gadget_move_cancelled_request(req);
 
-               list_for_each_entry_safe(req, tmp, &dep->pending_list, list)
-                       dwc3_gadget_move_cancelled_request(req);
-
-               if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) {
-                       dep->flags &= ~DWC3_EP_DELAY_START;
+               if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
                        dwc3_gadget_ep_cleanup_cancelled_requests(dep);
-               }
+
+               if ((dep->flags & DWC3_EP_DELAY_START) &&
+                   !usb_endpoint_xfer_isoc(dep->endpoint.desc))
+                       __dwc3_gadget_kick_transfer(dep);
+
+               dep->flags &= ~DWC3_EP_DELAY_START;
        }
 
        return ret;