stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch
@ 2021-08-12 17:16 Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 1/7] usb: dwc3: Stop active transfers before halting the controller Sam Protsenko
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

This patch series pulls the patch ae7e86108b12 ("usb: dwc3: Stop active
transfers before halting the controller") and some fixes/dependencies
for that patch. It's needed to fix the actual panic I observed when
doing role switch with USB2.0 Dual Role Device controller. Next
procedure can be used to reproduce the panic:

1. Boot in peripheral role
2. Configure RNDIS gadget, perform ping, stop ping
3. Switch to host role
4. Kernel panic occurs

Kernel panic happens because gadget->udc->driver->disconnect() (which
is configfs_composite_disconnect()) is not called from
usb_gadget_disconnect() function, due to timeout condition in
dwc3_gadget_run_stop(), which leads to not called rndis_disable(). And
although previously created endpoints are not valid anymore,
eth_start_xmit() gets called and tries to use those, which leads to
invalid memory access. This patch fixes timeout condition, so next
call chain doesn't fail anymore, and RNDIS uninitialized properly on
gadget to host role switch:

<<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>
    usb_role_switch_set_role()
        v
    dwc3_usb_role_switch_set()
        v
    dwc3_set_mode()
        v
    __dwc3_set_mode()
        v
    dwc3_gadget_exit()
        v
    usb_del_gadget_udc()
        v
    usb_gadget_remove_driver()
        v
    usb_gadget_disconnect()
        v
    // THIS IS NOT CALLED because gadget->ops->pullup() =
    // dwc3_gadget_pullup() returns -ETIMEDOUT (-110)
    gadget->udc->driver->disconnect()
    // = configfs_composite_disconnect()
        v
    composite_disconnect()
        v
    reset_config()
        v
    foreach (f : function) : f->disable
        v
    rndis_disable()
        v
    gether_disconnect()
        v
    usb_ep_disable(),
    dev->port_usb = NULL
<<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>

Most of these patches are already applied in stable-5.10.

Wesley Cheng (7):
  usb: dwc3: Stop active transfers before halting the controller
  usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
  usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
  usb: dwc3: gadget: Prevent EP queuing while stopping transfers
  usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
  usb: dwc3: gadget: Disable gadget IRQ during pullup disable
  usb: dwc3: gadget: Avoid runtime resume if disabling pullup

 drivers/usb/dwc3/ep0.c    |   2 +-
 drivers/usb/dwc3/gadget.c | 118 +++++++++++++++++++++++++++++++-------
 2 files changed, 99 insertions(+), 21 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5.4 1/7] usb: dwc3: Stop active transfers before halting the controller
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 2/7] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Sam Protsenko
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit ae7e86108b12351028fa7e8796a59f9b2d9e1774 ]

In the DWC3 databook, for a device initiated disconnect or bus reset, the
driver is required to send dependxfer commands for any pending transfers.
In addition, before the controller can move to the halted state, the SW
needs to acknowledge any pending events.  If the controller is not halted
properly, there is a chance the controller will continue accessing stale or
freed TRBs and buffers.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Reviewed-by: Thinh Nguyen <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
---
 drivers/usb/dwc3/ep0.c    |  2 +-
 drivers/usb/dwc3/gadget.c | 66 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 03b444f753aa..4f28122f1bb8 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -197,7 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 	int				ret;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	if (!dep->endpoint.desc) {
+	if (!dep->endpoint.desc || !dwc->pullups_connected) {
 		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
 				dep->name);
 		ret = -ESHUTDOWN;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 9cf66636b19d..94c430dcce5d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1511,7 +1511,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
 	struct dwc3		*dwc = dep->dwc;
 
-	if (!dep->endpoint.desc) {
+	if (!dep->endpoint.desc || !dwc->pullups_connected) {
 		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
 				dep->name);
 		return -ESHUTDOWN;
@@ -1931,6 +1931,21 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
 	return 0;
 }
 
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 2; epnum < dwc->num_eps; epnum++) {
+		struct dwc3_ep *dep;
+
+		dep = dwc->eps[epnum];
+		if (!dep)
+			continue;
+
+		dwc3_remove_requests(dwc, dep);
+	}
+}
+
 static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 {
 	u32			reg;
@@ -1976,6 +1991,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 	return 0;
 }
 
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
+static void __dwc3_gadget_stop(struct dwc3 *dwc);
+
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 {
 	struct dwc3		*dwc = gadget_to_dwc(g);
@@ -1999,7 +2017,46 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 		}
 	}
 
