summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/thunderbolt/icm.c10
-rw-r--r--drivers/thunderbolt/xdomain.c25
-rw-r--r--include/linux/thunderbolt.h2
3 files changed, 31 insertions, 6 deletions
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index 2f93a7bccad5..c492995166f7 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -587,6 +587,11 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
struct icm_fr_pkg_approve_xdomain request;
int ret;
+ if (atomic_read(&xd->ntunnels) >= 1) {
+ tb_warn(tb, "only one tunnel is supported by the firmware\n");
+ return -EOPNOTSUPP;
+ }
+
memset(&request, 0, sizeof(request));
request.hdr.code = ICM_APPROVE_XDOMAIN;
request.link_info = xd->depth << ICM_LINK_INFO_DEPTH_SHIFT | xd->link;
@@ -1158,6 +1163,11 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
struct icm_tr_pkg_approve_xdomain request;
int ret;
+ if (atomic_read(&xd->ntunnels) >= 1) {
+ tb_warn(tb, "only one tunnel is supported by the firmware\n");
+ return -EOPNOTSUPP;
+ }
+
memset(&request, 0, sizeof(request));
request.hdr.code = ICM_APPROVE_XDOMAIN;
request.route_hi = upper_32_bits(xd->route);
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 9a30fe36c4be..6e83f93eee83 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -2038,6 +2038,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
INIT_DELAYED_WORK(&xd->state_work, tb_xdomain_state_work);
INIT_DELAYED_WORK(&xd->properties_changed_work,
tb_xdomain_properties_changed);
+ atomic_set(&xd->ntunnels, 0);
xd->local_uuid = kmemdup(local_uuid, sizeof(uuid_t), GFP_KERNEL);
if (!xd->local_uuid)
@@ -2328,9 +2329,15 @@ int tb_xdomain_enable_paths(struct tb_xdomain *xd, int transmit_path,
int transmit_ring, int receive_path,
int receive_ring)
{
- return tb_domain_approve_xdomain_paths(xd->tb, xd, transmit_path,
- transmit_ring, receive_path,
- receive_ring);
+ int ret;
+
+ ret = tb_domain_approve_xdomain_paths(xd->tb, xd, transmit_path,
+ transmit_ring, receive_path,
+ receive_ring);
+ if (ret)
+ return ret;
+ atomic_inc(&xd->ntunnels);
+ return 0;
}
EXPORT_SYMBOL_GPL(tb_xdomain_enable_paths);
@@ -2353,9 +2360,15 @@ int tb_xdomain_disable_paths(struct tb_xdomain *xd, int transmit_path,
int transmit_ring, int receive_path,
int receive_ring)
{
- return tb_domain_disconnect_xdomain_paths(xd->tb, xd, transmit_path,
- transmit_ring, receive_path,
- receive_ring);
+ int ret;
+
+ ret = tb_domain_disconnect_xdomain_paths(xd->tb, xd, transmit_path,
+ transmit_ring, receive_path,
+ receive_ring);
+ if (ret)
+ return ret;
+ atomic_dec(&xd->ntunnels);
+ return 0;
}
EXPORT_SYMBOL_GPL(tb_xdomain_disable_paths);
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index a5ef7100a6d3..bbdbbc84c999 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -228,6 +228,7 @@ enum tb_link_width {
* changed notification
* @bonding_possible: True if lane bonding is possible on local side
* @target_link_width: Target link width from the remote host
+ * @ntunnels: Keeps track of how many tunnels go through this XDomain
* @link: Root switch link the remote domain is connected (ICM only)
* @depth: Depth in the chain the remote domain is connected (ICM only)
*
@@ -273,6 +274,7 @@ struct tb_xdomain {
int properties_changed_retries;
bool bonding_possible;
u8 target_link_width;
+ atomic_t ntunnels;
u8 link;
u8 depth;
};