]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
thunderbolt: Don't create multiple DMA tunnels on firmware connection manager
authorAlan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
Thu, 2 Oct 2025 12:37:22 +0000 (15:37 +0300)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 5 May 2026 11:53:46 +0000 (13:53 +0200)
Firmware connection manager supports only one DMA tunnel per XDomain
connection. Firmware prior Intel Titan Ridge failed the operation
directly but the same does not happen anymore on Titan Ridge and
forward. For this reason add an explicit check, and fail the operation
accordingly in the driver.

Signed-off-by: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
drivers/thunderbolt/icm.c
drivers/thunderbolt/xdomain.c
include/linux/thunderbolt.h

index 2f93a7bccad55d71cd632377423608c01279e91c..c492995166f7a5f12daed2c80c8495543c8da780 100644 (file)
@@ -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);
index 9a30fe36c4be419198baa38146d5ad046cffd4bf..6e83f93eee83a315a34eeffecb778dc70fba1ca7 100644 (file)
@@ -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);
 
index a5ef7100a6d3fb30c2f86efe1d646cb25f24c1ac..bbdbbc84c9998cb51fd7c0acda1412f1d90d9f26 100644 (file)
@@ -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;
 };