* [PATCH v2 1/3] usb: xhci-plat: add xhci-no-soft-retry-quirk device property
2026-08-29 20:04 [PATCH v2 0/3] usb: xhci: add xhci-no-soft-retry-quirk Matt Eaton via B4 Relay
@ 2026-08-29 20:04 ` Matt Eaton via B4 Relay
2026-08-30 15:02 ` Michal Pecio
2026-08-29 20:04 ` [PATCH v2 2/3] usb: dwc3: add xhci_no_soft_retry software property Matt Eaton via B4 Relay
2026-08-29 20:04 ` [PATCH v2 3/3] usb: dwc3: qcom: set xhci_no_soft_retry for IPQ4019 Matt Eaton via B4 Relay
2 siblings, 1 reply; 6+ messages in thread
From: Matt Eaton via B4 Relay @ 2026-08-29 20:04 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thinh Nguyen
Cc: linux-usb, linux-kernel, linux-arm-msm, Matt Eaton
From: Matt Eaton <linux@divinehawk.com>
XHCI_NO_SOFT_RETRY exists for hosts that can't perform xHCI 1.0 Soft Retry
correctly, but it's only reachable from xhci-pci, matched against two AMD
Promontory PCI ids. Platform hosts have no way to ask for it.
Add it as a device property, read in the same parent-walk block as
quirk-broken-port-ped and its neighbors. It's opt-in, so no existing
platform is affected. The following patches set it from the dwc3 core
on behalf of hardware known to need it, rather than from devicetree.
Needed for the Synopsys DWC3 on a Qualcomm IPQ4019, whose command ring
wedges when a Stop Endpoint command lands on a just-soft-retry-reset
endpoint -- exactly what unplugging a device mid-transfer triggers:
xhci-hcd xhci-hcd.1.auto: xHCI host not responding to stop endpoint command
xhci-hcd xhci-hcd.1.auto: xHCI host controller not responding, assume dead
xhci-hcd xhci-hcd.1.auto: HC died; cleaning up
Signed-off-by: Matt Eaton <linux@divinehawk.com>
---
drivers/usb/host/xhci-plat.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 6fd595f81a30..22057493f935 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -265,6 +265,9 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
if (device_property_read_bool(tmpdev, "quirk-broken-port-ped"))
xhci->quirks |= XHCI_BROKEN_PORT_PED;
+ if (device_property_read_bool(tmpdev, "xhci-no-soft-retry-quirk"))
+ xhci->quirks |= XHCI_NO_SOFT_RETRY;
+
if (device_property_read_bool(tmpdev, "xhci-sg-trb-cache-size-quirk"))
xhci->quirks |= XHCI_SG_TRB_CACHE_SIZE_QUIRK;
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/3] usb: xhci-plat: add xhci-no-soft-retry-quirk device property
2026-08-29 20:04 ` [PATCH v2 1/3] usb: xhci-plat: add xhci-no-soft-retry-quirk device property Matt Eaton via B4 Relay
@ 2026-08-30 15:02 ` Michal Pecio
0 siblings, 0 replies; 6+ messages in thread
From: Michal Pecio @ 2026-08-30 15:02 UTC (permalink / raw)
To: Matt Eaton via B4 Relay
Cc: linux, Mathias Nyman, Greg Kroah-Hartman, Thinh Nguyen,
linux-usb, linux-kernel, linux-arm-msm
On Sat, 29 Aug 2026 22:04:10 +0200, Matt Eaton via B4 Relay wrote:
> From: Matt Eaton <linux@divinehawk.com>
>
> XHCI_NO_SOFT_RETRY exists for hosts that can't perform xHCI 1.0 Soft Retry
> correctly, but it's only reachable from xhci-pci, matched against two AMD
> Promontory PCI ids. Platform hosts have no way to ask for it.
>
> Add it as a device property, read in the same parent-walk block as
> quirk-broken-port-ped and its neighbors. It's opt-in, so no existing
> platform is affected. The following patches set it from the dwc3 core
> on behalf of hardware known to need it, rather than from devicetree.
>
> Needed for the Synopsys DWC3 on a Qualcomm IPQ4019, whose command ring
> wedges when a Stop Endpoint command lands on a just-soft-retry-reset
> endpoint -- exactly what unplugging a device mid-transfer triggers:
>
> xhci-hcd xhci-hcd.1.auto: xHCI host not responding to stop endpoint command
> xhci-hcd xhci-hcd.1.auto: xHCI host controller not responding, assume dead
> xhci-hcd xhci-hcd.1.auto: HC died; cleaning up
Hi,
Does it still happen in current Linus tree aka upcoming v7.3-rc1?
Similar problem, limited to the specific case of disconnection from the
root hub, was found on Renesas PCIe controllers (it looked like some
internal power management interfering with operation). It seems to be
solved by avoiding Soft Retry on known-disconnected root hub ports.
Regards,
Michal
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/3] usb: dwc3: add xhci_no_soft_retry software property
2026-08-29 20:04 [PATCH v2 0/3] usb: xhci: add xhci-no-soft-retry-quirk Matt Eaton via B4 Relay
2026-08-29 20:04 ` [PATCH v2 1/3] usb: xhci-plat: add xhci-no-soft-retry-quirk device property Matt Eaton via B4 Relay
@ 2026-08-29 20:04 ` Matt Eaton via B4 Relay
2026-08-30 9:33 ` Matt Eaton
2026-08-29 20:04 ` [PATCH v2 3/3] usb: dwc3: qcom: set xhci_no_soft_retry for IPQ4019 Matt Eaton via B4 Relay
2 siblings, 1 reply; 6+ messages in thread
From: Matt Eaton via B4 Relay @ 2026-08-29 20:04 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thinh Nguyen
Cc: linux-usb, linux-kernel, linux-arm-msm, Matt Eaton
From: Matt Eaton <linux@divinehawk.com>
Some DWC3 instances cannot carry out xHCI 1.0 Soft Retry correctly. Add a
software property so a glue driver can say so on behalf of hardware it
recognises from its compatible, carry it into struct dwc3, and pass it on
to xhci-plat as an xhci-no-soft-retry-quirk swnode property alongside the
other xHCI properties dwc3_host_init() already sets.
Nothing sets it yet, so no platform changes behaviour.
Suggested-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Matt Eaton <linux@divinehawk.com>
---
drivers/usb/dwc3/core.c | 3 +++
drivers/usb/dwc3/core.h | 3 +++
drivers/usb/dwc3/glue.h | 3 +++
drivers/usb/dwc3/host.c | 5 ++++-
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fd5c2cd36c59..1acfad333271 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1694,6 +1694,9 @@ static void dwc3_get_software_properties(struct dwc3 *dwc,
if (properties->needs_full_reinit)
dwc->needs_full_reinit = true;
+ if (properties->xhci_no_soft_retry)
+ dwc->xhci_no_soft_retry = true;
+
dwc->gsbuscfg0_reqinfo = DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED;
if (properties->gsbuscfg0_reqinfo !=
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 608daeb7ef10..c8beca1b10b3 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1123,6 +1123,8 @@ struct dwc3_glue_ops {
* @usb2_gadget_lpm_disable: set to disable usb2 lpm for gadget
* @needs_full_reinit: set to indicate the core may lose power and need full
* initialization during system pm
+ * @xhci_no_soft_retry: set to indicate the xHCI cannot carry out Soft Retry
+ * correctly
* @disable_scramble_quirk: set if we enable the disable scramble quirk
* @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
* @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
@@ -1384,6 +1386,7 @@ struct dwc3 {
unsigned usb2_lpm_disable:1;
unsigned usb2_gadget_lpm_disable:1;
unsigned needs_full_reinit:1;
+ unsigned xhci_no_soft_retry:1;
unsigned disable_scramble_quirk:1;
unsigned u2exit_lfps_quirk:1;
diff --git a/drivers/usb/dwc3/glue.h b/drivers/usb/dwc3/glue.h
index d738e1739ae0..595880332d19 100644
--- a/drivers/usb/dwc3/glue.h
+++ b/drivers/usb/dwc3/glue.h
@@ -14,10 +14,13 @@
* @gsbuscfg0_reqinfo: Value to be programmed in the GSBUSCFG0.REQINFO field
* @needs_full_reinit: indicate the controller may not remain power during system
* pm and need full initialization
+ * @xhci_no_soft_retry: indicate the controller cannot carry out xHCI Soft
+ * Retry correctly
*/
struct dwc3_properties {
u32 gsbuscfg0_reqinfo;
unsigned needs_full_reinit:1;
+ unsigned xhci_no_soft_retry:1;
};
#define DWC3_DEFAULT_PROPERTIES ((struct dwc3_properties){ \
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index c5674161b2b0..e22a8dc5d090 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -130,7 +130,7 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
int dwc3_host_init(struct dwc3 *dwc)
{
- struct property_entry props[6];
+ struct property_entry props[7];
struct platform_device *xhci;
int ret, irq;
int prop_idx = 0;
@@ -186,6 +186,9 @@ int dwc3_host_init(struct dwc3 *dwc)
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 300A))
props[prop_idx++] = PROPERTY_ENTRY_BOOL("quirk-broken-port-ped");
+ if (dwc->xhci_no_soft_retry)
+ props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-no-soft-retry-quirk");
+
props[prop_idx++] = PROPERTY_ENTRY_U16("num-hc-interrupters",
dwc->num_hc_interrupters);
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v2 2/3] usb: dwc3: add xhci_no_soft_retry software property
2026-08-29 20:04 ` [PATCH v2 2/3] usb: dwc3: add xhci_no_soft_retry software property Matt Eaton via B4 Relay
@ 2026-08-30 9:33 ` Matt Eaton
0 siblings, 0 replies; 6+ messages in thread
From: Matt Eaton @ 2026-08-30 9:33 UTC (permalink / raw)
To: linux
Cc: Mathias Nyman, Greg Kroah-Hartman, Thinh Nguyen, linux-usb,
linux-kernel, linux-arm-msm
On Sat, Aug 29, 2026 at 10:04 PM Matt Eaton via B4 Relay
<devnull+linux.divinehawk.com@kernel.org> wrote:
>
> From: Matt Eaton <linux@divinehawk.com>
>
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index c5674161b2b0..e22a8dc5d090 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -130,7 +130,7 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
>
> int dwc3_host_init(struct dwc3 *dwc)
> {
> - struct property_entry props[6];
> + struct property_entry props[7];
I think this should be props[8] now as it should have been props[7]
before (latent bug?), with the last entry being NULL to satisfy
property_entries_dup(). I can do a patch v3.
Regards,
Matt
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 3/3] usb: dwc3: qcom: set xhci_no_soft_retry for IPQ4019
2026-08-29 20:04 [PATCH v2 0/3] usb: xhci: add xhci-no-soft-retry-quirk Matt Eaton via B4 Relay
2026-08-29 20:04 ` [PATCH v2 1/3] usb: xhci-plat: add xhci-no-soft-retry-quirk device property Matt Eaton via B4 Relay
2026-08-29 20:04 ` [PATCH v2 2/3] usb: dwc3: add xhci_no_soft_retry software property Matt Eaton via B4 Relay
@ 2026-08-29 20:04 ` Matt Eaton via B4 Relay
2 siblings, 0 replies; 6+ messages in thread
From: Matt Eaton via B4 Relay @ 2026-08-29 20:04 UTC (permalink / raw)
To: Mathias Nyman, Greg Kroah-Hartman, Thinh Nguyen
Cc: linux-usb, linux-kernel, linux-arm-msm, Matt Eaton
From: Matt Eaton <linux@divinehawk.com>
The dwc3 instances on IPQ4019 mishandle xHCI 1.0 Soft Retry. A Stop
Endpoint command that lands on a just-soft-retry-reset endpoint wedges
the command ring, and the stop-endpoint watchdog kills the host five
seconds later:
xhci-hcd xhci-hcd.1.auto: xHCI host not responding to stop endpoint command
xhci-hcd xhci-hcd.1.auto: xHCI host controller not responding, assume dead
xhci-hcd xhci-hcd.1.auto: HC died; cleaning up
Reproducible by unplugging a USB-tethered phone mid-transfer. The port
stays dead until the platform device is rebound. The controller itself
is alive throughout, hence the -110 timeout rather than -ENODEV.
Qualcomm's 4.4 vendor kernel predates Soft Retry entirely, so it has
never been able to hit this.
This is a property of the IP rather than of any board, so it is carried
as match data on the SoC compatible.
Both dwc3 nodes on this SoC share the compatible, so both get the quirk.
Measured on the usb2 instance, which drives the external port; the usb3
instance on the board under test hosts a soldered Bluetooth radio that
is never unplugged, so it cannot reach the trigger in normal use.
Suggested-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Signed-off-by: Matt Eaton <linux@divinehawk.com>
---
drivers/usb/dwc3/dwc3-qcom.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index ac68b4218b56..1edf75696e45 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -607,8 +607,19 @@ static struct dwc3_glue_ops dwc3_qcom_glue_ops = {
.pre_run_stop = dwc3_qcom_run_stop_notifier,
};
+/*
+ * The dwc3 instances on IPQ4019 mishandle xHCI Soft Retry: a Stop
+ * Endpoint command landing on a just-soft-retry-reset endpoint wedges the
+ * command ring and the host is killed by the stop-endpoint watchdog.
+ */
+static const struct dwc3_properties dwc3_qcom_ipq4019_properties = {
+ .gsbuscfg0_reqinfo = DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED,
+ .xhci_no_soft_retry = 1,
+};
+
static int dwc3_qcom_probe(struct platform_device *pdev)
{
+ const struct dwc3_properties *properties;
struct dwc3_probe_data probe_data = {};
struct device *dev = &pdev->dev;
struct dwc3_qcom *qcom;
@@ -704,7 +715,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
probe_data.dwc = &qcom->dwc;
probe_data.res = &res;
probe_data.ignore_clocks_and_resets = true;
- probe_data.properties = DWC3_DEFAULT_PROPERTIES;
+
+ properties = of_device_get_match_data(dev);
+ probe_data.properties = properties ? *properties : DWC3_DEFAULT_PROPERTIES;
+
ret = dwc3_core_probe(&probe_data);
if (ret) {
ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
@@ -839,6 +853,7 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
};
static const struct of_device_id dwc3_qcom_of_match[] = {
+ { .compatible = "qcom,ipq4019-dwc3", .data = &dwc3_qcom_ipq4019_properties },
{ .compatible = "qcom,snps-dwc3" },
{ }
};
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread