This patch fixes a commit that causes a hang from device waiting for data with the wrong sequence number. The commit ffb80fc672c3 ("usb: dwc3: gadget: skip Set/Clear Halt when invalid") adds a check to return early depending on DWC3_EP_STALL is set or not, prevent sending the ep halt command to HW endpoint to do CLEAR_FEATURE(ENDPOINT_HALT) request. This was to workaround the issue for macOS where the device hangs from sending DWC3 clear stall command. In USB 3.1 spec, 9.4.5, CLEAR_FEATURE(ENDPOINT_HALT) request always results in the data sequence being reinitialized to zero regardless whether the endpoint has been halted or not. Some device class depends on this feature for its protocol. For instance, in mass storage class, there is MSC reset protocol that does CLEAR_FEATURE(ENDPOINT_HALT) on bulk endpoints. This protocol reinitializes the data sequence and ensures that whatever pending data requested from previous CBW will be reset. Otherwise this will cause a hang as the device can wait for the data with the wrong sequence number from the previous CBW. We found this failure in USB CV: MSC Error Recovery Test with f_mass_storage. This patch fixes this issue by checking to see whether the set/halt ep call is a protocol call before early exit to make sure that set/clear halt endpoint command can go through if it is a device class protocol. Fixes: ffb80fc672c3 ("usb: dwc3: gadget: skip Set/Clear Halt when invalid") Signed-off-by: Thinh Nguyen <thinhn@xxxxxxxxxxxx> --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 93d98fb7215e..59385eadd8b4 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1442,7 +1442,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) unsigned transfer_in_flight; unsigned started; - if (dep->flags & DWC3_EP_STALL) + if (!protocol && (dep->flags & DWC3_EP_STALL)) return 0; if (dep->number > 1) @@ -1466,7 +1466,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) else dep->flags |= DWC3_EP_STALL; } else { - if (!(dep->flags & DWC3_EP_STALL)) + if (!protocol && !(dep->flags & DWC3_EP_STALL)) return 0; ret = dwc3_send_clear_stall_ep_cmd(dep); -- 2.11.0