linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-usb@vger.kernel.org
Cc: Andreas Noever <andreas.noever@gmail.com>,
	Michael Jamet <michael.jamet@intel.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Yehezkel Bernat <YehezkelShB@gmail.com>,
	Rajmohan Mani <rajmohan.mani@intel.com>,
	Nicholas Johnson <nicholas.johnson-opensource@outlook.com.au>,
	Lukas Wunner <lukas@wunner.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Mario.Limonciello@dell.com,
	Anthony Wong <anthony.wong@canonical.com>,
	linux-kernel@vger.kernel.org
Subject: [RFC PATCH 20/22] thunderbolt: Add support for USB tunnels
Date: Tue,  1 Oct 2019 14:38:28 +0300	[thread overview]
Message-ID: <20191001113830.13028-21-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20191001113830.13028-1-mika.westerberg@linux.intel.com>

From: Rajmohan Mani <rajmohan.mani@intel.com>

USB4 added a capability to tunnel USB 3.x protocol over the USB4
fabric. USB4 device routers may include integrated SuperSpeed HUB or a
function or both. USB tunneling follows PCIe so that the tunnel is
created between the parent and the child router from USB downstream
adapter port to USB upstream adapter port over a single USB4 link.

This adds support for USB tunneling and also capability to discover
existing USB tunnels (for example created by connection manager in boot
firmware).

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Co-developed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/switch.c  |  35 ++++++++
 drivers/thunderbolt/tb.c      | 153 ++++++++++++++++++++++++++------
 drivers/thunderbolt/tb.h      |  15 ++++
 drivers/thunderbolt/tb_regs.h |   9 +-
 drivers/thunderbolt/tunnel.c  | 158 +++++++++++++++++++++++++++++++++-
 drivers/thunderbolt/tunnel.h  |   9 ++
 drivers/thunderbolt/usb4.c    |  41 ++++++++-
 7 files changed, 393 insertions(+), 27 deletions(-)

diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 58e3f54ddbb9..5a3236fefb76 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -1025,11 +1025,46 @@ bool tb_port_is_enabled(struct tb_port *port)
 	case TB_TYPE_DP_HDMI_OUT:
 		return tb_dp_port_is_enabled(port);
 
+	case TB_TYPE_USB_UP:
+	case TB_TYPE_USB_DOWN:
+		return tb_usb_port_is_enabled(port);
+
 	default:
 		return false;
 	}
 }
 
