diff options
author | Thinh Nguyen <Thinh.Nguyen@synopsys.com> | 2022-04-21 19:22:50 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-02-23 08:55:11 +0100 |
commit | 9273bd26b06d31cae0911c8405f69862db3bbc83 (patch) | |
tree | 9785c1f6523f8aa0b41a8d4eb070fc11876672e2 | |
parent | 92f7a10a2bfe01568e78113a685501f4bdeb07d7 (diff) | |
download | linux-stable-9273bd26b06d31cae0911c8405f69862db3bbc83.tar.gz linux-stable-9273bd26b06d31cae0911c8405f69862db3bbc83.tar.bz2 linux-stable-9273bd26b06d31cae0911c8405f69862db3bbc83.zip |
usb: dwc3: ep0: Don't prepare beyond Setup stage
[ Upstream commit c96683798e272366866a5c0ce3073c0b5a256db7 ]
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>
Stable-dep-of: 730e12fbec53 ("usb: dwc3: gadget: Handle EP0 request dequeuing properly")
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 2 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 29 |
2 files changed, 18 insertions, 13 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 34cb8662e129..624de23782b5 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -816,7 +816,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); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3a663d71d791..2afe6784f1df 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2473,6 +2473,23 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) 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 * disconnect, the SW needs to ensure that it sends "a DEPENDXFER @@ -2516,18 +2533,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) is_on = !!is_on; 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 |