Skip to content

Commit 948ce83

Browse files
matnymangregkh
authored andcommitted
xhci: Add USB4 tunnel detection for USB3 devices on Intel hosts
Knowledge about tunneled devices is useful in order to correctly describe the relationship between tunneled USB3 device and USB4 Host Interface, ensuring proper suspend and resume order, and to be able to power down Thunderbolt if there is no need for tunneling. Intel hosts share if a USB3 connection is native or tunneled via vendor specific "SPR eSS PORT" registers. These vendor registers are available if host supports a vendor specific SPR shadow extended capability with ID 206. Registers are per USB3 port and 0x20 apart. Knowing the tunneling status of the device connected to roothub is enough as all its children will have the same status. Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 9299f12 commit 948ce83

File tree

4 files changed

+48
-0
lines changed

4 files changed

+48
-0
lines changed

drivers/usb/host/xhci-ext-caps.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#define XHCI_EXT_CAPS_DEBUG 10
4343
/* Vendor caps */
4444
#define XHCI_EXT_CAPS_VENDOR_INTEL 192
45+
#define XHCI_EXT_CAPS_INTEL_SPR_SHADOW 206
4546
/* USB Legacy Support Capability - section 7.1.1 */
4647
#define XHCI_HC_BIOS_OWNED (1 << 16)
4748
#define XHCI_HC_OS_OWNED (1 << 24)
@@ -64,6 +65,10 @@
6465
#define XHCI_HLC (1 << 19)
6566
#define XHCI_BLC (1 << 20)
6667

68+
/* Intel SPR shadow capability */
69+
#define XHCI_INTEL_SPR_ESS_PORT_OFFSET 0x8ac4 /* SuperSpeed port control */
70+
#define XHCI_INTEL_SPR_TUNEN BIT(4) /* Tunnel mode enabled */
71+
6772
/* command register values to disable interrupts and halt the HC */
6873
/* start/stop HC execution - do not write unless HC is halted*/
6974
#define XHCI_CMD_RUN (1 << 0)

drivers/usb/host/xhci-hub.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,37 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
752752
return xhci_reset(xhci, XHCI_RESET_SHORT_USEC);
753753
}
754754

755+
/**
756+
* xhci_port_is_tunneled() - Check if USB3 connection is tunneled over USB4
757+
* @xhci: xhci host controller
758+
* @port: USB3 port to be checked.
759+
*
760+
* Some hosts can detect if a USB3 connection is native USB3 or tunneled over
761+
* USB4. Intel hosts expose this via vendor specific extended capability 206
762+
* eSS PORT registers TUNEN (tunnel enabled) bit.
763+
*
764+
* A USB3 device must be connected to the port to detect the tunnel.
765+
*
766+
* Return: true if USB3 connection is tunneled over USB4
767+
*/
768+
bool xhci_port_is_tunneled(struct xhci_hcd *xhci, struct xhci_port *port)
769+
{
770+
void __iomem *base;
771+
u32 offset;
772+
773+
base = &xhci->cap_regs->hc_capbase;
774+
offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
775+
776+
if (offset && offset <= XHCI_INTEL_SPR_ESS_PORT_OFFSET) {
777+
offset = XHCI_INTEL_SPR_ESS_PORT_OFFSET + port->hcd_portnum * 0x20;
778+
779+
if (readl(base + offset) & XHCI_INTEL_SPR_TUNEN)
780+
return true;
781+
}
782+
783+
return false;
784+
}
785+
755786
void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,
756787
u32 link_state)
757788
{

drivers/usb/host/xhci.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4525,6 +4525,17 @@ static int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
45254525
struct xhci_port *port;
45264526
u32 capability;
45274527

4528+
/* Check if USB3 device at root port is tunneled over USB4 */
4529+
if (hcd->speed >= HCD_USB3 && !udev->parent->parent) {
4530+
port = xhci->usb3_rhub.ports[udev->portnum - 1];
4531+
4532+
if (xhci_port_is_tunneled(xhci, port))
4533+
dev_dbg(&udev->dev, "tunneled over USB4 link\n");
4534+
else
4535+
dev_dbg(&udev->dev, "native USB 3.x link\n");
4536+
return 0;
4537+
}
4538+
45284539
if (hcd->speed >= HCD_USB3 || !udev->lpm_capable || !xhci->hw_lpm_support)
45294540
return 0;
45304541

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
19291929
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
19301930
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
19311931
struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd);
1932+
bool xhci_port_is_tunneled(struct xhci_hcd *xhci, struct xhci_port *port);
19321933

19331934
void xhci_hc_died(struct xhci_hcd *xhci);
19341935

0 commit comments

Comments
 (0)