+	/*
+	 * Synchronize any pending event handling before executing the controller
+	 * halt routine.
+	 */
+	if (!is_on) {
+		dwc3_gadget_disable_irq(dwc);
+		synchronize_irq(dwc->irq_gadget);
+	}
+
 	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (!is_on) {
+		u32 count;
+
+		/*
+		 * In the Synopsis 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
+		 * command for any active transfers" before clearing the RunStop
+		 * bit.
+		 */
+		dwc3_stop_active_transfers(dwc);
+		__dwc3_gadget_stop(dwc);
+
+		/*
+		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+		 * Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the
+		 * "software needs to acknowledge the events that are generated
+		 * (by writing to GEVNTCOUNTn) while it is waiting for this bit
+		 * to be set to '1'."
+		 */
+		count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
+		count &= DWC3_GEVNTCOUNT_MASK;
+		if (count > 0) {
+			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+			dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
+						dwc->ev_buf->length;
+		}
+	}
+
 	ret = dwc3_gadget_run_stop(dwc, is_on, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
@@ -3038,6 +3095,13 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 	}
 
 	dwc3_reset_gadget(dwc);
+	/*
+	 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
+	 * Section 4.1.2 Table 4-2, it states that during a USB reset, the SW
+	 * needs to ensure that it sends "a DEPENDXFER command for any active
+	 * transfers."
+	 */
+	dwc3_stop_active_transfers(dwc);
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 2/7] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 1/7] usb: dwc3: Stop active transfers before halting the controller Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 3/7] usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup Sam Protsenko
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit 77adb8bdf4227257e26b7ff67272678e66a0b250 ]

The DWC3 runtime suspend routine checks for the USB connected parameter to
determine if the controller can enter into a low power state.  The
connected state is only set to false after receiving a disconnect event.
However, in the case of a device initiated disconnect (i.e. UDC unbind),
the controller is halted and a disconnect event is never generated.  Set
the connected flag to false if issuing a device initiated disconnect to
allow the controller to be suspended.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1609283136-22140-2-git-send-email-wcheng@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 94c430dcce5d..bc655d637b86 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2017,6 +2017,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 		}
 	}
 
+	/*
+	 * Check the return value for successful resume, or error.  For a
+	 * successful resume, the DWC3 runtime PM resume routine will handle
+	 * the run stop sequence, so avoid duplicate operations here.
+	 */
+	ret = pm_runtime_get_sync(dwc->dev);
+	if (!ret || ret < 0) {
+		pm_runtime_put(dwc->dev);
+		return 0;
+	}
+
 	/*
 	 * Synchronize any pending event handling before executing the controller
 	 * halt routine.
@@ -2055,10 +2066,12 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 			dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
 						dwc->ev_buf->length;
 		}
+		dwc->connected = false;
 	}
 
 	ret = dwc3_gadget_run_stop(dwc, is_on, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
+	pm_runtime_put(dwc->dev);
 
 	return ret;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 3/7] usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 1/7] usb: dwc3: Stop active transfers before halting the controller Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 2/7] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 4/7] usb: dwc3: gadget: Prevent EP queuing while stopping transfers Sam Protsenko
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit a1383b3537a7bea1c213baa7878ccc4ecf4413b5 ]

usb_gadget_deactivate/usb_gadget_activate does not execute the UDC start
operation, which may leave EP0 disabled and event IRQs disabled when
re-activating the function. Move the enabling/disabling of USB EP0 and
device event IRQs to be performed in the pullup routine.

Fixes: ae7e86108b12 ("usb: dwc3: Stop active transfers before halting the controller")
Tested-by: Michael Tretter <m.tretter@pengutronix.de>
Cc: stable <stable@vger.kernel.org>
Reported-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1609282837-21666-1-git-send-email-wcheng@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index bc655d637b86..e242174321d1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1993,6 +1993,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
 
 static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
 static void __dwc3_gadget_stop(struct dwc3 *dwc);
+static int __dwc3_gadget_start(struct dwc3 *dwc);
 
 static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 {
@@ -2067,6 +2068,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 						dwc->ev_buf->length;
 		}
 		dwc->connected = false;
+	} else {
+		__dwc3_gadget_start(dwc);
 	}
 
 	ret = dwc3_gadget_run_stop(dwc, is_on, false);
@@ -2244,10 +2247,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
 	}
 
 	dwc->gadget_driver	= driver;
-
-	if (pm_runtime_active(dwc->dev))
-		__dwc3_gadget_start(dwc);
-
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
@@ -2273,13 +2272,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dwc->lock, flags);
-
-	if (pm_runtime_suspended(dwc->dev))
-		goto out;
-
-	__dwc3_gadget_stop(dwc);
-
-out:
 	dwc->gadget_driver	= NULL;
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 4/7] usb: dwc3: gadget: Prevent EP queuing while stopping transfers
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
                   ` (2 preceding siblings ...)
  2021-08-12 17:16 ` [PATCH 5.4 3/7] usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 5/7] usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable Sam Protsenko
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit f09ddcfcb8c569675066337adac2ac205113471f ]

In the situations where the DWC3 gadget stops active transfers, once
calling the dwc3_gadget_giveback(), there is a chance where a function
driver can queue a new USB request in between the time where the dwc3
lock has been released and re-aquired.  This occurs after we've already
issued an ENDXFER command.  When the stop active transfers continues
to remove USB requests from all dep lists, the newly added request will
also be removed, while controller still has an active TRB for it.
This can lead to the controller accessing an unmapped memory address.

Fix this by ensuring parameters to prevent EP queuing are set before
calling the stop active transfers API.

Fixes: ae7e86108b12 ("usb: dwc3: Stop active transfers before halting the controller")
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1615507142-23097-1-git-send-email-wcheng@codeaurora.org
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index e242174321d1..8702035d08f1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -746,8 +746,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
 	trace_dwc3_gadget_ep_disable(dep);
 
-	dwc3_remove_requests(dwc, dep);
-
 	/* make sure HW endpoint isn't stalled */
 	if (dep->flags & DWC3_EP_STALL)
 		__dwc3_gadget_ep_set_halt(dep, 0, false);
