Skip to content

Commit 308092d

Browse files
committed
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: 8e1de70 ("thunderbolt: Add support for XDomain lane bonding") Cc: stable@vger.kernel.org Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
1 parent e19f714 commit 308092d

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

drivers/thunderbolt/xdomain.c

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,27 @@ static void update_property_block(struct tb_xdomain *xd)
703703
mutex_unlock(&xdomain_lock);
704704
}
705705

706+
static void start_handshake(struct tb_xdomain *xd)
707+
{
708+
xd->state = XDOMAIN_STATE_INIT;
709+
queue_delayed_work(xd->tb->wq, &xd->state_work,
710+
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
711+
}
712+
713+
/* Can be called from state_work */
714+
static void __stop_handshake(struct tb_xdomain *xd)
715+
{
716+
cancel_delayed_work_sync(&xd->properties_changed_work);
717+
xd->properties_changed_retries = 0;
718+
xd->state_retries = 0;
719+
}
720+
721+
static void stop_handshake(struct tb_xdomain *xd)
722+
{
723+
cancel_delayed_work_sync(&xd->state_work);
724+
__stop_handshake(xd);
725+
}
726+
706727
static void tb_xdp_handle_request(struct work_struct *work)
707728
{
708729
struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
@@ -765,6 +786,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
765786
case UUID_REQUEST:
766787
tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
767788
ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
789+
/*
790+
* If we've stopped the discovery with an error such as
791+
* timing out, we will restart the handshake now that we
792+
* received UUID request from the remote host.
793+
*/
794+
if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
795+
dev_dbg(&xd->dev, "restarting handshake\n");
796+
start_handshake(xd);
797+
}
768798
break;
769799

770800
case LINK_STATE_STATUS_REQUEST:
@@ -1521,6 +1551,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
15211551
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
15221552
}
15231553

1554+
static void tb_xdomain_failed(struct tb_xdomain *xd)
1555+
{
1556+
xd->state = XDOMAIN_STATE_ERROR;
1557+
queue_delayed_work(xd->tb->wq, &xd->state_work,
1558+
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1559+
}
1560+
15241561
static void tb_xdomain_state_work(struct work_struct *work)
15251562
{
15261563
struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
@@ -1547,7 +1584,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
15471584
if (ret) {
15481585
if (ret == -EAGAIN)
15491586
goto retry_state;
1550-
xd->state = XDOMAIN_STATE_ERROR;
1587+
tb_xdomain_failed(xd);
15511588
} else {
15521589
tb_xdomain_queue_properties_changed(xd);
15531590
if (xd->bonding_possible)
@@ -1612,7 +1649,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
16121649
if (ret) {
16131650
if (ret == -EAGAIN)
16141651
goto retry_state;
1615-
xd->state = XDOMAIN_STATE_ERROR;
1652+
tb_xdomain_failed(xd);
16161653
} else {
16171654
xd->state = XDOMAIN_STATE_ENUMERATED;
16181655
}
@@ -1623,6 +1660,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
16231660
break;
16241661

16251662
case XDOMAIN_STATE_ERROR:
1663+
dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
1664+
__stop_handshake(xd);
16261665
break;
16271666

16281667
default:
@@ -1833,21 +1872,6 @@ static void tb_xdomain_release(struct device *dev)
18331872
kfree(xd);
18341873
}
18351874

1836-
static void start_handshake(struct tb_xdomain *xd)
1837-
{
1838-
xd->state = XDOMAIN_STATE_INIT;
1839-
queue_delayed_work(xd->tb->wq, &xd->state_work,
1840-
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
1841-
}
1842-
1843-
static void stop_handshake(struct tb_xdomain *xd)
1844-
{
1845-
cancel_delayed_work_sync(&xd->properties_changed_work);
1846-
cancel_delayed_work_sync(&xd->state_work);
1847-
xd->properties_changed_retries = 0;
1848-
xd->state_retries = 0;
1849-
}
1850-
18511875
static int __maybe_unused tb_xdomain_suspend(struct device *dev)
18521876
{
18531877
stop_handshake(tb_to_xdomain(dev));

0 commit comments

Comments
 (0)