+/**
+ * tb_usb_port_is_enabled() - Is the USB adapter port enabled
+ * @port: USB port to check
+ */
+bool tb_usb_port_is_enabled(struct tb_port *port)
+{
+	u32 data;
+
+	if (tb_port_read(port, &data, TB_CFG_PORT,
+			 port->cap_adap + ADP_USB3_CS_0, 1))
+		return false;
+
+	return !!(data & ADP_USB3_CS_0_PE);
+}
+
+/**
+ * tb_usb_port_enable() - Enable USB adapter port
+ * @port: USB port to enable
+ * @enable: Enable/disable the USB adapter
+ */
+int tb_usb_port_enable(struct tb_port *port, bool enable)
+{
+	u32 word = enable ? (ADP_USB3_CS_0_PE | ADP_USB3_CS_0_V)
+			  : ADP_USB3_CS_0_V;
+
+	if (!port->cap_adap)
+		return -ENXIO;
+	return tb_port_write(port, &word, TB_CFG_PORT,
+			     port->cap_adap + ADP_USB3_CS_0, 1);
+}
+
 /**
  * tb_pci_port_is_enabled() - Is the PCIe adapter port enabled
  * @port: PCIe port to check
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index f2868c125637..6c468ba96e9a 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -116,6 +116,10 @@ static void tb_discover_tunnels(struct tb_switch *sw)
 			tunnel = tb_tunnel_discover_pci(tb, port);
 			break;
 
+		case TB_TYPE_USB_DOWN:
+			tunnel = tb_tunnel_discover_usb(tb, port);
+			break;
+
 		default:
 			break;
 		}
@@ -180,6 +184,117 @@ static int tb_enable_tmu(struct tb_switch *sw)
 	return tb_switch_tmu_enable(sw);
 }
 
+/**
+ * tb_find_unused_port() - return the first inactive port on @sw
+ * @sw: Switch to find the port on
+ * @type: Port type to look for
+ */
+static struct tb_port *tb_find_unused_port(struct tb_switch *sw,
+					   enum tb_port_type type)
+{
+	int i;
+
+	tb_switch_for_each_port(sw, i) {
+		if (tb_is_upstream_port(&sw->ports[i]))
+			continue;
+		if (sw->ports[i].config.type != type)
+			continue;
+		if (!sw->ports[i].cap_adap)
+			continue;
+		if (tb_port_is_enabled(&sw->ports[i]))
+			continue;
+		return &sw->ports[i];
+	}
+	return NULL;
+}
+
+static struct tb_port *tb_find_usb_down(struct tb_switch *sw,
+					const struct tb_port *port)
+{
+	struct tb_port *down;
+
+	down = usb4_switch_map_usb_down(sw, port);
+	if (down) {
+		if (WARN_ON(!tb_port_is_usb_down(down)))
+			goto out;
+		if (WARN_ON(tb_usb_port_is_enabled(down)))
+			goto out;
+
+		return down;
+	}
+
+out:
+	return tb_find_unused_port(sw, TB_TYPE_USB_DOWN);
+}
+
+static int tb_tunnel_usb(struct tb *tb, struct tb_switch *sw)
+{
+	struct tb_switch *parent = tb_switch_parent(sw);
+	struct tb_port *up, *down, *port;
+	struct tb_cm *tcm = tb_priv(tb);
+	struct tb_tunnel *tunnel;
+
+	up = tb_switch_find_port(sw, TB_TYPE_USB_UP);
+	if (!up)
+		return 0;
+
+	/*
+	 * Look up available down port. Since we are chaining it should
+	 * be found right above this switch.
+	 */
+	port = tb_port_at(tb_route(sw), parent);
+	down = tb_find_usb_down(parent, port);
+	if (!down)
+		return 0;
+
+	if (tb_route(parent)) {
+		struct tb_port *parent_up;
+		/*
+		 * Check first that the parent switch has its upstream
+		 * USB port enabled. Otherwise the chain is not complete
+		 * and there is no point setting up a new tunnel.
+		 */
+		parent_up = tb_switch_find_port(parent, TB_TYPE_USB_UP);
+		if (!parent_up || !tb_port_is_enabled(parent_up))
+			return 0;
+	}
+
+	tunnel = tb_tunnel_alloc_usb(tb, up, down);
+	if (!tunnel)
+		return -ENOMEM;
+
+	if (tb_tunnel_activate(tunnel)) {
+		tb_port_info(up,
+			     "USB tunnel activation failed, aborting\n");
+		tb_tunnel_free(tunnel);
+		return -EIO;
+	}
+
+	list_add_tail(&tunnel->list, &tcm->tunnel_list);
+	return 0;
+}
+
+static int tb_create_usb_tunnels(struct tb_switch *sw)
+{
+	int i, ret;
+
+	if (tb_route(sw)) {
+		ret = tb_tunnel_usb(sw->tb, sw);
+		if (ret)
+			return ret;
+	}
+
+	tb_switch_for_each_remote_port(sw, i) {
+		struct tb_port *port = &sw->ports[i];
+
+		ret = tb_create_usb_tunnels(port->remote->sw);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static void tb_scan_port(struct tb_port *port);
 
 /**
@@ -285,6 +400,15 @@ static void tb_scan_port(struct tb_port *port)
 	if (tb_enable_tmu(sw))
 		tb_sw_warn(sw, "failed to enable TMU\n");
 
+	/*
+	 * Create USB tunnels only when the switch is plugged to the
+	 * domain. This is because we scan the domain also during
+	 * discovery and want to discover existing USB tunnels before we
+	 * create any new.
+	 */
+	if (tcm->hotplug_active && tb_tunnel_usb(sw->tb, sw))
+		tb_sw_warn(sw, "USB tunnel creation failed\n");
+
 	tb_scan_switch(sw);
 }
 
@@ -365,30 +489,6 @@ static void tb_free_unplugged_children(struct tb_switch *sw)
 	}
 }
 
-/**
- * tb_find_unused_port() - return the first inactive port on @sw
- * @sw: Switch to find the port on
- * @type: Port type to look for
- */
-static struct tb_port *tb_find_unused_port(struct tb_switch *sw,
-					   enum tb_port_type type)
-{
-	int i;
-
-	tb_switch_for_each_port(sw, i) {
-		if (tb_is_upstream_port(&sw->ports[i]))
-			continue;
-		if (sw->ports[i].config.type != type)
-			continue;
-		if (!sw->ports[i].cap_adap)
-			continue;
-		if (tb_port_is_enabled(&sw->ports[i]))
-			continue;
-		return &sw->ports[i];
-	}
-	return NULL;
-}
-
 static struct tb_port *tb_find_pcie_down(struct tb_switch *sw,
 					 const struct tb_port *port)
 {
@@ -890,6 +990,11 @@ static int tb_start(struct tb *tb)
 	tb_scan_switch(tb->root_switch);
 	/* Find out tunnels created by the boot firmware */
 	tb_discover_tunnels(tb->root_switch);
+	/*
+	 * If the boot firmware did not create USB tunnels create them
+	 * now for the whole topology.
+	 */
+	tb_create_usb_tunnels(tb->root_switch);
 	/* Add DP IN resources for the root switch */
 	tb_add_dp_resources(tb->root_switch);
 	/* Make the discovered switches available to the userspace */
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 087fd6d6ef9a..fbeb8bab77e5 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -432,6 +432,16 @@ static inline bool tb_port_is_dpout(const struct tb_port *port)
 	return port && port->config.type == TB_TYPE_DP_HDMI_OUT;
 }
 
+static inline bool tb_port_is_usb_down(const struct tb_port *port)
+{
+	return port && port->config.type == TB_TYPE_USB_DOWN;
+}
+
+static inline bool tb_port_is_usb_up(const struct tb_port *port)
+{
+	return port && port->config.type == TB_TYPE_USB_UP;
+}
+
 static inline int tb_sw_read(struct tb_switch *sw, void *buffer,
 			     enum tb_cfg_space space, u32 offset, u32 length)
 {
@@ -760,6 +770,9 @@ int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
 int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
 bool tb_port_is_enabled(struct tb_port *port);
 
+bool tb_usb_port_is_enabled(struct tb_port *port);
+int tb_usb_port_enable(struct tb_port *port, bool enable);
+
 bool tb_pci_port_is_enabled(struct tb_port *port);
 int tb_pci_port_enable(struct tb_port *port, bool enable);
 
@@ -842,6 +855,8 @@ int usb4_switch_alloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
 int usb4_switch_dealloc_dp_resource(struct tb_switch *sw, struct tb_port *in);
 struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
 					  const struct tb_port *port);
+struct tb_port *usb4_switch_map_usb_down(struct tb_switch *sw,
+					 const struct tb_port *port);
 
 int usb4_port_unlock(struct tb_port *port);
 #endif
diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h
index ec1a5d1f7c94..062676229ac1 100644
--- a/drivers/thunderbolt/tb_regs.h
+++ b/drivers/thunderbolt/tb_regs.h
@@ -180,6 +180,7 @@ struct tb_regs_switch_header {
 #define ROUTER_CS_5_SLP				BIT(0)
 #define ROUTER_CS_5_C3S				BIT(23)
 #define ROUTER_CS_5_PTO				BIT(24)
+#define ROUTER_CS_5_UTO				BIT(25)
 #define ROUTER_CS_5_HCO				BIT(26)
 #define ROUTER_CS_5_CV				BIT(31)
 #define ROUTER_CS_6				0x06
@@ -221,7 +222,8 @@ enum tb_port_type {
 	TB_TYPE_DP_HDMI_OUT	= 0x0e0102,
 	TB_TYPE_PCIE_DOWN	= 0x100101,
 	TB_TYPE_PCIE_UP		= 0x100102,
-	/* TB_TYPE_USB		= 0x200000, lower order bits are not known */
+	TB_TYPE_USB_DOWN	= 0x200101,
+	TB_TYPE_USB_UP		= 0x200102,
 };
 
 /* Present on every port in TB_CF_PORT at address zero. */
@@ -331,6 +333,11 @@ struct tb_regs_port_header {
 #define ADP_PCIE_CS_0				0x00
 #define ADP_PCIE_CS_0_PE			BIT(31)
 
+/* USB adapter registers */
+#define ADP_USB3_CS_0				0x00
+#define ADP_USB3_CS_0_V				BIT(30)
+#define ADP_USB3_CS_0_PE			BIT(31)
+
 /* Hop register from TB_CFG_HOPS. 8 byte per entry. */
 struct tb_regs_hop {
 	/* DWORD 0 */
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index e8e387c4211f..299b77665d83 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -19,6 +19,12 @@
 #define TB_PCI_PATH_DOWN		0
 #define TB_PCI_PATH_UP			1
 
+/* USB adapters use always HopID of 8 for both directions */
+#define TB_USB_HOPID			8
+
+#define TB_USB_PATH_DOWN		0
+#define TB_USB_PATH_UP			1
+
 /* DP adapters use HopID 8 for AUX and 9 for Video */
 #define TB_DP_AUX_TX_HOPID		8
 #define TB_DP_AUX_RX_HOPID		8
@@ -31,7 +37,7 @@
 #define TB_DMA_PATH_OUT			0
 #define TB_DMA_PATH_IN			1
 
-static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA" };
+static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB"};
 
 #define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...)                   \
 	do {                                                            \
@@ -838,6 +844,156 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
 	return tunnel;
 }
 
+static int tb_usb_activate(struct tb_tunnel *tunnel, bool activate)
+{
+	int res;
+
+	res = tb_usb_port_enable(tunnel->src_port, activate);
+	if (res)
+		return res;
+
+	if (tb_port_is_usb_up(tunnel->dst_port))
+		return tb_usb_port_enable(tunnel->dst_port, activate);
+
+	return 0;
+}
+
+static void tb_usb_init_path(struct tb_path *path)
+{
+	path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL;
+	path->egress_shared_buffer = TB_PATH_NONE;
+	path->ingress_fc_enable = TB_PATH_ALL;
+	path->ingress_shared_buffer = TB_PATH_NONE;
+	path->priority = 3;
+	path->weight = 3;
+	path->drop_packages = 0;
+	path->nfc_credits = 0;
+	path->hops[0].initial_credits = 7;
+	path->hops[1].initial_credits =
+		tb_initial_credits(path->hops[1].in_port->sw);
+}
+
+/**
+ * tb_tunnel_discover_usb() - Discover existing USB tunnels
+ * @tb: Pointer to the domain structure
+ * @down: USB downstream adapter
+ *
+ * If @down adapter is active, follows the tunnel to the USB upstream
+ * adapter and back. Returns the discovered tunnel or %NULL if there was
+ * no tunnel.
+ */
+struct tb_tunnel *tb_tunnel_discover_usb(struct tb *tb, struct tb_port *down)
+{
+	struct tb_tunnel *tunnel;
+	struct tb_path *path;
+
+	if (!tb_usb_port_is_enabled(down))
+		return NULL;
+
+	tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_USB);
+	if (!tunnel)
+		return NULL;
+
+	tunnel->activate = tb_usb_activate;
+	tunnel->src_port = down;
+
+	/*
+	 * Discover both paths even if they are not complete. We will
+	 * clean them up by calling tb_tunnel_deactivate() below in that
+	 * case.
+	 */
+	path = tb_path_discover(down, TB_USB_HOPID, NULL, -1,
+				&tunnel->dst_port, "USB Up");
+	if (!path) {
+		/* Just disable the downstream port */
+		tb_usb_port_enable(down, false);
+		goto err_free;
+	}
+	tunnel->paths[TB_USB_PATH_UP] = path;
+	tb_usb_init_path(tunnel->paths[TB_USB_PATH_UP]);
+
+	path = tb_path_discover(tunnel->dst_port, -1, down, TB_USB_HOPID, NULL,
+				"USB Down");
+	if (!path)
+		goto err_deactivate;
+	tunnel->paths[TB_USB_PATH_DOWN] = path;
+	tb_usb_init_path(tunnel->paths[TB_USB_PATH_DOWN]);
+
+	/* Validate that the tunnel is complete */
+	if (!tb_port_is_usb_up(tunnel->dst_port)) {
+		tb_port_warn(tunnel->dst_port,
+			     "path does not end on an USB adapter, cleaning up\n");
+		goto err_deactivate;
+	}
+
+	if (down != tunnel->src_port) {
+		tb_tunnel_warn(tunnel, "path is not complete, cleaning up\n");
+		goto err_deactivate;
+	}
+
+	if (!tb_usb_port_is_enabled(tunnel->dst_port)) {
+		tb_tunnel_warn(tunnel,
+			       "tunnel is not fully activated, cleaning up\n");
+		goto err_deactivate;
+	}
+
+	tb_tunnel_dbg(tunnel, "discovered\n");
+	return tunnel;
+
+err_deactivate:
+	tb_tunnel_deactivate(tunnel);
+err_free:
+	tb_tunnel_free(tunnel);
+
+	return NULL;
+}
+
+/**
+ * tb_tunnel_alloc_usb() - allocate a USB tunnel
+ * @tb: Pointer to the domain structure
+ * @up: USB upstream adapter port
+ * @down: USB downstream adapter port
+ *
+ * Allocate an USB tunnel. The ports must be of type @TB_TYPE_USB_UP and
+ * @TB_TYPE_USB_DOWN.
+ *
+ * Return: Returns a tb_tunnel on success or %NULL on failure.
+ */
+struct tb_tunnel *tb_tunnel_alloc_usb(struct tb *tb, struct tb_port *up,
+				      struct tb_port *down)
+{
+	struct tb_tunnel *tunnel;
+	struct tb_path *path;
+
+	tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_USB);
+	if (!tunnel)
+		return NULL;
+
+	tunnel->activate = tb_usb_activate;
+	tunnel->src_port = down;
+	tunnel->dst_port = up;
+
+	path = tb_path_alloc(tb, down, TB_USB_HOPID, up, TB_USB_HOPID, 0,
+			     "USB Down");
+	if (!path) {
+		tb_tunnel_free(tunnel);
+		return NULL;
+	}
+	tb_usb_init_path(path);
+	tunnel->paths[TB_USB_PATH_DOWN] = path;
+
+	path = tb_path_alloc(tb, up, TB_USB_HOPID, down, TB_USB_HOPID, 0,
+			     "USB Up");
+	if (!path) {
+		tb_tunnel_free(tunnel);
+		return NULL;
+	}
+	tb_usb_init_path(path);
+	tunnel->paths[TB_USB_PATH_UP] = path;
+
+	return tunnel;
+}
+
 /**
  * tb_tunnel_free() - free a tunnel
  * @tunnel: Tunnel to be freed
diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h
index ba888da005f5..83c6723fe8d8 100644
--- a/drivers/thunderbolt/tunnel.h
+++ b/drivers/thunderbolt/tunnel.h
@@ -15,6 +15,7 @@ enum tb_tunnel_type {
 	TB_TUNNEL_PCI,
 	TB_TUNNEL_DP,
 	TB_TUNNEL_DMA,
+	TB_TUNNEL_USB,
 };
 
 /**
@@ -57,6 +58,9 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
 				      struct tb_port *dst, int transmit_ring,
 				      int transmit_path, int receive_ring,
 				      int receive_path);
+struct tb_tunnel *tb_tunnel_discover_usb(struct tb *tb, struct tb_port *down);
+struct tb_tunnel *tb_tunnel_alloc_usb(struct tb *tb, struct tb_port *up,
+				      struct tb_port *down);
 
 void tb_tunnel_free(struct tb_tunnel *tunnel);
 int tb_tunnel_activate(struct tb_tunnel *tunnel);
@@ -82,5 +86,10 @@ static inline bool tb_tunnel_is_dma(const struct tb_tunnel *tunnel)
 	return tunnel->type == TB_TUNNEL_DMA;
 }
 
+static inline bool tb_tunnel_is_usb(const struct tb_tunnel *tunnel)
+{
+	return tunnel->type == TB_TUNNEL_USB;
+}
+
 #endif
 
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
index 4b0997292b43..24f60f7523b8 100644
--- a/drivers/thunderbolt/usb4.c
+++ b/drivers/thunderbolt/usb4.c
@@ -226,10 +226,19 @@ int usb4_switch_setup(struct tb_switch *sw)
 
 	parent = tb_switch_parent(sw);
 
+	if (tb_switch_find_port(parent, TB_TYPE_USB_DOWN)) {
+		val |= ROUTER_CS_5_UTO;
+		xhci = false;
+	}
+
 	/* Only enable PCIe tunneling if the parent router supports it */
 	if (tb_switch_find_port(parent, TB_TYPE_PCIE_DOWN)) {
 		val |= ROUTER_CS_5_PTO;
-		/* xHCI can be enabled if PCIe tunneling is supported */
+		/*
+		 * xHCI can be enabled if PCIe tunneling is supported
+		 * and the parent does not have any USB dowstream
+		 * adapters (so we cannot do USB tunneling).
+		 */
 		if (xhci & ROUTER_CS_6_HCI)
 			val |= ROUTER_CS_5_HCO;
 	}
@@ -701,6 +710,36 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw,
 	return NULL;
 }
 
+/**
+ * usb4_switch_map_usb_down() - Map USB4 port to a USB downstream adapter
+ * @sw: USB4 router
+ * @port: USB4 port
+ *
+ * USB4 routers have direct mapping between USB4 ports and USB 3.x
+ * downstream adapters where the USB 3.x topology is extended. This
+ * function returns the corresponding downstream USB 3.x adapter or
+ * %NULL if no such mapping was possible.
+ */
+struct tb_port *usb4_switch_map_usb_down(struct tb_switch *sw,
+					 const struct tb_port *port)
+{
+	int usb4_idx = usb4_port_idx(sw, port);
+	int i, usb_idx = 0;
+
+	/* Find USB down port matching usb4_port */
+	tb_switch_for_each_port(sw, i) {
+		if (tb_port_is_usb_down(&sw->ports[i])) {
+			if (usb_idx == usb4_idx &&
+			    !tb_usb_port_is_enabled(&sw->ports[i])) {
+				return &sw->ports[i];
+			}
+			usb_idx++;
+		}
+	}
+
+	return NULL;
+}
+
 /**
  * usb4_port_unlock() - Unlock USB4 downstream port
  * @port: USB4 port to unlock
-- 
2.23.0


  parent reply	other threads:[~2019-10-01 11:39 UTC|newest]

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-01 11:38 [RFC PATCH 00/22] thunderbolt: Add support for USB4 Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 01/22] thunderbolt: Introduce tb_switch_is_icm() Mika Westerberg
2019-10-01 12:10   ` Greg Kroah-Hartman
2019-10-01 12:46     ` Mika Westerberg
2019-10-01 13:36       ` Mario.Limonciello
2019-10-01 13:48         ` Mika Westerberg
2019-10-01 13:50           ` Mario.Limonciello
2019-10-01 13:52             ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 02/22] thunderbolt: Log switch route string on config read/write timeout Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 03/22] thunderbolt: Log warning if adding switch fails Mika Westerberg
2019-10-01 12:18   ` Greg Kroah-Hartman
2019-10-01 12:48     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 04/22] thunderbolt: Make tb_sw_write() take const parameter Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 05/22] thunderbolt: Add helper macros to iterate over switch ports Mika Westerberg
2019-10-02 14:17   ` Oliver Neukum
2019-10-02 14:28     ` Mika Westerberg
2019-10-06 12:15       ` Lukas Wunner
2019-10-01 11:38 ` [RFC PATCH 06/22] thunderbolt: Add support for lane bonding Mika Westerberg
2019-10-01 12:38   ` Greg Kroah-Hartman
2019-10-01 12:53     ` Mika Westerberg
2019-10-02 14:21       ` Oliver Neukum
2019-10-02 14:30         ` Mika Westerberg
2019-10-03  8:25           ` Oliver Neukum
2019-10-03  8:53             ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 07/22] thunderbolt: Add default linking between ports if not provided by DROM Mika Westerberg
2019-10-01 12:39   ` Greg Kroah-Hartman
2019-10-01 13:14     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 08/22] thunderbolt: Add downstream PCIe port mappings for Alpine and Titan Ridge Mika Westerberg
2019-10-01 12:40   ` Greg Kroah-Hartman
2019-10-01 13:27     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 09/22] thunderbolt: Convert basic adapter register names to follow the USB4 spec Mika Westerberg
2019-10-01 12:41   ` Greg Kroah-Hartman
2019-10-01 13:28     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 10/22] thunderbolt: Convert PCIe adapter register names to use USB4 names Mika Westerberg
2019-10-01 12:42   ` Greg Kroah-Hartman
2019-10-01 11:38 ` [RFC PATCH 11/22] thunderbolt: Convert DP adapter register names to follow the USB4 spec Mika Westerberg
2019-10-01 12:42   ` Greg Kroah-Hartman
2019-10-01 11:38 ` [RFC PATCH 12/22] thunderbolt: Add Display Port CM handshake for Titan Ridge devices Mika Westerberg
2019-10-01 12:44   ` Greg Kroah-Hartman
2019-10-01 13:30     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 13/22] thunderbolt: Add Display Port adapter pairing and resource management Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 14/22] thunderbolt: Add bandwidth management for Display Port tunnels Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 15/22] thunderbolt: Make tb_find_port() available to other files Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 16/22] thunderbolt: Call tb_eeprom_get_drom_offset() from tb_eeprom_read_n() Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 17/22] thunderbolt: Add initial support for USB4 Mika Westerberg
2019-10-01 12:47   ` Greg Kroah-Hartman
2019-10-01 13:09     ` Mika Westerberg
2019-10-01 14:53       ` Greg Kroah-Hartman
2019-10-01 14:59         ` Mario.Limonciello
2019-10-01 15:13           ` Mika Westerberg
2019-10-01 15:22           ` Greg KH
2019-10-01 15:32             ` Mika Westerberg
2019-10-01 15:07         ` Mika Westerberg
2019-10-01 15:19           ` Greg Kroah-Hartman
2019-10-01 15:26             ` Mika Westerberg
2019-10-01 16:27           ` Oliver Neukum
2019-10-02  8:30             ` Mika Westerberg
2019-10-02  8:39               ` Greg Kroah-Hartman
2019-10-02  8:49                 ` Mika Westerberg
2019-10-01 17:05   ` Mario.Limonciello
2019-10-01 18:14     ` Mario.Limonciello
2019-10-02  8:39       ` Mika Westerberg
2019-10-02 15:09         ` Mario.Limonciello
2019-10-02 15:36           ` Yehezkel Bernat
2019-10-02 16:00             ` Mario.Limonciello
2019-10-03  8:00               ` Mika Westerberg
2019-10-03 14:41                 ` Mario.Limonciello
2019-10-04  7:54                   ` Mika Westerberg
2019-10-04  8:07                     ` Yehezkel Bernat
2019-10-04  8:19                       ` Mika Westerberg
2019-10-04 11:19                         ` Yehezkel Bernat
2019-10-04 14:05                           ` Mario.Limonciello
2019-10-04 14:19                             ` Mario.Limonciello
2019-10-04 14:21                             ` Mika Westerberg
     [not found]                               ` <1570201357.2.0@kellner.me>
2019-10-04 15:16                                 ` Mika Westerberg
2019-10-04 15:22                                   ` Christian Kellner
2019-10-02  8:34     ` Mika Westerberg
2019-10-02 15:04       ` Mario.Limonciello
2019-10-01 11:38 ` [RFC PATCH 18/22] thunderbolt: Make tb_switch_find_cap() available to other files Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 19/22] thunderbolt: Add support for Time Management Unit Mika Westerberg
2019-10-02 16:52   ` Mani, Rajmohan
2019-10-03  8:01     ` Mika Westerberg
2019-10-01 11:38 ` Mika Westerberg [this message]
2019-10-03  8:42   ` [RFC PATCH 20/22] thunderbolt: Add support for USB tunnels Oliver Neukum
2019-10-03  8:52     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 21/22] thunderbolt: Update documentation with the USB4 information Mika Westerberg
2019-10-01 14:17   ` Mario.Limonciello
2019-10-01 14:21     ` Mika Westerberg
2019-10-01 11:38 ` [RFC PATCH 22/22] thunderbolt: Do not start firmware unless asked by the user Mika Westerberg
2019-10-01 14:43   ` Mario.Limonciello
2019-10-01 14:58     ` Mika Westerberg
2019-10-01 16:53       ` Mario.Limonciello
2019-10-02  8:48         ` Mika Westerberg
2019-10-01 12:49 ` [RFC PATCH 00/22] thunderbolt: Add support for USB4 Greg Kroah-Hartman
2019-10-01 13:42   ` Mika Westerberg

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=20191001113830.13028-21-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=Mario.Limonciello@dell.com \
    --cc=YehezkelShB@gmail.com \
    --cc=andreas.noever@gmail.com \
    --cc=anthony.wong@canonical.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=michael.jamet@intel.com \
    --cc=nicholas.johnson-opensource@outlook.com.au \
    --cc=rajmohan.mani@intel.com \
    --cc=stern@rowland.harvard.edu \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).