Currently DWC3 controller revisions 3.10a and later supports GUCTL[14: Rst_actbitlater] bit which allows polling CMDACT bit to know whether ENDXFER command is completed. Other revisions wait 1ms for ENDXFER completion after issuing the command. Consider a case where an IN request was queued, and parallelly soft_disconnect was called (due to ffs_epfile_release). This eventually calls stop_active_transfer with IOC cleared, hence send_gadget_ep_cmd() skips waiting for CMDACT cleared during endxfer. For DWC3 controllers with revisions >= 310a, we don't forcefully wait for 1ms either, and we proceed by unmapping the requests. If ENDXFER didn't complete by this time, it leads to SMMU faults since the controller would still be accessing those requests. DWC3 databook specifies that CMDACT bit can be polled to check completion of the EndXfer. Hence use it in stop_active_transfer to know whether the ENDXFER got completed. Section 3.2.2.7 Command 8: End Transfer (DEPENDXFER) Note: If GUCTL2[Rst_actbitlater] is set, Software can poll the completion of the End Transfer command by polling the command active bit to be cleared to 0. Fixes: b353eb6dc285 ("usb: dwc3: gadget: Skip waiting for CMDACT cleared during endxfer") Signed-off-by: Prashanth K <quic_prashk@xxxxxxxxxxx> --- drivers/usb/dwc3/gadget.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4df2661f6675..acb54c48451f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1701,8 +1701,8 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int { struct dwc3 *dwc = dep->dwc; struct dwc3_gadget_ep_cmd_params params; - u32 cmd; - int ret; + u32 cmd, reg; + int ret, retries = 500; cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; @@ -1726,6 +1726,24 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int if (!interrupt) { if (!DWC3_IP_IS(DWC3) || DWC3_VER_IS_PRIOR(DWC3, 310A)) mdelay(1); + else { + /* + * ENDXFER polling is available on version 3.10a and later of + * the DWC3 controller (This is enabled by setting GUCTL2[14]) + */ + do { + reg = dwc3_readl(dep->regs, DWC3_DEPCMD); + if (!(reg & DWC3_DEPCMD_CMDACT)) + break; + udelay(2); + } while (--retries); + + if (!retries && (dwc->ep0state != EP0_SETUP_PHASE)) { + dep->flags |= DWC3_EP_DELAY_STOP; + return -ETIMEDOUT; + } + } + dep->flags &= ~DWC3_EP_TRANSFER_STARTED; } else if (!ret) { dep->flags |= DWC3_EP_END_TRANSFER_PENDING; -- 2.25.1