]> git.proxmox.com Git - pve-kernel.git/blobdiff - patches/kernel/0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch
rebase patches on top of Ubuntu-6.2.0-39.40
[pve-kernel.git] / patches / kernel / 0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch
diff --git a/patches/kernel/0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch b/patches/kernel/0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch
new file mode 100644 (file)
index 0000000..d15296e
--- /dev/null
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mika Westerberg <mika.westerberg@linux.intel.com>
+Date: Thu, 7 Sep 2023 16:02:30 +0300
+Subject: [PATCH] thunderbolt: Restart XDomain discovery handshake after
+ failure
+
+Alex reported that after rebooting the other host the peer-to-peer link
+does not come up anymore. The reason for this is that the host that was
+not rebooted tries to send the UUID request only 10 times according to
+the USB4 Inter-Domain spec and gives up if it does not get reply. Then
+when the other side is actually ready it cannot get the link established
+anymore. The USB4 Inter-Domain spec requires that the discovery protocol
+is restarted in that case so implement this now.
+
+Reported-by: Alex Balcanquall <alex@alexbal.com>
+Fixes: 8e1de7042596 ("thunderbolt: Add support for XDomain lane bonding")
+Cc: stable@vger.kernel.org
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
+---
+ drivers/thunderbolt/xdomain.c | 58 +++++++++++++++++++++++++----------
+ 1 file changed, 41 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
+index 3c51e47dd86b..0b17a4d4e9b9 100644
+--- a/drivers/thunderbolt/xdomain.c
++++ b/drivers/thunderbolt/xdomain.c
+@@ -704,6 +704,27 @@ static void update_property_block(struct tb_xdomain *xd)
+       mutex_unlock(&xdomain_lock);
+ }
++static void start_handshake(struct tb_xdomain *xd)
++{
++      xd->state = XDOMAIN_STATE_INIT;
++      queue_delayed_work(xd->tb->wq, &xd->state_work,
++                         msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
++}
++
++/* Can be called from state_work */
++static void __stop_handshake(struct tb_xdomain *xd)
++{
++      cancel_delayed_work_sync(&xd->properties_changed_work);
++      xd->properties_changed_retries = 0;
++      xd->state_retries = 0;
++}
++
++static void stop_handshake(struct tb_xdomain *xd)
++{
++      cancel_delayed_work_sync(&xd->state_work);
++      __stop_handshake(xd);
++}
++
+ static void tb_xdp_handle_request(struct work_struct *work)
+ {
+       struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
+@@ -766,6 +787,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
+       case UUID_REQUEST:
+               tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
+               ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
++              /*
++               * If we've stopped the discovery with an error such as
++               * timing out, we will restart the handshake now that we
++               * received UUID request from the remote host.
++               */
++              if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
++                      dev_dbg(&xd->dev, "restarting handshake\n");
++                      start_handshake(xd);
++              }
+               break;
+       case LINK_STATE_STATUS_REQUEST:
+@@ -1522,6 +1552,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
+                          msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+ }
++static void tb_xdomain_failed(struct tb_xdomain *xd)
++{
++      xd->state = XDOMAIN_STATE_ERROR;
++      queue_delayed_work(xd->tb->wq, &xd->state_work,
++                         msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
++}
++
+ static void tb_xdomain_state_work(struct work_struct *work)
+ {
+       struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
+@@ -1548,7 +1585,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
+               if (ret) {
+                       if (ret == -EAGAIN)
+                               goto retry_state;
+-                      xd->state = XDOMAIN_STATE_ERROR;
++                      tb_xdomain_failed(xd);
+               } else {
+                       tb_xdomain_queue_properties_changed(xd);
+                       if (xd->bonding_possible)
+@@ -1613,7 +1650,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
+               if (ret) {
+                       if (ret == -EAGAIN)
+                               goto retry_state;
+-                      xd->state = XDOMAIN_STATE_ERROR;
++                      tb_xdomain_failed(xd);
+               } else {
+                       xd->state = XDOMAIN_STATE_ENUMERATED;
+               }
+@@ -1624,6 +1661,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
+               break;
+       case XDOMAIN_STATE_ERROR:
++              dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
++              __stop_handshake(xd);
+               break;
+       default:
+@@ -1793,21 +1832,6 @@ static void tb_xdomain_release(struct device *dev)
+       kfree(xd);
+ }
+-static void start_handshake(struct tb_xdomain *xd)
+-{
+-      xd->state = XDOMAIN_STATE_INIT;
+-      queue_delayed_work(xd->tb->wq, &xd->state_work,
+-                         msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
+-}
+-
+-static void stop_handshake(struct tb_xdomain *xd)
+-{
+-      cancel_delayed_work_sync(&xd->properties_changed_work);
+-      cancel_delayed_work_sync(&xd->state_work);
+-      xd->properties_changed_retries = 0;
+-      xd->state_retries = 0;
+-}
+-
+ static int __maybe_unused tb_xdomain_suspend(struct device *dev)
+ {
+       stop_handshake(tb_to_xdomain(dev));