Skip to content

Commit

Permalink
usb: dwc3: ep0: Don't prepare beyond Setup stage
Browse files Browse the repository at this point in the history
Since we can't guarantee that the host won't send new Setup packet
before going through the device-initiated disconnect, don't prepare
beyond the Setup stage and keep the device in EP0_SETUP_PHASE. This
ensures that the device-initated disconnect sequence can go through
gracefully. Note that the controller won't service the End Transfer
command if it can't DMA out the Setup packet.

Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/6bacec56ecabb2c6e49a09cedfcac281fdc97de0.1650593829.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Thinh Nguyen authored and Greg Kroah-Hartman committed May 5, 2022
1 parent 8f8034f commit c966837
Showing 2 changed files with 18 additions and 13 deletions.
2 changes: 1 addition & 1 deletion drivers/usb/dwc3/ep0.c
Original file line number Diff line number Diff line change
@@ -813,7 +813,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
int ret = -EINVAL;
u32 len;

if (!dwc->gadget_driver)
if (!dwc->gadget_driver || !dwc->connected)
goto out;

trace_dwc3_ctrl_req(ctrl);
29 changes: 17 additions & 12 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
@@ -2514,6 +2514,23 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
spin_lock_irqsave(&dwc->lock, flags);
dwc->connected = false;

/*
* Per databook, when we want to stop the gadget, if a control transfer
* is still in process, complete it and get the core into setup phase.
*/
if (dwc->ep0state != EP0_SETUP_PHASE) {
int ret;

reinit_completion(&dwc->ep0_in_setup);

spin_unlock_irqrestore(&dwc->lock, flags);
ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
spin_lock_irqsave(&dwc->lock, flags);
if (ret == 0)
dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
}

/*
* In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
* Section 4.1.8 Table 4-7, it states that for a device-initiated
@@ -2546,18 +2563,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return 0;

dwc->softconnect = is_on;
/*
* Per databook, when we want to stop the gadget, if a control transfer
* is still in process, complete it and get the core into setup phase.
*/
if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
reinit_completion(&dwc->ep0_in_setup);

ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
if (ret == 0)
dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
}

/*
* Avoid issuing a runtime resume if the device is already in the

0 comments on commit c966837

Please sign in to comment.