@@ -766,6 +764,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 		dep->endpoint.desc = NULL;
 	}
 
+	dwc3_remove_requests(dwc, dep);
+
 	return 0;
 }
 
@@ -1511,7 +1511,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
 	struct dwc3		*dwc = dep->dwc;
 
-	if (!dep->endpoint.desc || !dwc->pullups_connected) {
+	if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
 		dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
 				dep->name);
 		return -ESHUTDOWN;
@@ -2043,6 +2043,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 	if (!is_on) {
 		u32 count;
 
+		dwc->connected = false;
 		/*
 		 * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a
 		 * Section 4.1.8 Table 4-7, it states that for a device-initiated
@@ -2067,7 +2068,6 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 			dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) %
 						dwc->ev_buf->length;
 		}
-		dwc->connected = false;
 	} else {
 		__dwc3_gadget_start(dwc);
 	}
@@ -3057,8 +3057,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
 	u32			reg;
 
-	dwc->connected = true;
-
 	/*
 	 * Ideally, dwc3_reset_gadget() would trigger the function
 	 * drivers to stop any active transfers through ep disable.
@@ -3107,6 +3105,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 	 * transfers."
 	 */
 	dwc3_stop_active_transfers(dwc);
+	dwc->connected = true;
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
 	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 5/7] usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
                   ` (3 preceding siblings ...)
  2021-08-12 17:16 ` [PATCH 5.4 4/7] usb: dwc3: gadget: Prevent EP queuing while stopping transfers Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 6/7] usb: dwc3: gadget: Disable gadget IRQ during pullup disable Sam Protsenko
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit 5aef629704ad4d983ecf5c8a25840f16e45b6d59 ]

Ensure that dep->flags are cleared until after stop active transfers
is completed.  Otherwise, the ENDXFER command will not be executed
during ep disable.

Fixes: f09ddcfcb8c5 ("usb: dwc3: gadget: Prevent EP queuing while stopping transfers")
Cc: stable <stable@vger.kernel.org>
Reported-and-tested-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1616610664-16495-1-git-send-email-wcheng@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8702035d08f1..5f2e4a2638f5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -754,10 +754,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 	reg &= ~DWC3_DALEPENA_EP(dep->number);
 	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
 
-	dep->stream_capable = false;
-	dep->type = 0;
-	dep->flags = 0;
-
 	/* Clear out the ep descriptors for non-ep0 */
 	if (dep->number > 1) {
 		dep->endpoint.comp_desc = NULL;
@@ -766,6 +762,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
 	dwc3_remove_requests(dwc, dep);
 
+	dep->stream_capable = false;
+	dep->type = 0;
+	dep->flags = 0;
+
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 6/7] usb: dwc3: gadget: Disable gadget IRQ during pullup disable
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
                   ` (4 preceding siblings ...)
  2021-08-12 17:16 ` [PATCH 5.4 5/7] usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-12 17:16 ` [PATCH 5.4 7/7] usb: dwc3: gadget: Avoid runtime resume if disabling pullup Sam Protsenko
  2021-08-13  8:49 ` [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Greg Kroah-Hartman
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit 8212937305f84ef73ea81036dafb80c557583d4b ]

