Skip to content

Commit d8a2bb4

Browse files
Wesley Chenggregkh
authored andcommitted
usb: dwc3: gadget: Add 1ms delay after end transfer command without IOC
Previously, there was a 100uS delay inserted after issuing an end transfer command for specific controller revisions. This was due to the fact that there was a GUCTL2 bit field which enabled synchronous completion of the end transfer command once the CMDACT bit was cleared in the DEPCMD register. Since this bit does not exist for all controller revisions and the current implementation heavily relies on utizling the EndTransfer command completion interrupt, add the delay back in for uses where the interrupt on completion bit is not set, and increase the duration to 1ms for the controller to complete the command. An issue was seen where the USB request buffer was unmapped while the DWC3 controller was still accessing the TRB. However, it was confirmed that the end transfer command was successfully submitted. (no end transfer timeout) In situations, such as dwc3_gadget_soft_disconnect() and __dwc3_gadget_ep_disable(), the dwc3_remove_request() is utilized, which will issue the end transfer command, and follow up with dwc3_gadget_giveback(). At least for the USB ep disable path, it is required for any pending and started requests to be completed and returned to the function driver in the same context of the disable call. Without the GUCTL2 bit, it is not ensured that the end transfer is completed before the buffers are unmapped. Fixes: cf2f8b6 ("usb: dwc3: gadget: Remove END_TRANSFER delay") Cc: stable <[email protected]> Signed-off-by: Wesley Cheng <[email protected]> Acked-by: Thinh Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 02c1820 commit d8a2bb4

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

drivers/usb/dwc3/gadget.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,7 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
16991699
*/
17001700
static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
17011701
{
1702+
struct dwc3 *dwc = dep->dwc;
17021703
struct dwc3_gadget_ep_cmd_params params;
17031704
u32 cmd;
17041705
int ret;
@@ -1722,10 +1723,13 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int
17221723
WARN_ON_ONCE(ret);
17231724
dep->resource_index = 0;
17241725

1725-
if (!interrupt)
1726+
if (!interrupt) {
1727+
if (!DWC3_IP_IS(DWC3) || DWC3_VER_IS_PRIOR(DWC3, 310A))
1728+
mdelay(1);
17261729
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
1727-
else if (!ret)
1730+
} else if (!ret) {
17281731
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
1732+
}
17291733

17301734
dep->flags &= ~DWC3_EP_DELAY_STOP;
17311735
return ret;
@@ -3774,7 +3778,11 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
37743778
* enabled, the EndTransfer command will have completed upon
37753779
* returning from this function.
37763780
*
3777-
* This mode is NOT available on the DWC_usb31 IP.
3781+
* This mode is NOT available on the DWC_usb31 IP. In this
3782+
* case, if the IOC bit is not set, then delay by 1ms
3783+
* after issuing the EndTransfer command. This allows for the
3784+
* controller to handle the command completely before DWC3
3785+
* remove requests attempts to unmap USB request buffers.
37783786
*/
37793787

37803788
__dwc3_stop_active_transfer(dep, force, interrupt);

0 commit comments

Comments
 (0)