Linux USB
 help / color / mirror / Atom feed
* [PATCH v3 0/4] DWC3 link tunneling state reporting
@ 2026-09-01 10:05 Konrad Dybcio
  2026-09-01 10:05 ` [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Konrad Dybcio @ 2026-09-01 10:05 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman
  Cc: linux-usb, linux-kernel, usb4-upstream, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

Currently, retrieving the tunneled/native state of a running port is
only possible on Intel XHCI hosts. This series extends that to CIO-
capable DWC31 controllers (see [1]).

Note that this patchset only results in the correct udev->tunnel_mode
value being assigned. Creating the device links (which requires this
information) between the USB4 router and the USB3 controller does not
currently take place on DT-based platforms, but that will be amended
in a follow-up patchset.

Tested on a Qualcomm X1E80100 CRD board, with a (currently) out-of-tree
set of drivers.

[1] I'm not entirely sure about the DWC version range (particularly
    wrt DWC32 and newer), so I limited it to a reasonable subset. I'll
    happily amend that.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
Changes in v3:
- Report USB_LINK_UNKNOWN instead of NATIVE if the DWC3 controller
  seems not to support USB4
- Cache the capability of reporting tunneling mode instead of checking
  it every single time
- Link to v2: https://patch.msgid.link/20260715-topic-dwc3_tunneling_state-v2-0-026487a08119@oss.qualcomm.com

Changes in v2:
- Add handling for XHCI v1.2's USB3 tunneling and PORTSC.TM for
  platforms that advertise it (!!! UNTESTED !!!, I have no access to
  HW that exposes this)
- Prefer the aforementioned cap over custom implementations
- Bail out of the DWC3-specific check if `usb4-host-interface` device
  property is absent - hence this now depends on:
  https://github.com/devicetree-org/dt-schema/pull/196

- Link to v1: https://patch.msgid.link/20260505-topic-dwc3_tunneling_state-v1-0-4aaa6c3c14cb@oss.qualcomm.com

---
Konrad Dybcio (4):
      usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value
      usb: xhci: Honor PORTSC.TM if valid
      usb: xhci: Allow custom op for usb_link_tunnel_mode reporting
      usb: dwc3: Notify XHCI core of tunneled status

 drivers/usb/dwc3/core.c          | 16 ++++++++++++++++
 drivers/usb/dwc3/core.h          | 18 ++++++++++++++++++
 drivers/usb/dwc3/host.c          | 12 ++++++++++++
 drivers/usb/host/xhci-debugfs.c  |  9 +++++++++
 drivers/usb/host/xhci-debugfs.h  |  2 ++
 drivers/usb/host/xhci-ext-caps.h |  4 ++++
 drivers/usb/host/xhci-hub.c      | 24 +++++++++++++++++++-----
 drivers/usb/host/xhci-plat.c     |  2 ++
 drivers/usb/host/xhci-plat.h     |  1 +
 drivers/usb/host/xhci-port.h     |  3 ++-
 drivers/usb/host/xhci.c          | 11 ++++++++++-
 drivers/usb/host/xhci.h          |  6 +++++-
 12 files changed, 100 insertions(+), 8 deletions(-)
---
base-commit: 89c07d98716a13454ec3fd9f97689e812cc71bd4
change-id: 20260504-topic-dwc3_tunneling_state-50588c0e1ae3

Best regards,
--  
Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>


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

* [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value
  2026-09-01 10:05 [PATCH v3 0/4] DWC3 link tunneling state reporting Konrad Dybcio
@ 2026-09-01 10:05 ` Konrad Dybcio
  2026-09-05  0:26   ` Thinh Nguyen
  2026-09-01 10:05 ` [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid Konrad Dybcio
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2026-09-01 10:05 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman
  Cc: linux-usb, linux-kernel, usb4-upstream, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

The USB3 Tunneling Support Capability (idx 18) features a single
register. Expose it over debugfs, if supported by the controller.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
 drivers/usb/host/xhci-debugfs.c  | 9 +++++++++
 drivers/usb/host/xhci-debugfs.h  | 2 ++
 drivers/usb/host/xhci-ext-caps.h | 1 +
 3 files changed, 12 insertions(+)

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 2aa01d99f23d..f4bb66a9845a 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -82,6 +82,10 @@ static const struct debugfs_reg32 xhci_extcap_dbc[] = {
 	dump_register(EXTCAP_DBC_DEVINFO2),
 };
 
+static const struct debugfs_reg32 xhci_extcap_usb3_tunneling[] = {
+	dump_register(EXTCAP_USB3_TUNNELING),
+};
+
 static struct dentry *xhci_debugfs_root;
 
 static struct xhci_regset *xhci_debugfs_alloc_regset(struct xhci_hcd *xhci)
@@ -816,6 +820,11 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
 				   ARRAY_SIZE(xhci_extcap_dbc),
 				   "reg-ext-dbc");
 
+	xhci_debugfs_extcap_regset(xhci, XHCI_EXT_CAPS_USB3_TUNNELING,
+				   xhci_extcap_usb3_tunneling,
+				   ARRAY_SIZE(xhci_extcap_usb3_tunneling),
+				   "reg-usb3-tunneling");
+
 	xhci_debugfs_create_ring_dir(xhci, &xhci->cmd_ring,
 				     "command-ring",
 				     xhci->debugfs_root);
diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h
index 7c074b4be819..ca6b7f2da8e3 100644
--- a/drivers/usb/host/xhci-debugfs.h
+++ b/drivers/usb/host/xhci-debugfs.h
@@ -70,6 +70,8 @@
 #define REG_EXTCAP_DBC_DEVINFO1				0x38
 #define REG_EXTCAP_DBC_DEVINFO2				0x3c
 
+#define REG_EXTCAP_USB3_TUNNELING			0x00
+
 #define dump_register(nm)				\
 {							\
 	.name	= __stringify(nm),			\
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 67ecf7320c62..22e53a750e2a 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -40,6 +40,7 @@
 #define XHCI_EXT_CAPS_ROUTE	5
 /* IDs 6-9 reserved */
 #define XHCI_EXT_CAPS_DEBUG	10
+#define XHCI_EXT_CAPS_USB3_TUNNELING	18
 /* Vendor caps */
 #define XHCI_EXT_CAPS_VENDOR_INTEL	192
 #define XHCI_EXT_CAPS_INTEL_SPR_SHADOW	206

-- 
2.55.0


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

* [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid
  2026-09-01 10:05 [PATCH v3 0/4] DWC3 link tunneling state reporting Konrad Dybcio
  2026-09-01 10:05 ` [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
@ 2026-09-01 10:05 ` Konrad Dybcio
  2026-09-05  0:27   ` Thinh Nguyen
  2026-09-01 10:05 ` [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting Konrad Dybcio
  2026-09-01 10:05 ` [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status Konrad Dybcio
  3 siblings, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2026-09-01 10:05 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman
  Cc: linux-usb, linux-kernel, usb4-upstream, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Currently, the only way for the USB core to determine whether the link
is native or tunneled is via an Intel vendor-specific Extended
Capability.

The XHCI specification v1.2 and newer expose a common ext_cap,
indicating whether BIT(2) of PORTSC can be interpreted as the tunneling
status.

Make use of that and fall back to the existing Intel-specific path if
the ext_cap is absent.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
 drivers/usb/host/xhci-ext-caps.h |  3 +++
 drivers/usb/host/xhci-hub.c      | 11 ++++++++++-
 drivers/usb/host/xhci-port.h     |  3 ++-
 drivers/usb/host/xhci.c          |  8 ++++++++
 drivers/usb/host/xhci.h          |  1 +
 5 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 22e53a750e2a..af7d624cd38e 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -66,6 +66,9 @@
 #define XHCI_HLC               (1 << 19)
 #define XHCI_BLC               (1 << 20)
 
+/* USB3 tunneling support capability - section 7.11 */
+#define XHCI_USB3_TUNNELING_SUPPORTED	BIT(16)
+
 /* Intel SPR shadow capability */
 #define XHCI_INTEL_SPR_ESS_PORT_OFFSET  0x8ac4	/* SuperSpeed port control */
 #define XHCI_INTEL_SPR_TUNEN	BIT(4)		/* Tunnel mode enabled */
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 470bafe1802b..80f07bd5081d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -769,8 +769,17 @@ enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
 	struct usb_hcd *hcd;
 	void __iomem *base;
 	u32 offset;
+	u32 val;
 
-	/* Don't try and probe this capability for non-Intel hosts */
+	if (xhci->portsc_tunnel_reporting) {
+		val = xhci_portsc_readl(port);
+		if (val & PORT_TM)
+			return USB_LINK_TUNNELED;
+
+		return USB_LINK_NATIVE;
+	}
+
+	/* Fall back to the legacy Intel-specific ext_cap */
 	hcd = xhci_to_hcd(xhci);
 	if (!dev_is_pci(hcd->self.controller) ||
 	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
diff --git a/drivers/usb/host/xhci-port.h b/drivers/usb/host/xhci-port.h
index 889b5fb0fcd8..215c9cadbc34 100644
--- a/drivers/usb/host/xhci-port.h
+++ b/drivers/usb/host/xhci-port.h
@@ -5,7 +5,8 @@
 #define PORT_CONNECT	(1 << 0)
 /* true: port enabled */
 #define PORT_PE		(1 << 1)
-/* bit 2 reserved and zeroed */
+/* true: port is tunneling traffic over USB4 */
+#define PORT_TM		(1 << 2)
 /* true: port has an over-current condition */
 #define PORT_OC		(1 << 3)
 /* true: port reset signaling asserted */
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a9e47e178c28..5fb78613a993 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5433,9 +5433,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	 * quirks
 	 */
 	struct device		*dev = hcd->self.sysdev;
+	void __iomem		*base;
 	int			retval;
 	u32			hcs_params1;
 	u32			hc_capbase;
+	u32			tunnel_cap;
 
 	/* Accept arbitrarily long scatter-gather lists */
 	hcd->self.sg_tablesize = ~0;
@@ -5456,6 +5458,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	mutex_init(&xhci->mutex);
 	xhci->main_hcd = hcd;
 	xhci->cap_regs = hcd->regs;
+	base = &xhci->cap_regs->hc_capbase;
 	hc_capbase = readl(&xhci->cap_regs->hc_capbase);
 	if (hc_capbase == U32_MAX) {
 		xhci_warn(xhci, "Host controller not accessible, removed?\n");
@@ -5473,6 +5476,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 	xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
 	if (xhci->hci_version > 0x100)
 		xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
+	tunnel_cap = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_USB3_TUNNELING);
+	if (tunnel_cap) {
+		xhci->portsc_tunnel_reporting =
+			!!(readl(base + tunnel_cap) & XHCI_USB3_TUNNELING_SUPPORTED);
+	}
 
 	xhci->dma_mask_bits = 64;
 	xhci->max_slots = min(FIELD_GET(HCS_SLOTS_MASK, hcs_params1), MAX_HC_SLOTS);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c7bfa7f028d3..480fcbac4525 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1662,6 +1662,7 @@ struct xhci_hcd {
 	/* cached extended protocol port capabilities */
 	struct xhci_port_cap	*port_caps;
 	unsigned int		num_port_caps;
+	bool			portsc_tunnel_reporting;
 	/* Compliance Mode Recovery Data */
 	struct timer_list	comp_mode_recovery_timer;
 	u32			port_status_u0;

-- 
2.55.0


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

* [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting
  2026-09-01 10:05 [PATCH v3 0/4] DWC3 link tunneling state reporting Konrad Dybcio
  2026-09-01 10:05 ` [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
  2026-09-01 10:05 ` [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid Konrad Dybcio
@ 2026-09-01 10:05 ` Konrad Dybcio
  2026-09-05  0:29   ` Thinh Nguyen
  2026-09-01 10:05 ` [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status Konrad Dybcio
  3 siblings, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2026-09-01 10:05 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman
  Cc: linux-usb, linux-kernel, usb4-upstream, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

The Thunderbolt framework relies on the USB core to create device links
for tunneled ports, so that the USB3 controller is only kept
runtime-resumed for the duration of the tunneling.

Currently, retrieving that information is only possibe on Intel XHCI
hosts, through a vendor-specific capability. Extend xhci-plat to allow
plumbing a custom one.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
 drivers/usb/host/xhci-hub.c  | 13 +++++++++----
 drivers/usb/host/xhci-plat.c |  2 ++
 drivers/usb/host/xhci-plat.h |  1 +
 drivers/usb/host/xhci.c      |  3 ++-
 drivers/usb/host/xhci.h      |  5 ++++-
 5 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 80f07bd5081d..c585e4d02d84 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -749,7 +749,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
 }
 
 /**
- * xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4
+ * xhci_port_tunnel_mode() - Check if USB3 connection is tunneled over USB4
  * @xhci: xhci host controller
  * @port: USB3 port to be checked.
  *
@@ -763,7 +763,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
  * detecting USB3 over USB4 tunnels. USB_LINK_NATIVE or USB_LINK_TUNNELED
  * otherwise.
  */
-enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
+enum usb_link_tunnel_mode xhci_port_tunnel_mode(struct xhci_hcd *xhci,
 						struct xhci_port *port)
 {
 	struct usb_hcd *hcd;
@@ -782,8 +782,13 @@ enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
 	/* Fall back to the legacy Intel-specific ext_cap */
 	hcd = xhci_to_hcd(xhci);
 	if (!dev_is_pci(hcd->self.controller) ||
-	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
-		return USB_LINK_UNKNOWN;
+	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL) {
+		/* Last chance - if the controller has a custom tunnel_mode op, try that */
+		if (xhci->tunnel_mode)
+			return xhci->tunnel_mode(xhci_to_hcd(xhci), port->hcd_portnum);
+		else
+			return USB_LINK_UNKNOWN;
+	}
 
 	base = &xhci->cap_regs->hc_capbase;
 	offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 6fd595f81a30..c19bc5d7a7b5 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -244,6 +244,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
 		priv = hcd_to_xhci_priv(hcd);
 		/* Just copy data for now */
 		*priv = *priv_match;
+
+		xhci->tunnel_mode = priv->tunnel_mode;
 	}
 
 	device_set_wakeup_capable(&pdev->dev, true);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index 00751d851831..c5042766a486 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -22,6 +22,7 @@ struct xhci_plat_priv {
 	int (*suspend_quirk)(struct usb_hcd *);
 	int (*resume_quirk)(struct usb_hcd *);
 	int (*post_resume_quirk)(struct usb_hcd *);
+	enum usb_link_tunnel_mode (*tunnel_mode)(struct usb_hcd *hcd, int portnum);
 };
 
 #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 5fb78613a993..a7e3c46937fa 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4762,7 +4762,8 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
 	if (hcd->speed >= HCD_USB3 && !udev->parent->parent) {
 		port = xhci->usb3_rhub.ports[udev->portnum - 1];
 
-		udev->tunnel_mode = xhci_port_is_tunneled(xhci, port);
+		udev->tunnel_mode = xhci_port_tunnel_mode(xhci, port);
+
 		if (udev->tunnel_mode == USB_LINK_UNKNOWN)
 			dev_dbg(&udev->dev, "link tunnel state unknown\n");
 		else if (udev->tunnel_mode == USB_LINK_TUNNELED)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 480fcbac4525..2b5c0b304c6b 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1675,6 +1675,9 @@ struct xhci_hcd {
 	struct list_head	regset_list;
 
 	void			*dbc;
+
+	enum usb_link_tunnel_mode (*tunnel_mode)(struct usb_hcd *hcd, int portnum);
+
 	/* platform-specific data -- must come last */
 	unsigned long		priv[] __aligned(sizeof(s64));
 };
@@ -1981,7 +1984,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
 int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
 struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
-enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
+enum usb_link_tunnel_mode xhci_port_tunnel_mode(struct xhci_hcd *xhci,
 						struct xhci_port *port);
 void xhci_hc_died(struct xhci_hcd *xhci);
 

-- 
2.55.0


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

* [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status
  2026-09-01 10:05 [PATCH v3 0/4] DWC3 link tunneling state reporting Konrad Dybcio
                   ` (2 preceding siblings ...)
  2026-09-01 10:05 ` [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting Konrad Dybcio
@ 2026-09-01 10:05 ` Konrad Dybcio
  2026-09-05  0:30   ` Thinh Nguyen
  3 siblings, 1 reply; 9+ messages in thread
From: Konrad Dybcio @ 2026-09-01 10:05 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman
  Cc: linux-usb, linux-kernel, usb4-upstream, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

The Thunderbolt framework relies on the USB core to create device links
for tunneled ports, so that the USB3 controller is only kept
runtime-resumed for the duration of the tunneling. This depends on
first knowing whether a connection is tunneled or native.

Add the logic to handle that for DWC3 controllers.

Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
 drivers/usb/dwc3/core.c | 16 ++++++++++++++++
 drivers/usb/dwc3/core.h | 18 ++++++++++++++++++
 drivers/usb/dwc3/host.c | 12 ++++++++++++
 3 files changed, 46 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fd5c2cd36c59..6af8937525ff 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -162,6 +162,22 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
 }
 EXPORT_SYMBOL_GPL(dwc3_set_prtcap);
 
+enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port)
+{
+	/* Prior versions had no CIO support */
+	if (!DWC3_VER_IS_WITHIN(DWC31, 191A, ANY))
+		return USB_LINK_UNKNOWN;
+
+	/* Not all DWC3 instances have CIO HW, trust the platform firmware */
+	if (!device_property_present(dwc->dev, "usb4-host-interface"))
+		return USB_LINK_UNKNOWN;
+
+	if (dwc3_readl(dwc, DWC3_CIOCTRL(port)) & DWC3_CIOCTRL_CIO_EN)
+		return USB_LINK_TUNNELED;
+
+	return USB_LINK_NATIVE;
+}
+
 static void __dwc3_set_mode(struct work_struct *work)
 {
 	struct dwc3 *dwc = work_to_dwc(work);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 608daeb7ef10..decc51cd6505 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -179,6 +179,11 @@
 #define DWC3_OEVTEN		0xcc0C
 #define DWC3_OSTS		0xcc10
 
+/* CIO regs */
+#define DWC3_CIO_BASE(n)	(0xcd20 + ((n) * 0x30))
+#define DWC3_CIOCTRL(n)		(DWC3_CIO_BASE(n) + 0x00)
+#define DWC3_CIOCTRL_CIO_EN	BIT(0)
+
 #define DWC3_LLUCTL(n)		(0xd024 + ((n) * 0x80))
 
 /* Bit fields */
@@ -1314,6 +1319,7 @@ struct dwc3 {
 #define DWC31_REVISION_170A	0x3137302a
 #define DWC31_REVISION_180A	0x3138302a
 #define DWC31_REVISION_190A	0x3139302a
+#define DWC31_REVISION_191A	0x3139312a
 #define DWC31_REVISION_200A	0x3230302a
 
 #define DWC32_REVISION_ANY	0x0
@@ -1658,11 +1664,23 @@ static inline void dwc3_pre_run_stop(struct dwc3 *dwc, bool is_on)
 #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
+
+/**
+ * dwc3_link_tunnel_mode - Check whether the link is tunneled over TBT/USB4
+ * @dwc: Pointer to DWC3 controller context
+ * @port: 0-based port index
+ *
+ * Returns: USB_LINK_TUNNELED if tunneled, USB_LINK_NATIVE if not, or
+ *          when the controller does not have USB4 capabilities.
+ */
+enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port);
 #else
 static inline int dwc3_host_init(struct dwc3 *dwc)
 { return 0; }
 static inline void dwc3_host_exit(struct dwc3 *dwc)
 { }
+static inline enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port)
+{ return USB_LINK_UNKNOWN; }
 #endif
 
 #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index c5674161b2b0..1b9c4f94c2fd 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -78,8 +78,20 @@ static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
 	dwc3_enable_susphy(dwc, true);
 }
 
+static enum usb_link_tunnel_mode dwc3_xhci_tunnel_mode(struct usb_hcd *hcd, int portnum)
+{
+	struct platform_device *pdev;
+	struct dwc3 *dwc;
+
+	pdev = to_platform_device(hcd->self.controller);
+	dwc = dev_get_drvdata(pdev->dev.parent);
+
+	return dwc3_link_tunnel_mode(dwc, portnum);
+}
+
 static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
 	.plat_start = dwc3_xhci_plat_start,
+	.tunnel_mode = dwc3_xhci_tunnel_mode,
 };
 
 static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,

-- 
2.55.0


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

* Re: [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value
  2026-09-01 10:05 ` [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
@ 2026-09-05  0:26   ` Thinh Nguyen
  0 siblings, 0 replies; 9+ messages in thread
From: Thinh Nguyen @ 2026-09-05  0:26 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	usb4-upstream@oss.qualcomm.com, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

On Tue, Sep 01, 2026, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> The USB3 Tunneling Support Capability (idx 18) features a single
> register. Expose it over debugfs, if supported by the controller.
> 
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
>  drivers/usb/host/xhci-debugfs.c  | 9 +++++++++
>  drivers/usb/host/xhci-debugfs.h  | 2 ++
>  drivers/usb/host/xhci-ext-caps.h | 1 +
>  3 files changed, 12 insertions(+)
> 
> diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
> index 2aa01d99f23d..f4bb66a9845a 100644
> --- a/drivers/usb/host/xhci-debugfs.c
> +++ b/drivers/usb/host/xhci-debugfs.c
> @@ -82,6 +82,10 @@ static const struct debugfs_reg32 xhci_extcap_dbc[] = {
>  	dump_register(EXTCAP_DBC_DEVINFO2),
>  };
>  
> +static const struct debugfs_reg32 xhci_extcap_usb3_tunneling[] = {
> +	dump_register(EXTCAP_USB3_TUNNELING),
> +};
> +
>  static struct dentry *xhci_debugfs_root;
>  
>  static struct xhci_regset *xhci_debugfs_alloc_regset(struct xhci_hcd *xhci)
> @@ -816,6 +820,11 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
>  				   ARRAY_SIZE(xhci_extcap_dbc),
>  				   "reg-ext-dbc");
>  
> +	xhci_debugfs_extcap_regset(xhci, XHCI_EXT_CAPS_USB3_TUNNELING,
> +				   xhci_extcap_usb3_tunneling,
> +				   ARRAY_SIZE(xhci_extcap_usb3_tunneling),
> +				   "reg-usb3-tunneling");
> +
>  	xhci_debugfs_create_ring_dir(xhci, &xhci->cmd_ring,
>  				     "command-ring",
>  				     xhci->debugfs_root);
> diff --git a/drivers/usb/host/xhci-debugfs.h b/drivers/usb/host/xhci-debugfs.h
> index 7c074b4be819..ca6b7f2da8e3 100644
> --- a/drivers/usb/host/xhci-debugfs.h
> +++ b/drivers/usb/host/xhci-debugfs.h
> @@ -70,6 +70,8 @@
>  #define REG_EXTCAP_DBC_DEVINFO1				0x38
>  #define REG_EXTCAP_DBC_DEVINFO2				0x3c
>  
> +#define REG_EXTCAP_USB3_TUNNELING			0x00
> +
>  #define dump_register(nm)				\
>  {							\
>  	.name	= __stringify(nm),			\
> diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
> index 67ecf7320c62..22e53a750e2a 100644
> --- a/drivers/usb/host/xhci-ext-caps.h
> +++ b/drivers/usb/host/xhci-ext-caps.h
> @@ -40,6 +40,7 @@
>  #define XHCI_EXT_CAPS_ROUTE	5
>  /* IDs 6-9 reserved */
>  #define XHCI_EXT_CAPS_DEBUG	10
> +#define XHCI_EXT_CAPS_USB3_TUNNELING	18
>  /* Vendor caps */
>  #define XHCI_EXT_CAPS_VENDOR_INTEL	192
>  #define XHCI_EXT_CAPS_INTEL_SPR_SHADOW	206
> 
> -- 
> 2.55.0
> 

Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>

Thanks,
Thinh

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

* Re: [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid
  2026-09-01 10:05 ` [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid Konrad Dybcio
@ 2026-09-05  0:27   ` Thinh Nguyen
  0 siblings, 0 replies; 9+ messages in thread
From: Thinh Nguyen @ 2026-09-05  0:27 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	usb4-upstream@oss.qualcomm.com, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

On Tue, Sep 01, 2026, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> Currently, the only way for the USB core to determine whether the link
> is native or tunneled is via an Intel vendor-specific Extended
> Capability.
> 
> The XHCI specification v1.2 and newer expose a common ext_cap,
> indicating whether BIT(2) of PORTSC can be interpreted as the tunneling
> status.
> 
> Make use of that and fall back to the existing Intel-specific path if
> the ext_cap is absent.
> 
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
>  drivers/usb/host/xhci-ext-caps.h |  3 +++
>  drivers/usb/host/xhci-hub.c      | 11 ++++++++++-
>  drivers/usb/host/xhci-port.h     |  3 ++-
>  drivers/usb/host/xhci.c          |  8 ++++++++
>  drivers/usb/host/xhci.h          |  1 +
>  5 files changed, 24 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
> index 22e53a750e2a..af7d624cd38e 100644
> --- a/drivers/usb/host/xhci-ext-caps.h
> +++ b/drivers/usb/host/xhci-ext-caps.h
> @@ -66,6 +66,9 @@
>  #define XHCI_HLC               (1 << 19)
>  #define XHCI_BLC               (1 << 20)
>  
> +/* USB3 tunneling support capability - section 7.11 */
> +#define XHCI_USB3_TUNNELING_SUPPORTED	BIT(16)
> +
>  /* Intel SPR shadow capability */
>  #define XHCI_INTEL_SPR_ESS_PORT_OFFSET  0x8ac4	/* SuperSpeed port control */
>  #define XHCI_INTEL_SPR_TUNEN	BIT(4)		/* Tunnel mode enabled */
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index 470bafe1802b..80f07bd5081d 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -769,8 +769,17 @@ enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
>  	struct usb_hcd *hcd;
>  	void __iomem *base;
>  	u32 offset;
> +	u32 val;
>  
> -	/* Don't try and probe this capability for non-Intel hosts */
> +	if (xhci->portsc_tunnel_reporting) {
> +		val = xhci_portsc_readl(port);
> +		if (val & PORT_TM)
> +			return USB_LINK_TUNNELED;
> +
> +		return USB_LINK_NATIVE;
> +	}
> +
> +	/* Fall back to the legacy Intel-specific ext_cap */
>  	hcd = xhci_to_hcd(xhci);
>  	if (!dev_is_pci(hcd->self.controller) ||
>  	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
> diff --git a/drivers/usb/host/xhci-port.h b/drivers/usb/host/xhci-port.h
> index 889b5fb0fcd8..215c9cadbc34 100644
> --- a/drivers/usb/host/xhci-port.h
> +++ b/drivers/usb/host/xhci-port.h
> @@ -5,7 +5,8 @@
>  #define PORT_CONNECT	(1 << 0)
>  /* true: port enabled */
>  #define PORT_PE		(1 << 1)
> -/* bit 2 reserved and zeroed */
> +/* true: port is tunneling traffic over USB4 */
> +#define PORT_TM		(1 << 2)
>  /* true: port has an over-current condition */
>  #define PORT_OC		(1 << 3)
>  /* true: port reset signaling asserted */
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index a9e47e178c28..5fb78613a993 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -5433,9 +5433,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
>  	 * quirks
>  	 */
>  	struct device		*dev = hcd->self.sysdev;
> +	void __iomem		*base;
>  	int			retval;
>  	u32			hcs_params1;
>  	u32			hc_capbase;
> +	u32			tunnel_cap;
>  
>  	/* Accept arbitrarily long scatter-gather lists */
>  	hcd->self.sg_tablesize = ~0;
> @@ -5456,6 +5458,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
>  	mutex_init(&xhci->mutex);
>  	xhci->main_hcd = hcd;
>  	xhci->cap_regs = hcd->regs;
> +	base = &xhci->cap_regs->hc_capbase;
>  	hc_capbase = readl(&xhci->cap_regs->hc_capbase);
>  	if (hc_capbase == U32_MAX) {
>  		xhci_warn(xhci, "Host controller not accessible, removed?\n");
> @@ -5473,6 +5476,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
>  	xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);
>  	if (xhci->hci_version > 0x100)
>  		xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
> +	tunnel_cap = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_USB3_TUNNELING);
> +	if (tunnel_cap) {
> +		xhci->portsc_tunnel_reporting =
> +			!!(readl(base + tunnel_cap) & XHCI_USB3_TUNNELING_SUPPORTED);
> +	}
>  
>  	xhci->dma_mask_bits = 64;
>  	xhci->max_slots = min(FIELD_GET(HCS_SLOTS_MASK, hcs_params1), MAX_HC_SLOTS);
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index c7bfa7f028d3..480fcbac4525 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1662,6 +1662,7 @@ struct xhci_hcd {
>  	/* cached extended protocol port capabilities */
>  	struct xhci_port_cap	*port_caps;
>  	unsigned int		num_port_caps;
> +	bool			portsc_tunnel_reporting;
>  	/* Compliance Mode Recovery Data */
>  	struct timer_list	comp_mode_recovery_timer;
>  	u32			port_status_u0;
> 
> -- 
> 2.55.0
> 

Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>

Thanks,
Thinh

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

* Re: [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting
  2026-09-01 10:05 ` [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting Konrad Dybcio
@ 2026-09-05  0:29   ` Thinh Nguyen
  0 siblings, 0 replies; 9+ messages in thread
From: Thinh Nguyen @ 2026-09-05  0:29 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	usb4-upstream@oss.qualcomm.com, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

On Tue, Sep 01, 2026, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> The Thunderbolt framework relies on the USB core to create device links
> for tunneled ports, so that the USB3 controller is only kept
> runtime-resumed for the duration of the tunneling.
> 
> Currently, retrieving that information is only possibe on Intel XHCI
> hosts, through a vendor-specific capability. Extend xhci-plat to allow
> plumbing a custom one.
> 
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
>  drivers/usb/host/xhci-hub.c  | 13 +++++++++----
>  drivers/usb/host/xhci-plat.c |  2 ++
>  drivers/usb/host/xhci-plat.h |  1 +
>  drivers/usb/host/xhci.c      |  3 ++-
>  drivers/usb/host/xhci.h      |  5 ++++-
>  5 files changed, 18 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index 80f07bd5081d..c585e4d02d84 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -749,7 +749,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
>  }
>  
>  /**
> - * xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4
> + * xhci_port_tunnel_mode() - Check if USB3 connection is tunneled over USB4
>   * @xhci: xhci host controller
>   * @port: USB3 port to be checked.
>   *
> @@ -763,7 +763,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
>   * detecting USB3 over USB4 tunnels. USB_LINK_NATIVE or USB_LINK_TUNNELED
>   * otherwise.
>   */
> -enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
> +enum usb_link_tunnel_mode xhci_port_tunnel_mode(struct xhci_hcd *xhci,
>  						struct xhci_port *port)
>  {
>  	struct usb_hcd *hcd;
> @@ -782,8 +782,13 @@ enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
>  	/* Fall back to the legacy Intel-specific ext_cap */
>  	hcd = xhci_to_hcd(xhci);
>  	if (!dev_is_pci(hcd->self.controller) ||
> -	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
> -		return USB_LINK_UNKNOWN;
> +	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL) {
> +		/* Last chance - if the controller has a custom tunnel_mode op, try that */
> +		if (xhci->tunnel_mode)
> +			return xhci->tunnel_mode(xhci_to_hcd(xhci), port->hcd_portnum);
> +		else
> +			return USB_LINK_UNKNOWN;
> +	}
>  
>  	base = &xhci->cap_regs->hc_capbase;
>  	offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
> index 6fd595f81a30..c19bc5d7a7b5 100644
> --- a/drivers/usb/host/xhci-plat.c
> +++ b/drivers/usb/host/xhci-plat.c
> @@ -244,6 +244,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
>  		priv = hcd_to_xhci_priv(hcd);
>  		/* Just copy data for now */
>  		*priv = *priv_match;
> +
> +		xhci->tunnel_mode = priv->tunnel_mode;
>  	}
>  
>  	device_set_wakeup_capable(&pdev->dev, true);
> diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
> index 00751d851831..c5042766a486 100644
> --- a/drivers/usb/host/xhci-plat.h
> +++ b/drivers/usb/host/xhci-plat.h
> @@ -22,6 +22,7 @@ struct xhci_plat_priv {
>  	int (*suspend_quirk)(struct usb_hcd *);
>  	int (*resume_quirk)(struct usb_hcd *);
>  	int (*post_resume_quirk)(struct usb_hcd *);
> +	enum usb_link_tunnel_mode (*tunnel_mode)(struct usb_hcd *hcd, int portnum);
>  };
>  
>  #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index 5fb78613a993..a7e3c46937fa 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -4762,7 +4762,8 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
>  	if (hcd->speed >= HCD_USB3 && !udev->parent->parent) {
>  		port = xhci->usb3_rhub.ports[udev->portnum - 1];
>  
> -		udev->tunnel_mode = xhci_port_is_tunneled(xhci, port);
> +		udev->tunnel_mode = xhci_port_tunnel_mode(xhci, port);
> +
>  		if (udev->tunnel_mode == USB_LINK_UNKNOWN)
>  			dev_dbg(&udev->dev, "link tunnel state unknown\n");
>  		else if (udev->tunnel_mode == USB_LINK_TUNNELED)
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 480fcbac4525..2b5c0b304c6b 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1675,6 +1675,9 @@ struct xhci_hcd {
>  	struct list_head	regset_list;
>  
>  	void			*dbc;
> +
> +	enum usb_link_tunnel_mode (*tunnel_mode)(struct usb_hcd *hcd, int portnum);
> +
>  	/* platform-specific data -- must come last */
>  	unsigned long		priv[] __aligned(sizeof(s64));
>  };
> @@ -1981,7 +1984,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
>  int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
>  int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
>  struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
> -enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
> +enum usb_link_tunnel_mode xhci_port_tunnel_mode(struct xhci_hcd *xhci,
>  						struct xhci_port *port);
>  void xhci_hc_died(struct xhci_hcd *xhci);
>  
> 
> -- 
> 2.55.0
> 

Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>

Thanks,
Thinh

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

* Re: [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status
  2026-09-01 10:05 ` [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status Konrad Dybcio
@ 2026-09-05  0:30   ` Thinh Nguyen
  0 siblings, 0 replies; 9+ messages in thread
From: Thinh Nguyen @ 2026-09-05  0:30 UTC (permalink / raw)
  To: Konrad Dybcio
  Cc: Thinh Nguyen, Greg Kroah-Hartman, Mathias Nyman,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	usb4-upstream@oss.qualcomm.com, Raghavendra Thoorpu,
	Mika Westerberg, Sven Peter, Konrad Dybcio

On Tue, Sep 01, 2026, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> The Thunderbolt framework relies on the USB core to create device links
> for tunneled ports, so that the USB3 controller is only kept
> runtime-resumed for the duration of the tunneling. This depends on
> first knowing whether a connection is tunneled or native.
> 
> Add the logic to handle that for DWC3 controllers.
> 
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
>  drivers/usb/dwc3/core.c | 16 ++++++++++++++++
>  drivers/usb/dwc3/core.h | 18 ++++++++++++++++++
>  drivers/usb/dwc3/host.c | 12 ++++++++++++
>  3 files changed, 46 insertions(+)
> 
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index fd5c2cd36c59..6af8937525ff 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -162,6 +162,22 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
>  }
>  EXPORT_SYMBOL_GPL(dwc3_set_prtcap);
>  
> +enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port)
> +{
> +	/* Prior versions had no CIO support */
> +	if (!DWC3_VER_IS_WITHIN(DWC31, 191A, ANY))
> +		return USB_LINK_UNKNOWN;
> +
> +	/* Not all DWC3 instances have CIO HW, trust the platform firmware */
> +	if (!device_property_present(dwc->dev, "usb4-host-interface"))
> +		return USB_LINK_UNKNOWN;
> +
> +	if (dwc3_readl(dwc, DWC3_CIOCTRL(port)) & DWC3_CIOCTRL_CIO_EN)
> +		return USB_LINK_TUNNELED;
> +
> +	return USB_LINK_NATIVE;
> +}
> +
>  static void __dwc3_set_mode(struct work_struct *work)
>  {
>  	struct dwc3 *dwc = work_to_dwc(work);
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 608daeb7ef10..decc51cd6505 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -179,6 +179,11 @@
>  #define DWC3_OEVTEN		0xcc0C
>  #define DWC3_OSTS		0xcc10
>  
> +/* CIO regs */
> +#define DWC3_CIO_BASE(n)	(0xcd20 + ((n) * 0x30))
> +#define DWC3_CIOCTRL(n)		(DWC3_CIO_BASE(n) + 0x00)
> +#define DWC3_CIOCTRL_CIO_EN	BIT(0)
> +
>  #define DWC3_LLUCTL(n)		(0xd024 + ((n) * 0x80))
>  
>  /* Bit fields */
> @@ -1314,6 +1319,7 @@ struct dwc3 {
>  #define DWC31_REVISION_170A	0x3137302a
>  #define DWC31_REVISION_180A	0x3138302a
>  #define DWC31_REVISION_190A	0x3139302a
> +#define DWC31_REVISION_191A	0x3139312a
>  #define DWC31_REVISION_200A	0x3230302a
>  
>  #define DWC32_REVISION_ANY	0x0
> @@ -1658,11 +1664,23 @@ static inline void dwc3_pre_run_stop(struct dwc3 *dwc, bool is_on)
>  #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
>  int dwc3_host_init(struct dwc3 *dwc);
>  void dwc3_host_exit(struct dwc3 *dwc);
> +
> +/**
> + * dwc3_link_tunnel_mode - Check whether the link is tunneled over TBT/USB4
> + * @dwc: Pointer to DWC3 controller context
> + * @port: 0-based port index
> + *
> + * Returns: USB_LINK_TUNNELED if tunneled, USB_LINK_NATIVE if not, or
> + *          when the controller does not have USB4 capabilities.
> + */
> +enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port);
>  #else
>  static inline int dwc3_host_init(struct dwc3 *dwc)
>  { return 0; }
>  static inline void dwc3_host_exit(struct dwc3 *dwc)
>  { }
> +static inline enum usb_link_tunnel_mode dwc3_link_tunnel_mode(struct dwc3 *dwc, u8 port)
> +{ return USB_LINK_UNKNOWN; }
>  #endif
>  
>  #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index c5674161b2b0..1b9c4f94c2fd 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -78,8 +78,20 @@ static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
>  	dwc3_enable_susphy(dwc, true);
>  }
>  
> +static enum usb_link_tunnel_mode dwc3_xhci_tunnel_mode(struct usb_hcd *hcd, int portnum)
> +{
> +	struct platform_device *pdev;
> +	struct dwc3 *dwc;
> +
> +	pdev = to_platform_device(hcd->self.controller);
> +	dwc = dev_get_drvdata(pdev->dev.parent);
> +
> +	return dwc3_link_tunnel_mode(dwc, portnum);
> +}
> +
>  static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
>  	.plat_start = dwc3_xhci_plat_start,
> +	.tunnel_mode = dwc3_xhci_tunnel_mode,
>  };
>  
>  static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
> 
> -- 
> 2.55.0
> 

Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>

Thanks,
Thinh

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

end of thread, other threads:[~2026-09-05  0:30 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 10:05 [PATCH v3 0/4] DWC3 link tunneling state reporting Konrad Dybcio
2026-09-01 10:05 ` [PATCH v3 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
2026-09-05  0:26   ` Thinh Nguyen
2026-09-01 10:05 ` [PATCH v3 2/4] usb: xhci: Honor PORTSC.TM if valid Konrad Dybcio
2026-09-05  0:27   ` Thinh Nguyen
2026-09-01 10:05 ` [PATCH v3 3/4] usb: xhci: Allow custom op for usb_link_tunnel_mode reporting Konrad Dybcio
2026-09-05  0:29   ` Thinh Nguyen
2026-09-01 10:05 ` [PATCH v3 4/4] usb: dwc3: Notify XHCI core of tunneled status Konrad Dybcio
2026-09-05  0:30   ` Thinh Nguyen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox