]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
thunderbolt: Use different lane for second DisplayPort tunnel
authorMika Westerberg <mika.westerberg@linux.intel.com>
Fri, 1 Apr 2022 14:24:28 +0000 (17:24 +0300)
committerStefan Bader <stefan.bader@canonical.com>
Fri, 26 Aug 2022 08:53:03 +0000 (10:53 +0200)
BugLink: https://bugs.launchpad.net/bugs/1982968
[ Upstream commit 9d2d0a5cf0ca063f417681cc33e767ce52615286 ]

Brad reported that on Apple hardware with Light Ridge or Falcon Ridge
controller, plugging in a chain of Thunderbolt displays (Light Ridge
based controllers) causes all kinds of tearing and flickering. The
reason for this is that on Thunderbolt 1 hardware there is no lane
bonding so we have two independent 10 Gb/s lanes, and currently Linux
tunnels both displays through the lane 1. This makes the displays to
share the 10 Gb/s bandwidth which may not be enough for higher
resolutions.

For this reason make the second tunnel go through the lane 0 instead.
This seems to match what the macOS connection manager is also doing.

Reported-by: Brad Campbell <lists2009@fnarfbargle.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Brad Campbell <lists2009@fnarfbargle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
drivers/thunderbolt/tb.c
drivers/thunderbolt/test.c
drivers/thunderbolt/tunnel.c
drivers/thunderbolt/tunnel.h

index 9f55da11cf4639ecfc01721a373d3468b2ee51b4..eeff620ef407bebf1fa5529661ffc2eec439b2b0 100644 (file)
@@ -862,7 +862,7 @@ static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in)
 
 static void tb_tunnel_dp(struct tb *tb)
 {
-       int available_up, available_down, ret;
+       int available_up, available_down, ret, link_nr;
        struct tb_cm *tcm = tb_priv(tb);
        struct tb_port *port, *in, *out;
        struct tb_tunnel *tunnel;
@@ -907,6 +907,20 @@ static void tb_tunnel_dp(struct tb *tb)
                return;
        }
 
+       /*
+        * This is only applicable to links that are not bonded (so
+        * when Thunderbolt 1 hardware is involved somewhere in the
+        * topology). For these try to share the DP bandwidth between
+        * the two lanes.
+        */
+       link_nr = 1;
+       list_for_each_entry(tunnel, &tcm->tunnel_list, list) {
+               if (tb_tunnel_is_dp(tunnel)) {
+                       link_nr = 0;
+                       break;
+               }
+       }
+
        /*
         * DP stream needs the domain to be active so runtime resume
         * both ends of the tunnel.
@@ -938,7 +952,8 @@ static void tb_tunnel_dp(struct tb *tb)
        tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n",
               available_up, available_down);
 
-       tunnel = tb_tunnel_alloc_dp(tb, in, out, available_up, available_down);
+       tunnel = tb_tunnel_alloc_dp(tb, in, out, link_nr, available_up,
+                                   available_down);
        if (!tunnel) {
                tb_port_dbg(out, "could not allocate DP tunnel\n");
                goto err_reclaim;
index 1f69bab236ee9c81edc9735cae630285f369ec63..66b6e665e96f0b801e615588327590cc6864bb17 100644 (file)
@@ -1348,7 +1348,7 @@ static void tb_test_tunnel_dp(struct kunit *test)
        in = &host->ports[5];
        out = &dev->ports[13];
 
-       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, tunnel != NULL);
        KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
        KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@@ -1394,7 +1394,7 @@ static void tb_test_tunnel_dp_chain(struct kunit *test)
        in = &host->ports[5];
        out = &dev4->ports[14];
 
-       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, tunnel != NULL);
        KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
        KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@@ -1444,7 +1444,7 @@ static void tb_test_tunnel_dp_tree(struct kunit *test)
        in = &dev2->ports[13];
        out = &dev5->ports[13];
 
-       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, tunnel != NULL);
        KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
        KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@@ -1509,7 +1509,7 @@ static void tb_test_tunnel_dp_max_length(struct kunit *test)
        in = &dev6->ports[13];
        out = &dev12->ports[13];
 
-       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, tunnel != NULL);
        KUNIT_EXPECT_EQ(test, tunnel->type, TB_TUNNEL_DP);
        KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in);
@@ -1627,7 +1627,7 @@ static void tb_test_tunnel_port_on_path(struct kunit *test)
        in = &dev2->ports[13];
        out = &dev5->ports[13];
 
-       dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, dp_tunnel != NULL);
 
        KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, in));
@@ -2009,7 +2009,7 @@ static void tb_test_credit_alloc_dp(struct kunit *test)
        in = &host->ports[5];
        out = &dev->ports[14];
 
-       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       tunnel = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, tunnel != NULL);
        KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3);
 
@@ -2245,7 +2245,7 @@ static struct tb_tunnel *TB_TEST_DP_TUNNEL1(struct kunit *test,
 
        in = &host->ports[5];
        out = &dev->ports[13];
-       dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       dp_tunnel1 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, dp_tunnel1 != NULL);
        KUNIT_ASSERT_EQ(test, dp_tunnel1->npaths, (size_t)3);
 
@@ -2282,7 +2282,7 @@ static struct tb_tunnel *TB_TEST_DP_TUNNEL2(struct kunit *test,
 
        in = &host->ports[6];
        out = &dev->ports[14];
-       dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 0, 0);
+       dp_tunnel2 = tb_tunnel_alloc_dp(NULL, in, out, 1, 0, 0);
        KUNIT_ASSERT_TRUE(test, dp_tunnel2 != NULL);
        KUNIT_ASSERT_EQ(test, dp_tunnel2->npaths, (size_t)3);
 
index 7588cf9c70e6e8c8f2b46fafff29670e716f857f..d85b41a093b97a24659d60513043558a6fd96bf4 100644 (file)
@@ -850,6 +850,7 @@ err_free:
  * @tb: Pointer to the domain structure
  * @in: DP in adapter port
  * @out: DP out adapter port
+ * @link_nr: Preferred lane adapter when the link is not bonded
  * @max_up: Maximum available upstream bandwidth for the DP tunnel (%0
  *         if not limited)
  * @max_down: Maximum available downstream bandwidth for the DP tunnel
@@ -861,8 +862,8 @@ err_free:
  * Return: Returns a tb_tunnel on success or NULL on failure.
  */
 struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
-                                    struct tb_port *out, int max_up,
-                                    int max_down)
+                                    struct tb_port *out, int link_nr,
+                                    int max_up, int max_down)
 {
        struct tb_tunnel *tunnel;
        struct tb_path **paths;
@@ -886,21 +887,21 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
        paths = tunnel->paths;
 
        path = tb_path_alloc(tb, in, TB_DP_VIDEO_HOPID, out, TB_DP_VIDEO_HOPID,
-                            1, "Video");
+                            link_nr, "Video");
        if (!path)
                goto err_free;
        tb_dp_init_video_path(path);
        paths[TB_DP_VIDEO_PATH_OUT] = path;
 
        path = tb_path_alloc(tb, in, TB_DP_AUX_TX_HOPID, out,
-                            TB_DP_AUX_TX_HOPID, 1, "AUX TX");
+                            TB_DP_AUX_TX_HOPID, link_nr, "AUX TX");
        if (!path)
                goto err_free;
        tb_dp_init_aux_path(path);
        paths[TB_DP_AUX_PATH_OUT] = path;
 
        path = tb_path_alloc(tb, out, TB_DP_AUX_RX_HOPID, in,
-                            TB_DP_AUX_RX_HOPID, 1, "AUX RX");
+                            TB_DP_AUX_RX_HOPID, link_nr, "AUX RX");
        if (!path)
                goto err_free;
        tb_dp_init_aux_path(path);
index 03e56076b5bcff2f792ef2137cb98090c018e16d..bb4d1f1d6d0b02a228e02541139738b56504e4af 100644 (file)
@@ -71,8 +71,8 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up,
 struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in,
                                        bool alloc_hopid);
 struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in,
-                                    struct tb_port *out, int max_up,
-                                    int max_down);
+                                    struct tb_port *out, int link_nr,
+                                    int max_up, int max_down);
 struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi,
                                      struct tb_port *dst, int transmit_path,
                                      int transmit_ring, int receive_path,