]> git.proxmox.com Git - pve-kernel.git/blob - patches/kernel/0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch
6af7817cdfe7d4b012ece3bddbf4ece1cc581ed1
[pve-kernel.git] / patches / kernel / 0011-thunderbolt-Restart-XDomain-discovery-handshake-afte.patch
1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Mika Westerberg <mika.westerberg@linux.intel.com>
3 Date: Thu, 7 Sep 2023 16:02:30 +0300
4 Subject: [PATCH] thunderbolt: Restart XDomain discovery handshake after
5 failure
6
7 Alex reported that after rebooting the other host the peer-to-peer link
8 does not come up anymore. The reason for this is that the host that was
9 not rebooted tries to send the UUID request only 10 times according to
10 the USB4 Inter-Domain spec and gives up if it does not get reply. Then
11 when the other side is actually ready it cannot get the link established
12 anymore. The USB4 Inter-Domain spec requires that the discovery protocol
13 is restarted in that case so implement this now.
14
15 Reported-by: Alex Balcanquall <alex@alexbal.com>
16 Fixes: 8e1de7042596 ("thunderbolt: Add support for XDomain lane bonding")
17 Cc: stable@vger.kernel.org
18 Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
19 Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
20 ---
21 drivers/thunderbolt/xdomain.c | 58 +++++++++++++++++++++++++----------
22 1 file changed, 41 insertions(+), 17 deletions(-)
23
24 diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
25 index 5b5566862318..9803f0bbf20d 100644
26 --- a/drivers/thunderbolt/xdomain.c
27 +++ b/drivers/thunderbolt/xdomain.c
28 @@ -703,6 +703,27 @@ static void update_property_block(struct tb_xdomain *xd)
29 mutex_unlock(&xdomain_lock);
30 }
31
32 +static void start_handshake(struct tb_xdomain *xd)
33 +{
34 + xd->state = XDOMAIN_STATE_INIT;
35 + queue_delayed_work(xd->tb->wq, &xd->state_work,
36 + msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
37 +}
38 +
39 +/* Can be called from state_work */
40 +static void __stop_handshake(struct tb_xdomain *xd)
41 +{
42 + cancel_delayed_work_sync(&xd->properties_changed_work);
43 + xd->properties_changed_retries = 0;
44 + xd->state_retries = 0;
45 +}
46 +
47 +static void stop_handshake(struct tb_xdomain *xd)
48 +{
49 + cancel_delayed_work_sync(&xd->state_work);
50 + __stop_handshake(xd);
51 +}
52 +
53 static void tb_xdp_handle_request(struct work_struct *work)
54 {
55 struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
56 @@ -765,6 +786,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
57 case UUID_REQUEST:
58 tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
59 ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
60 + /*
61 + * If we've stopped the discovery with an error such as
62 + * timing out, we will restart the handshake now that we
63 + * received UUID request from the remote host.
64 + */
65 + if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
66 + dev_dbg(&xd->dev, "restarting handshake\n");
67 + start_handshake(xd);
68 + }
69 break;
70
71 case LINK_STATE_STATUS_REQUEST:
72 @@ -1521,6 +1551,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
73 msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
74 }
75
76 +static void tb_xdomain_failed(struct tb_xdomain *xd)
77 +{
78 + xd->state = XDOMAIN_STATE_ERROR;
79 + queue_delayed_work(xd->tb->wq, &xd->state_work,
80 + msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
81 +}
82 +
83 static void tb_xdomain_state_work(struct work_struct *work)
84 {
85 struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
86 @@ -1547,7 +1584,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
87 if (ret) {
88 if (ret == -EAGAIN)
89 goto retry_state;
90 - xd->state = XDOMAIN_STATE_ERROR;
91 + tb_xdomain_failed(xd);
92 } else {
93 tb_xdomain_queue_properties_changed(xd);
94 if (xd->bonding_possible)
95 @@ -1612,7 +1649,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
96 if (ret) {
97 if (ret == -EAGAIN)
98 goto retry_state;
99 - xd->state = XDOMAIN_STATE_ERROR;
100 + tb_xdomain_failed(xd);
101 } else {
102 xd->state = XDOMAIN_STATE_ENUMERATED;
103 }
104 @@ -1623,6 +1660,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
105 break;
106
107 case XDOMAIN_STATE_ERROR:
108 + dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
109 + __stop_handshake(xd);
110 break;
111
112 default:
113 @@ -1833,21 +1872,6 @@ static void tb_xdomain_release(struct device *dev)
114 kfree(xd);
115 }
116
117 -static void start_handshake(struct tb_xdomain *xd)
118 -{
119 - xd->state = XDOMAIN_STATE_INIT;
120 - queue_delayed_work(xd->tb->wq, &xd->state_work,
121 - msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
122 -}
123 -
124 -static void stop_handshake(struct tb_xdomain *xd)
125 -{
126 - cancel_delayed_work_sync(&xd->properties_changed_work);
127 - cancel_delayed_work_sync(&xd->state_work);
128 - xd->properties_changed_retries = 0;
129 - xd->state_retries = 0;
130 -}
131 -
132 static int __maybe_unused tb_xdomain_suspend(struct device *dev)
133 {
134 stop_handshake(tb_to_xdomain(dev));