thunderbolt: Allow multiple DMA tunnels over a single XDomain connection
Currently we have had an artificial limitation of a single DMA tunnel
per XDomain connection. However, hardware wise there is no such limit
and software based connection manager can take advantage of all the DMA
rings available on the host to establish tunnels.
For this reason make the tb_xdomain_[enable|disable]_paths() to take the
DMA ring and HopID as parameter instead of storing them in the struct
tb_xdomain. We also add API functions to allocate input and output
HopIDs of the XDomain connection that the service drivers can use
instead of hard-coding.
Also convert the two existing service drivers over to this API.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 30e17f7..eb15022 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -1075,7 +1075,9 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
return 0;
}
-static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
+ int transmit_path, int transmit_ring,
+ int receive_path, int receive_ring)
{
struct tb_cm *tcm = tb_priv(tb);
struct tb_port *nhi_port, *dst_port;
@@ -1087,9 +1089,8 @@ static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI);
mutex_lock(&tb->lock);
- tunnel = tb_tunnel_alloc_dma(tb, nhi_port, dst_port, xd->transmit_ring,
- xd->transmit_path, xd->receive_ring,
- xd->receive_path);
+ tunnel = tb_tunnel_alloc_dma(tb, nhi_port, dst_port, transmit_path,
+ transmit_ring, receive_path, receive_ring);
if (!tunnel) {
mutex_unlock(&tb->lock);
return -ENOMEM;
@@ -1108,29 +1109,40 @@ static int tb_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
return 0;
}
-static void __tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+static void __tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
+ int transmit_path, int transmit_ring,
+ int receive_path, int receive_ring)
{
- struct tb_port *dst_port;
- struct tb_tunnel *tunnel;
+ struct tb_cm *tcm = tb_priv(tb);
+ struct tb_port *nhi_port, *dst_port;
+ struct tb_tunnel *tunnel, *n;
struct tb_switch *sw;
sw = tb_to_switch(xd->dev.parent);
dst_port = tb_port_at(xd->route, sw);
+ nhi_port = tb_switch_find_port(tb->root_switch, TB_TYPE_NHI);
- /*
- * It is possible that the tunnel was already teared down (in
- * case of cable disconnect) so it is fine if we cannot find it
- * here anymore.
- */
- tunnel = tb_find_tunnel(tb, TB_TUNNEL_DMA, NULL, dst_port);
- tb_deactivate_and_free_tunnel(tunnel);
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
+ if (!tb_tunnel_is_dma(tunnel))
+ continue;
+ if (tunnel->src_port != nhi_port || tunnel->dst_port != dst_port)
+ continue;
+
+ if (tb_tunnel_match_dma(tunnel, transmit_path, transmit_ring,
+ receive_path, receive_ring))
+ tb_deactivate_and_free_tunnel(tunnel);
+ }
}
-static int tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd)
+static int tb_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
+ int transmit_path, int transmit_ring,
+ int receive_path, int receive_ring)
{
if (!xd->is_unplugged) {
mutex_lock(&tb->lock);
- __tb_disconnect_xdomain_paths(tb, xd);
+ __tb_disconnect_xdomain_paths(tb, xd, transmit_path,
+ transmit_ring, receive_path,
+ receive_ring);
mutex_unlock(&tb->lock);
}
return 0;
@@ -1206,12 +1218,12 @@ static void tb_handle_hotplug(struct work_struct *work)
* tb_xdomain_remove() so setting XDomain as
* unplugged here prevents deadlock if they call
* tb_xdomain_disable_paths(). We will tear down
- * the path below.
+ * all the tunnels below.
*/
xd->is_unplugged = true;
tb_xdomain_remove(xd);
port->xdomain = NULL;
- __tb_disconnect_xdomain_paths(tb, xd);
+ __tb_disconnect_xdomain_paths(tb, xd, -1, -1, -1, -1);
tb_xdomain_put(xd);
tb_port_unconfigure_xdomain(port);
} else if (tb_port_is_dpout(port) || tb_port_is_dpin(port)) {