]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
usb: dwc3: gadget: Fix START_TRANSFER link state check
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Tue, 20 Apr 2021 02:11:12 +0000 (19:11 -0700)
committerStefan Bader <stefan.bader@canonical.com>
Wed, 19 May 2021 08:59:50 +0000 (10:59 +0200)
BugLink: https://bugs.launchpad.net/bugs/1928825
commit c560e76319a94a3b9285bc426c609903408e4826 upstream.

The START_TRANSFER command needs to be executed while in ON/U0 link
state (with an exception during register initialization). Don't use
dwc->link_state to check this since the driver only tracks the link
state when the link state change interrupt is enabled. Check the link
state from DSTS register instead.

Note that often the host already brings the device out of low power
before it sends/requests the next transfer. So, the user won't see any
issue when the device starts transfer then. This issue is more
noticeable in cases when the device delays starting transfer, which can
happen during delayed control status after the host put the device in
low power.

Fixes: 799e9dc82968 ("usb: dwc3: gadget: conditionally disable Link State change events")
Cc: <stable@vger.kernel.org>
Acked-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/bcefaa9ecbc3e1936858c0baa14de6612960e909.1618884221.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
drivers/usb/dwc3/gadget.c

index aa520c343367c668c1a9edb0f884f0d43fb5fe63..af8efebfaf110302a70d3def6cb369374f396286 100644 (file)
@@ -304,13 +304,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
        }
 
        if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
-               int             needs_wakeup;
+               int link_state;
 
-               needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
-                               dwc->link_state == DWC3_LINK_STATE_U2 ||
-                               dwc->link_state == DWC3_LINK_STATE_U3);
-
-               if (unlikely(needs_wakeup)) {
+               link_state = dwc3_gadget_get_link_state(dwc);
+               if (link_state == DWC3_LINK_STATE_U1 ||
+                   link_state == DWC3_LINK_STATE_U2 ||
+                   link_state == DWC3_LINK_STATE_U3) {
                        ret = __dwc3_gadget_wakeup(dwc);
                        dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
                                        ret);
@@ -1862,6 +1861,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
        case DWC3_LINK_STATE_RESET:
        case DWC3_LINK_STATE_RX_DET:    /* in HS, means Early Suspend */
        case DWC3_LINK_STATE_U3:        /* in HS, means SUSPEND */
+       case DWC3_LINK_STATE_U2:        /* in HS, means Sleep (L1) */
+       case DWC3_LINK_STATE_U1:
        case DWC3_LINK_STATE_RESUME:
                break;
        default: