* [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
2020-11-05 23:28 [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded Wesley Cheng
@ 2020-11-05 23:28 ` Wesley Cheng
0 siblings, 0 replies; 4+ messages in thread
From: Wesley Cheng @ 2020-11-05 23:28 UTC (permalink / raw)
To: balbi, gregkh, stern, Thinh.Nguyen
Cc: linux-kernel, linux-usb, jackp, Wesley Cheng
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>
---
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 5d879b7606d5..babf977cadc0 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2012,6 +2012,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.
@@ -2050,10 +2061,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;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded
@ 2020-12-29 23:05 Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting Wesley Cheng
0 siblings, 2 replies; 4+ messages in thread
From: Wesley Cheng @ 2020-12-29 23:05 UTC (permalink / raw)
To: balbi, gregkh; +Cc: linux-kernel, linux-usb, Wesley Cheng
Changes in v2:
- Modified logic for executing the runtime PM resume. Using a sychronous get
call to avoid race conditions.
During the following scenario, the DWC3 runtime suspend routine is blocked as
the connected flag is still true:
1. Enumerate device w/ host.
2. Gadget is unbinded
- echo "" > /sys/kernel/config/usb_gadget/g1/UDC
3. Disconnect the USB cable (VBUS low)
4. No dwc3_gadget_disconnect_interrupt() seen (since controller is
halted from step#1)
5. Runtime PM autosuspend fails due to "dwc->connected" being true
(cleared in dwc3_gadget_disconnect_interrupt())
6. Gadget binded
- echo udc_name > /sys/kernel/config/usb_gadget/g1/UDC
7. No runtime suspend until cable is plugged in and out
Technically, for device initiated disconnects, there is no active session/link
with the host, so the DWC3 controller should be allowed to go into a low power
state. Also, we need to now consider when re-binding the UDC,
dwc3_gadget_set_speed() is executed before dwc3_gadget_pullup(), so if the DWC3
controller is suspended/disabled, while accessing the DCFG, that could result in
bus timeouts, etc... Change the dwc3_gadget_set_speed() to save the speed
being requested, and program it during dwc3_gadget_run_stop(), which is executed
during PM runtime resume. If not, previous setting will be overridden as we
execute a DWC3 controller reset during PM runtime resume.
Wesley Cheng (2):
usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
usb: dwc3: gadget: Preserve UDC max speed setting
drivers/usb/dwc3/core.h | 1 +
drivers/usb/dwc3/gadget.c | 121 ++++++++++++++++++++++----------------
2 files changed, 71 insertions(+), 51 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded
2020-12-29 23:05 [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded Wesley Cheng
@ 2020-12-29 23:05 ` Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting Wesley Cheng
1 sibling, 0 replies; 4+ messages in thread
From: Wesley Cheng @ 2020-12-29 23:05 UTC (permalink / raw)
To: balbi, gregkh; +Cc: linux-kernel, linux-usb, Wesley Cheng
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>
---
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 5d879b7606d5..babf977cadc0 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2012,6 +2012,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.
@@ -2050,10 +2061,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;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting
2020-12-29 23:05 [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Wesley Cheng
@ 2020-12-29 23:05 ` Wesley Cheng
1 sibling, 0 replies; 4+ messages in thread
From: Wesley Cheng @ 2020-12-29 23:05 UTC (permalink / raw)
To: balbi, gregkh; +Cc: linux-kernel, linux-usb, Wesley Cheng
The USB gadget/UDC driver can restrict the DWC3 controller speed using
dwc3_gadget_set_speed(). Store this setting into a variable, in order for
this setting to persist across controller resets due to runtime PM.
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
---
drivers/usb/dwc3/core.h | 1 +
drivers/usb/dwc3/gadget.c | 108 ++++++++++++++++++++------------------
2 files changed, 58 insertions(+), 51 deletions(-)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2f04b3e42bf1..390d3deef0ba 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1119,6 +1119,7 @@ struct dwc3 {
u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
+ u32 gadget_max_speed;
u32 ip;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index babf977cadc0..c145da1d8ba5 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1941,6 +1941,61 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
}
}
+static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+ /*
+ * WORKAROUND: DWC3 revision < 2.20a have an issue
+ * which would cause metastability state on Run/Stop
+ * bit if we try to force the IP to USB2-only mode.
+ *
+ * Because of that, we cannot configure the IP to any
+ * speed other than the SuperSpeed
+ *
+ * Refers to:
+ *
+ * STAR#9000525659: Clock Domain Crossing on DCTL in
+ * USB 2.0 Mode
+ */
+ if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
+ !dwc->dis_metastability_quirk) {
+ reg |= DWC3_DCFG_SUPERSPEED;
+ } else {
+ switch (dwc->gadget_max_speed) {
+ case USB_SPEED_LOW:
+ reg |= DWC3_DCFG_LOWSPEED;
+ break;
+ case USB_SPEED_FULL:
+ reg |= DWC3_DCFG_FULLSPEED;
+ break;
+ case USB_SPEED_HIGH:
+ reg |= DWC3_DCFG_HIGHSPEED;
+ break;
+ case USB_SPEED_SUPER:
+ reg |= DWC3_DCFG_SUPERSPEED;
+ break;
+ case USB_SPEED_SUPER_PLUS:
+ if (DWC3_IP_IS(DWC3))
+ reg |= DWC3_DCFG_SUPERSPEED;
+ else
+ reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ break;
+ default:
+ dev_err(dwc->dev, "invalid speed (%d)\n", dwc->gadget_max_speed);
+
+ if (DWC3_IP_IS(DWC3))
+ reg |= DWC3_DCFG_SUPERSPEED;
+ else
+ reg |= DWC3_DCFG_SUPERSPEED_PLUS;
+ }
+ }
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
u32 reg;
@@ -1963,6 +2018,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
if (dwc->has_hibernation)
reg |= DWC3_DCTL_KEEP_CONNECT;
+ __dwc3_gadget_set_speed(dwc);
dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
@@ -2325,59 +2381,9 @@ static void dwc3_gadget_set_speed(struct usb_gadget *g,
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
- u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
- reg = dwc3_readl(dwc->regs, DWC3_DCFG);
- reg &= ~(DWC3_DCFG_SPEED_MASK);
-
- /*
- * WORKAROUND: DWC3 revision < 2.20a have an issue
- * which would cause metastability state on Run/Stop
- * bit if we try to force the IP to USB2-only mode.
- *
- * Because of that, we cannot configure the IP to any
- * speed other than the SuperSpeed
- *
- * Refers to:
- *
- * STAR#9000525659: Clock Domain Crossing on DCTL in
- * USB 2.0 Mode
- */
- if (DWC3_VER_IS_PRIOR(DWC3, 220A) &&
- !dwc->dis_metastability_quirk) {
- reg |= DWC3_DCFG_SUPERSPEED;
- } else {
- switch (speed) {
- case USB_SPEED_LOW:
- reg |= DWC3_DCFG_LOWSPEED;
- break;
- case USB_SPEED_FULL:
- reg |= DWC3_DCFG_FULLSPEED;
- break;
- case USB_SPEED_HIGH:
- reg |= DWC3_DCFG_HIGHSPEED;
- break;
- case USB_SPEED_SUPER:
- reg |= DWC3_DCFG_SUPERSPEED;
- break;
- case USB_SPEED_SUPER_PLUS:
- if (DWC3_IP_IS(DWC3))
- reg |= DWC3_DCFG_SUPERSPEED;
- else
- reg |= DWC3_DCFG_SUPERSPEED_PLUS;
- break;
- default:
- dev_err(dwc->dev, "invalid speed (%d)\n", speed);
-
- if (DWC3_IP_IS(DWC3))
- reg |= DWC3_DCFG_SUPERSPEED;
- else
- reg |= DWC3_DCFG_SUPERSPEED_PLUS;
- }
- }
- dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
+ dwc->gadget_max_speed = speed;
spin_unlock_irqrestore(&dwc->lock, flags);
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-12-29 23:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-29 23:05 [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Wesley Cheng
2020-12-29 23:05 ` [PATCH v2 2/2] usb: dwc3: gadget: Preserve UDC max speed setting Wesley Cheng
-- strict thread matches above, loose matches on Subject: below --
2020-11-05 23:28 [PATCH v2 0/2] Allow DWC3 runtime suspend if UDC is unbinded Wesley Cheng
2020-11-05 23:28 ` [PATCH v2 1/2] usb: dwc3: gadget: Allow runtime suspend if UDC unbinded Wesley Cheng
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.