Oliver Neukum eccafb
From c96683798e272366866a5c0ce3073c0b5a256db7 Mon Sep 17 00:00:00 2001
Oliver Neukum eccafb
From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Oliver Neukum eccafb
Date: Thu, 21 Apr 2022 19:22:50 -0700
Oliver Neukum eccafb
Subject: [PATCH] usb: dwc3: ep0: Don't prepare beyond Setup stage
Oliver Neukum eccafb
Git-commit: c96683798e272366866a5c0ce3073c0b5a256db7
Oliver Neukum eccafb
References: git-fixes
Oliver Neukum eccafb
Patch-mainline: v5.19-rc1
Oliver Neukum eccafb
Oliver Neukum eccafb
Since we can't guarantee that the host won't send new Setup packet
Oliver Neukum eccafb
before going through the device-initiated disconnect, don't prepare
Oliver Neukum eccafb
beyond the Setup stage and keep the device in EP0_SETUP_PHASE. This
Oliver Neukum eccafb
ensures that the device-initated disconnect sequence can go through
Oliver Neukum eccafb
gracefully. Note that the controller won't service the End Transfer
Oliver Neukum eccafb
command if it can't DMA out the Setup packet.
Oliver Neukum eccafb
Oliver Neukum eccafb
Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Oliver Neukum eccafb
Link: https://lore.kernel.org/r/6bacec56ecabb2c6e49a09cedfcac281fdc97de0.1650593829.git.Thinh.Nguyen@synopsys.com
Oliver Neukum eccafb
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Oliver Neukum eccafb
Signed-off-by: Oliver Neukum <oneukum@suse.com>
Oliver Neukum eccafb
---
Oliver Neukum eccafb
 drivers/usb/dwc3/ep0.c    |  2 +-
Oliver Neukum eccafb
 drivers/usb/dwc3/gadget.c | 29 +++++++++++++++++------------
Oliver Neukum eccafb
 2 files changed, 18 insertions(+), 13 deletions(-)
Oliver Neukum eccafb
Oliver Neukum eccafb
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
Oliver Neukum eccafb
index aa8476da222d..6615f641b34f 100644
Oliver Neukum eccafb
--- a/drivers/usb/dwc3/ep0.c
Oliver Neukum eccafb
+++ b/drivers/usb/dwc3/ep0.c
Oliver Neukum eccafb
@@ -813,7 +813,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
Oliver Neukum eccafb
 	int ret = -EINVAL;
Oliver Neukum eccafb
 	u32 len;
Oliver Neukum eccafb
 
Oliver Neukum eccafb
-	if (!dwc->gadget_driver)
Oliver Neukum eccafb
+	if (!dwc->gadget_driver || !dwc->connected)
Oliver Neukum eccafb
 		goto out;
Oliver Neukum eccafb
 
Oliver Neukum eccafb
 	trace_dwc3_ctrl_req(ctrl);
Oliver Neukum eccafb
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
Oliver Neukum eccafb
index 3c0a6c83ea43..5e3311e3cc16 100644
Oliver Neukum eccafb
--- a/drivers/usb/dwc3/gadget.c
Oliver Neukum eccafb
+++ b/drivers/usb/dwc3/gadget.c
Oliver Neukum eccafb
@@ -2514,6 +2514,23 @@ static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc)
Oliver Neukum eccafb
 	spin_lock_irqsave(&dwc->lock, flags);
Oliver Neukum eccafb
 	dwc->connected = false;
Oliver Neukum eccafb
 
Oliver Neukum eccafb
+	/*
Oliver Neukum eccafb
+	 * Per databook, when we want to stop the gadget, if a control transfer
Oliver Neukum eccafb
+	 * is still in process, complete it and get the core into setup phase.
Oliver Neukum eccafb
+	 */
Oliver Neukum eccafb
+	if (dwc->ep0state != EP0_SETUP_PHASE) {
Oliver Neukum eccafb
+		int ret;
Oliver Neukum eccafb
+
Oliver Neukum eccafb
+		reinit_completion(&dwc->ep0_in_setup);
Oliver Neukum eccafb
+
Oliver Neukum eccafb
+		spin_unlock_irqrestore(&dwc->lock, flags);
Oliver Neukum eccafb
+		ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
Oliver Neukum eccafb
+				msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
Oliver Neukum eccafb
+		spin_lock_irqsave(&dwc->lock, flags);
Oliver Neukum eccafb
+		if (ret == 0)
Oliver Neukum eccafb
+			dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
Oliver Neukum eccafb
+	}
Oliver Neukum eccafb
+
Oliver Neukum eccafb
 	/*
Oliver Neukum eccafb
 	 * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
Oliver Neukum eccafb
 	 * Section 4.1.8 Table 4-7, it states that for a device-initiated
Oliver Neukum eccafb
@@ -2546,18 +2563,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
Oliver Neukum eccafb
 		return 0;
Oliver Neukum eccafb
 
Oliver Neukum eccafb
 	dwc->softconnect = is_on;
Oliver Neukum eccafb
-	/*
Oliver Neukum eccafb
-	 * Per databook, when we want to stop the gadget, if a control transfer
Oliver Neukum eccafb
-	 * is still in process, complete it and get the core into setup phase.
Oliver Neukum eccafb
-	 */
Oliver Neukum eccafb
-	if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) {
Oliver Neukum eccafb
-		reinit_completion(&dwc->ep0_in_setup);
Oliver Neukum eccafb
-
Oliver Neukum eccafb
-		ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
Oliver Neukum eccafb
-				msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
Oliver Neukum eccafb
-		if (ret == 0)
Oliver Neukum eccafb
-			dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
Oliver Neukum eccafb
-	}
Oliver Neukum eccafb
 
Oliver Neukum eccafb
 	/*
Oliver Neukum eccafb
 	 * Avoid issuing a runtime resume if the device is already in the
Oliver Neukum eccafb
-- 
Oliver Neukum eccafb
2.40.1
Oliver Neukum eccafb