Current sequence utilizes dwc3_gadget_disable_irq() alongside
synchronize_irq() to ensure that no further DWC3 events are generated.
However, the dwc3_gadget_disable_irq() API only disables device
specific events.  Endpoint events can still be generated.  Briefly
disable the interrupt line, so that the cleanup code can run to
prevent device and endpoint events. (i.e. __dwc3_gadget_stop() and
dwc3_stop_active_transfers() respectively)

Without doing so, it can lead to both the interrupt handler and the
pullup disable routine both writing to the GEVNTCOUNT register, which
will cause an incorrect count being read from future interrupts.

Fixes: ae7e86108b12 ("usb: dwc3: Stop active transfers before halting the controller")
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1621571037-1424-1-git-send-email-wcheng@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5f2e4a2638f5..78a4b9e438b7 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2030,13 +2030,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 	}
 
 	/*
-	 * Synchronize any pending event handling before executing the controller
-	 * halt routine.
+	 * Synchronize and disable any further event handling while controller
+	 * is being enabled/disabled.
 	 */
-	if (!is_on) {
-		dwc3_gadget_disable_irq(dwc);
-		synchronize_irq(dwc->irq_gadget);
-	}
+	disable_irq(dwc->irq_gadget);
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
@@ -2074,6 +2071,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 
 	ret = dwc3_gadget_run_stop(dwc, is_on, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
+	enable_irq(dwc->irq_gadget);
+
 	pm_runtime_put(dwc->dev);
 
 	return ret;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5.4 7/7] usb: dwc3: gadget: Avoid runtime resume if disabling pullup
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
                   ` (5 preceding siblings ...)
  2021-08-12 17:16 ` [PATCH 5.4 6/7] usb: dwc3: gadget: Disable gadget IRQ during pullup disable Sam Protsenko
@ 2021-08-12 17:16 ` Sam Protsenko
  2021-08-13  8:49 ` [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Greg Kroah-Hartman
  7 siblings, 0 replies; 9+ messages in thread
From: Sam Protsenko @ 2021-08-12 17:16 UTC (permalink / raw)
  To: Greg Kroah-Hartman; +Cc: stable, Wesley Cheng

From: Wesley Cheng <wcheng@codeaurora.org>

[ Upstream commit cb10f68ad8150f243964b19391711aaac5e8ff42 ]

If the device is already in the runtime suspended state, any call to
the pullup routine will issue a runtime resume on the DWC3 core
device.  If the USB gadget is disabling the pullup, then avoid having
to issue a runtime resume, as DWC3 gadget has already been
halted/stopped.

This fixes an issue where the following condition occurs:

usb_gadget_remove_driver()
-->usb_gadget_disconnect()
 -->dwc3_gadget_pullup(0)
  -->pm_runtime_get_sync() -> ret = 0
  -->pm_runtime_put() [async]
-->usb_gadget_udc_stop()
 -->dwc3_gadget_stop()
  -->dwc->gadget_driver = NULL
...

dwc3_suspend_common()
-->dwc3_gadget_suspend()
 -->DWC3 halt/stop routine skipped, driver_data == NULL

This leads to a situation where the DWC3 gadget is not properly
stopped, as the runtime resume would have re-enabled EP0 and event
interrupts, and since we avoided the DWC3 gadget suspend, these
resources were never disabled.

Fixes: 77adb8bdf422 ("usb: dwc3: gadget: Allow runtime suspend if UDC unbinded")
Cc: stable <stable@vger.kernel.org>
Acked-by: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Link: https://lore.kernel.org/r/1628058245-30692-1-git-send-email-wcheng@codeaurora.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/dwc3/gadget.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 78a4b9e438b7..8a3752fcf7b4 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2018,6 +2018,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 		}
 	}
 
