All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
To: Konrad Dybcio <konradybcio@kernel.org>
Cc: Thinh Nguyen <Thinh.Nguyen@synopsys.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mathias Nyman <mathias.nyman@intel.com>,
	"linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"usb4-upstream@oss.qualcomm.com" <usb4-upstream@oss.qualcomm.com>,
	Raghavendra Thoorpu <rthoorpu@qti.qualcomm.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Sven Peter <sven@kernel.org>,
	Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Subject: Re: [PATCH v4 3/4] usb: xhci: Use update_device overrides for tunnel reporting
Date: Sat, 3 Oct 2026 00:30:52 +0000	[thread overview]
Message-ID: <asBLzaNbnBmG3mdx@vbox> (raw)
In-Reply-To: <20260929-topic-dwc3_tunneling_state-v4-3-63e296346d57@oss.qualcomm.com>

On Tue, Sep 29, 2026, Konrad Dybcio wrote:
> From: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> The Thunderbolt framework relies on USB core device links for tunneled
> ports, so it needs tunnel state when xHCI updates a device.
> 
> Use the .update_device override for controller-specific tunnel
> reporting.
> 
> Assisted-by: LLM
> Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
>  drivers/usb/host/xhci-hub.c  | 53 --------------------------------------------
>  drivers/usb/host/xhci-pci.c  | 38 +++++++++++++++++++++++++++++++
>  drivers/usb/host/xhci-plat.c | 18 +++++++++++++++
>  drivers/usb/host/xhci-plat.h |  2 ++
>  drivers/usb/host/xhci.c      | 19 +++++++++-------
>  drivers/usb/host/xhci.h      |  8 +++++--
>  6 files changed, 75 insertions(+), 63 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index 80f07bd5081d..31ba7a990e07 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -12,7 +12,6 @@
>  #include <linux/slab.h>
>  #include <linux/unaligned.h>
>  #include <linux/bitfield.h>
> -#include <linux/pci.h>
>  
>  #include "xhci.h"
>  #include "xhci-trace.h"
> @@ -748,58 +747,6 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
>  	return xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
>  }
>  
> -/**
> - * xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4
> - * @xhci: xhci host controller
> - * @port: USB3 port to be checked.
> - *
> - * Some hosts can detect if a USB3 connection is native USB3 or tunneled over
> - * USB4. Intel hosts expose this via vendor specific extended capability 206
> - * eSS PORT registers TUNEN (tunnel enabled) bit.
> - *
> - * A USB3 device must be connected to the port to detect the tunnel.
> - *
> - * Return: link tunnel mode enum, USB_LINK_UNKNOWN if host is incapable of
> - * 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,
> -						struct xhci_port *port)
> -{
> -	struct usb_hcd *hcd;
> -	void __iomem *base;
> -	u32 offset;
> -	u32 val;
> -
> -	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)
> -		return USB_LINK_UNKNOWN;
> -
> -	base = &xhci->cap_regs->hc_capbase;
> -	offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
> -
> -	if (offset && offset <= XHCI_INTEL_SPR_ESS_PORT_OFFSET) {
> -		offset = XHCI_INTEL_SPR_ESS_PORT_OFFSET + port->hcd_portnum * 0x20;
> -
> -		if (readl(base + offset) & XHCI_INTEL_SPR_TUNEN)
> -			return USB_LINK_TUNNELED;
> -		else
> -			return USB_LINK_NATIVE;
> -	}
> -
> -	return USB_LINK_UNKNOWN;
> -}
> -
>  void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
>  			 u32 link_state)
>  {
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index a8889081ae82..61ac267bc84a 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -103,11 +103,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd);
>  static int xhci_pci_run(struct usb_hcd *hcd);
>  static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
>  				      struct usb_tt *tt, gfp_t mem_flags);
> +static int xhci_pci_update_device(struct usb_hcd *hcd, struct usb_device *udev);
>  
>  static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
>  	.reset = xhci_pci_setup,
>  	.start = xhci_pci_run,
>  	.update_hub_device = xhci_pci_update_hub_device,
> +	.update_device = xhci_pci_update_device,
>  };
>  
>  /*
> @@ -606,6 +608,42 @@ static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hd
>  	return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
>  }
>  
> +static void xhci_intel_port_is_tunneled(struct usb_hcd *hcd,
> +					struct usb_device *udev)
> +{
> +	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
> +	struct xhci_port *port;
> +	void __iomem *base;
> +	u32 offset;
> +
> +	if (xhci->portsc_tunnel_reporting || udev->parent->parent)
> +		return;
> +
> +	port = xhci->usb3_rhub.ports[udev->portnum - 1];
> +
> +	base = &xhci->cap_regs->hc_capbase;
> +	offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
> +
> +	if (offset && offset <= XHCI_INTEL_SPR_ESS_PORT_OFFSET) {
> +		offset = XHCI_INTEL_SPR_ESS_PORT_OFFSET + port->hcd_portnum * 0x20;
> +
> +		if (readl(base + offset) & XHCI_INTEL_SPR_TUNEN)
> +			udev->tunnel_mode = USB_LINK_TUNNELED;
> +		else
> +			udev->tunnel_mode = USB_LINK_NATIVE;
> +	}
> +}
> +
> +static int xhci_pci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
> +
> +	if (pdev->vendor == PCI_VENDOR_ID_INTEL && hcd->speed >= HCD_USB3)
> +		xhci_intel_port_is_tunneled(hcd, udev);
> +
> +	return xhci_update_device(hcd, udev);
> +}
> +
>  /*
>   * We need to register our own PCI probe function (instead of the USB core's
>   * function) in order to create a second roothub under xHCI.
> diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
> index 6fd595f81a30..641e31976240 100644
> --- a/drivers/usb/host/xhci-plat.c
> +++ b/drivers/usb/host/xhci-plat.c
> @@ -30,13 +30,31 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver;
>  
>  static int xhci_plat_setup(struct usb_hcd *hcd);
>  static int xhci_plat_start(struct usb_hcd *hcd);
> +static int xhci_plat_update_device(struct usb_hcd *hcd, struct usb_device *udev);
>  
>  static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
>  	.extra_priv_size = sizeof(struct xhci_plat_priv),
>  	.reset = xhci_plat_setup,
>  	.start = xhci_plat_start,
> +	.update_device = xhci_plat_update_device,
>  };
>  
> +static int xhci_plat_update_device(struct usb_hcd *hcd, struct usb_device *udev)
> +{
> +	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
> +	struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
> +	int ret;
> +
> +	if (!xhci->portsc_tunnel_reporting && priv->update_device &&
> +	    hcd->speed >= HCD_USB3 && !udev->parent->parent) {
> +		ret = priv->update_device(hcd, udev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return xhci_update_device(hcd, udev);
> +}
> +
>  static void xhci_priv_plat_start(struct usb_hcd *hcd)
>  {
>  	struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
> diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
> index 00751d851831..91333605c46b 100644
> --- a/drivers/usb/host/xhci-plat.h
> +++ b/drivers/usb/host/xhci-plat.h
> @@ -10,6 +10,7 @@
>  
>  struct device;
>  struct platform_device;
> +struct usb_device;
>  struct usb_hcd;
>  
>  struct xhci_plat_priv {
> @@ -22,6 +23,7 @@ struct xhci_plat_priv {
>  	int (*suspend_quirk)(struct usb_hcd *);
>  	int (*resume_quirk)(struct usb_hcd *);
>  	int (*post_resume_quirk)(struct usb_hcd *);
> +	int (*update_device)(struct usb_hcd *hcd, struct usb_device *udev);
>  };
>  
>  #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..b252ce5e8499 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -4752,7 +4752,7 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
>  	return 0;
>  }
>  
> -static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
> +int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
>  {
>  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
>  	struct xhci_port *port;
> @@ -4760,9 +4760,14 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
>  
>  	/* Check if USB3 device at root port is tunneled over USB4 */
>  	if (hcd->speed >= HCD_USB3 && !udev->parent->parent) {
> -		port = xhci->usb3_rhub.ports[udev->portnum - 1];
> +		if (xhci->portsc_tunnel_reporting) {
> +			port = xhci->usb3_rhub.ports[udev->portnum - 1];
> +			if (xhci_portsc_readl(port) & PORT_TM)
> +				udev->tunnel_mode = USB_LINK_TUNNELED;
> +			else
> +				udev->tunnel_mode = USB_LINK_NATIVE;
> +		}
>  
> -		udev->tunnel_mode = xhci_port_is_tunneled(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)
> @@ -4793,6 +4798,7 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
>  
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(xhci_update_device);
>  
>  /*---------------------- USB 3.0 Link PM functions ------------------------*/
>  
> @@ -5242,11 +5248,6 @@ static int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
>  	return 0;
>  }
>  
> -static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
> -{
> -	return 0;
> -}
> -
>  static int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
>  			struct usb_device *udev, enum usb3_link_state state)
>  {
> @@ -5695,6 +5696,8 @@ void xhci_init_driver(struct hc_driver *drv,
>  			drv->update_hub_device = over->update_hub_device;
>  		if (over->hub_control)
>  			drv->hub_control = over->hub_control;
> +		if (over->update_device)
> +			drv->update_device = over->update_device;
>  	}
>  }
>  EXPORT_SYMBOL_GPL(xhci_init_driver);
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index 480fcbac4525..f12a309104dc 100644
> --- a/drivers/usb/host/xhci.h
> +++ b/drivers/usb/host/xhci.h
> @@ -1694,6 +1694,7 @@ struct xhci_driver_overrides {
>  			    struct usb_tt *tt, gfp_t mem_flags);
>  	int (*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
>  			   u16 wIndex, char *buf, u16 wLength);
> +	int (*update_device)(struct usb_hcd *hcd, struct usb_device *udev);
>  };
>  
>  #define	XHCI_CFC_DELAY		10
> @@ -1981,15 +1982,18 @@ 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,
> -						struct xhci_port *port);
>  void xhci_hc_died(struct xhci_hcd *xhci);
>  
>  #ifdef CONFIG_PM
> +int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);

