usb: dwc3: gadget: Continue handling EP0 xfercomplete events
authorWesley Cheng <quic_wcheng@quicinc.com>
Wed, 17 Aug 2022 18:23:54 +0000 (11:23 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 31 Aug 2022 07:07:53 +0000 (09:07 +0200)
During soft disconnect, EP0 events are expected to be handled in order to
allow the controller to successfully move into the halted state.  Since
__dwc3_gadget_stop() is executed before polling, EP0 has been disabled, and
events are being blocked.  Allow xfercomplete events to be handled, so that
cached SETUP packets can be read out from the internal controller memory.

Without doing so, it will lead to endxfer timeouts, which results to
controller halt failures.

Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
Link: https://lore.kernel.org/r/20220817182359.13550-5-quic_wcheng@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc3/gadget.c

index 311348aea58e33d7ae07643b58b7c7eaa4c89d2d..d6c0cb79ace33d9d0ed587a2d79e9d588d97e95c 100644 (file)
@@ -2721,6 +2721,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
        dep = dwc->eps[0];
+       dep->flags = 0;
        ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -2728,6 +2729,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
        }
 
        dep = dwc->eps[1];
+       dep->flags = 0;
        ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
@@ -3599,11 +3601,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
        dep = dwc->eps[epnum];
 
        if (!(dep->flags & DWC3_EP_ENABLED)) {
-               if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
+               if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED))
                        return;
 
                /* Handle only EPCMDCMPLT when EP disabled */
-               if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT)
+               if ((event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) &&
+                       !(epnum <= 1 && event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE))
                        return;
        }