thunderbolt: Verify PCIe adapter in detect state before tunnel setup

The USB4 Connection Manager guide suggests that a PCIe downstream and
PCIe upstream adapters of the USB4 router is in the Detect state before
setting up a PCIe tunnel.

Add this check by verifying the LTSSM field in ADP_PCIE_CS_0 before
tunnel setup.

Signed-off-by: Gil Fine <gil.fine@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
Gil Fine 2026-05-06 15:37:06 +03:00 committed by Mika Westerberg
parent b69af182b5
commit 69a7b98770
4 changed files with 75 additions and 0 deletions

View File

@ -1481,6 +1481,7 @@ int usb4_dp_port_allocate_bandwidth(struct tb_port *port, int bw);
int usb4_dp_port_requested_bandwidth(struct tb_port *port);
int usb4_pci_port_set_ext_encapsulation(struct tb_port *port, bool enable);
int usb4_pci_port_ltssm_state(struct tb_port *port);
static inline bool tb_is_usb4_port_device(const struct device *dev)
{

View File

@ -473,10 +473,25 @@ struct tb_regs_port_header {
/* PCIe adapter registers */
#define ADP_PCIE_CS_0 0x00
#define ADP_PCIE_CS_0_LTSSM_MASK GENMASK(28, 25)
#define ADP_PCIE_CS_0_PE BIT(31)
#define ADP_PCIE_CS_1 0x01
#define ADP_PCIE_CS_1_EE BIT(0)
enum tb_pcie_ltssm_state {
USB4_PCIE_LTSSM_DETECT,
USB4_PCIE_LTSSM_POLLING,
USB4_PCIE_LTSSM_CONFIG,
USB4_PCIE_LTSSM_CONFIG_IDLE,
USB4_PCIE_LTSSM_RECOVERY,
USB4_PCIE_LTSSM_RECOVERY_IDLE,
USB4_PCIE_LTSSM_L0,
USB4_PCIE_LTSSM_L1,
USB4_PCIE_LTSSM_L2,
USB4_PCIE_LTSSM_DISABLED,
USB4_PCIE_LTSSM_HOT_RESET,
};
/* USB adapter registers */
#define ADP_USB3_CS_0 0x00
#define ADP_USB3_CS_0_V BIT(30)

View File

@ -290,6 +290,40 @@ static inline void tb_tunnel_changed(struct tb_tunnel *tunnel)
tunnel->src_port, tunnel->dst_port);
}
static int tb_pci_port_ltssm_state_detect(struct tb_port *port)
{
ktime_t timeout = ktime_add_ms(ktime_get(), 500);
do {
int ret;
ret = usb4_pci_port_ltssm_state(port);
if (ret < 0)
return ret;
if (ret == USB4_PCIE_LTSSM_DETECT)
return 0;
fsleep(50);
} while (ktime_before(ktime_get(), timeout));
return -ETIMEDOUT;
}
static int tb_pci_pre_activate(struct tb_tunnel *tunnel)
{
struct tb_port *down = tunnel->src_port;
struct tb_port *up = tunnel->dst_port;
int ret;
ret = tb_switch_is_usb4(down->sw) ?
tb_pci_port_ltssm_state_detect(down) : 0;
if (ret)
return ret;
return tb_switch_is_usb4(up->sw) ?
tb_pci_port_ltssm_state_detect(up) : 0;
}
static int tb_pci_set_ext_encapsulation(struct tb_tunnel *tunnel, bool enable)
{
struct tb_port *port = tb_upstream_port(tunnel->dst_port->sw);
@ -505,6 +539,7 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
if (!tunnel)
return NULL;
tunnel->pre_activate = tb_pci_pre_activate;
tunnel->activate = tb_pci_activate;
tunnel->src_port = down;
tunnel->dst_port = up;

View File

@ -3145,3 +3145,27 @@ int usb4_pci_port_set_ext_encapsulation(struct tb_port *port, bool enable)
return tb_port_write(port, &val, TB_CFG_PORT,
port->cap_adap + ADP_PCIE_CS_1, 1);
}
/**
* usb4_pci_port_ltssm_state() - Read PCIe adapter LTSSM state
* @port: PCIe adapter
*
* Return:
* * LTSSM state of @port.
* * Negative errno - On failure.
*/
int usb4_pci_port_ltssm_state(struct tb_port *port)
{
u32 val;
int ret;
if (!tb_port_is_pcie_down(port) && !tb_port_is_pcie_up(port))
return -EINVAL;
ret = tb_port_read(port, &val, TB_CFG_PORT,
port->cap_adap + ADP_PCIE_CS_0, 1);
if (ret)
return ret;
return FIELD_GET(ADP_PCIE_CS_0_LTSSM_MASK, val);
}