+	/*
+	 * Avoid issuing a runtime resume if the device is already in the
+	 * suspended state during gadget disconnect.  DWC3 gadget was already
+	 * halted/stopped during runtime suspend.
+	 */
+	if (!is_on) {
+		pm_runtime_barrier(dwc->dev);
+		if (pm_runtime_suspended(dwc->dev))
+			return 0;
+	}
+
 	/*
 	 * Check the return value for successful resume, or error.  For a
 	 * successful resume, the DWC3 runtime PM resume routine will handle
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch
  2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
                   ` (6 preceding siblings ...)
  2021-08-12 17:16 ` [PATCH 5.4 7/7] usb: dwc3: gadget: Avoid runtime resume if disabling pullup Sam Protsenko
@ 2021-08-13  8:49 ` Greg Kroah-Hartman
  7 siblings, 0 replies; 9+ messages in thread
From: Greg Kroah-Hartman @ 2021-08-13  8:49 UTC (permalink / raw)
  To: Sam Protsenko; +Cc: stable, Wesley Cheng

On Thu, Aug 12, 2021 at 08:16:45PM +0300, Sam Protsenko wrote:
> This patch series pulls the patch ae7e86108b12 ("usb: dwc3: Stop active
> transfers before halting the controller") and some fixes/dependencies
> for that patch. It's needed to fix the actual panic I observed when
> doing role switch with USB2.0 Dual Role Device controller. Next
> procedure can be used to reproduce the panic:
> 
> 1. Boot in peripheral role
> 2. Configure RNDIS gadget, perform ping, stop ping
> 3. Switch to host role
> 4. Kernel panic occurs
> 
> Kernel panic happens because gadget->udc->driver->disconnect() (which
> is configfs_composite_disconnect()) is not called from
> usb_gadget_disconnect() function, due to timeout condition in
> dwc3_gadget_run_stop(), which leads to not called rndis_disable(). And
> although previously created endpoints are not valid anymore,
> eth_start_xmit() gets called and tries to use those, which leads to
> invalid memory access. This patch fixes timeout condition, so next
> call chain doesn't fail anymore, and RNDIS uninitialized properly on
> gadget to host role switch:
> 
> <<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>
>     usb_role_switch_set_role()
>         v
>     dwc3_usb_role_switch_set()
>         v
>     dwc3_set_mode()
>         v
>     __dwc3_set_mode()
>         v
>     dwc3_gadget_exit()
>         v
>     usb_del_gadget_udc()
>         v
>     usb_gadget_remove_driver()
>         v
>     usb_gadget_disconnect()
>         v
>     // THIS IS NOT CALLED because gadget->ops->pullup() =
>     // dwc3_gadget_pullup() returns -ETIMEDOUT (-110)
>     gadget->udc->driver->disconnect()
>     // = configfs_composite_disconnect()
>         v
>     composite_disconnect()
>         v
>     reset_config()
>         v
>     foreach (f : function) : f->disable
>         v
>     rndis_disable()
>         v
>     gether_disconnect()
>         v
>     usb_ep_disable(),
>     dev->port_usb = NULL
> <<<<<<<<<<<<<<<<<<<< cut here >>>>>>>>>>>>>>>>>>>
> 
> Most of these patches are already applied in stable-5.10.
> 
> Wesley Cheng (7):
>   usb: dwc3: Stop active transfers before halting the controller
>   usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
>   usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup
>   usb: dwc3: gadget: Prevent EP queuing while stopping transfers
>   usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
>   usb: dwc3: gadget: Disable gadget IRQ during pullup disable
>   usb: dwc3: gadget: Avoid runtime resume if disabling pullup
> 
>  drivers/usb/dwc3/ep0.c    |   2 +-
>  drivers/usb/dwc3/gadget.c | 118 +++++++++++++++++++++++++++++++-------
>  2 files changed, 99 insertions(+), 21 deletions(-)
> 
> -- 
> 2.30.2

Now queued up.  In the future, please put your own signed-off-by on
these patches, as you were forwarding them on to us.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-08-13  8:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-12 17:16 [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 1/7] usb: dwc3: Stop active transfers before halting the controller Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 2/7] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 3/7] usb: dwc3: gadget: Restart DWC3 gadget when enabling pullup Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 4/7] usb: dwc3: gadget: Prevent EP queuing while stopping transfers Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 5/7] usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 6/7] usb: dwc3: gadget: Disable gadget IRQ during pullup disable Sam Protsenko
2021-08-12 17:16 ` [PATCH 5.4 7/7] usb: dwc3: gadget: Avoid runtime resume if disabling pullup Sam Protsenko
2021-08-13  8:49 ` [PATCH 5.4 0/7] usb: dwc3: Fix DRD role switch Greg Kroah-Hartman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).