Why are we putting this inside this PM guard?

BR,
Thinh

>  int xhci_bus_suspend(struct usb_hcd *hcd);
>  int xhci_bus_resume(struct usb_hcd *hcd);
>  unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
>  #else
> +static inline int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
> +{
> +	return 0;
> +}
>  #define	xhci_bus_suspend	NULL
>  #define	xhci_bus_resume		NULL
>  #define	xhci_get_resuming_ports	NULL
> 
> -- 
> 2.55.0
> 

  reply	other threads:[~2026-10-03  0:31 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-29 15:54 [PATCH v4 0/4] DWC3 link tunneling state reporting Konrad Dybcio
2026-09-29 15:54 ` [PATCH v4 1/4] usb: xhci: debugfs: Expose the USB3 tunneling ext_cap register value Konrad Dybcio
2026-09-29 15:54 ` [PATCH v4 2/4] usb: xhci: Honor PORTSC.TM if valid Konrad Dybcio
2026-09-29 15:54 ` [PATCH v4 3/4] usb: xhci: Use update_device overrides for tunnel reporting Konrad Dybcio
2026-10-03  0:30   ` Thinh Nguyen [this message]
2026-10-13 16:25     ` Konrad Dybcio
2026-09-29 15:54 ` [PATCH v4 4/4] usb: dwc3: Notify XHCI core of tunneled status Konrad Dybcio
2026-10-03  1:23   ` Thinh Nguyen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=asBLzaNbnBmG3mdx@vbox \
    --to=thinh.nguyen@synopsys.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=konrad.dybcio@oss.qualcomm.com \
    --cc=konradybcio@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=mika.westerberg@linux.intel.com \
    --cc=rthoorpu@qti.qualcomm.com \
    --cc=sven@kernel.org \
    --cc=usb4-upstream@oss.qualcomm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.