History

thunderbolt: Add support for XDomain lane bonding

The USB4 Inter-Domain Service specification defines a protocol that can be used to establish lane bonding between two USB4 domains (hosts). So far we have not implemented it because the host controller DMA was not fast enough to be able to go over 20 Gbits/s even if lanes were bonded. However, starting from Intel Alder Lake CPUs the DMA can go over 20 Gbits/s so now it makes more sense to add this support to the driver. Because both ends need to negotiate the bonding we add a simple state machine that tracks the connection state and does the necessary steps described by the USB4 Inter-Domain Service specification. We only establish lane bonding when both sides of the link support it. Otherwise we default to use the single lane. Also this is only done when software connection manager is used. On systems with firmware based connection manager, it handles the high-speed tunneling so bonding lanes is specific to the implementation (Intel firmware based connection manager does not support lane bonding).

Mika Westerberg committed 4 years ago

Commit 8e1de701 parent 0a2e1665 files · +595 −83Browse files

Unified · Split

5 files
  1. drivers/thunderbolt/tb.c +0 −6
  2. drivers/thunderbolt/tb_msgs.h +39 −0
  3. drivers/thunderbolt/tb_regs.h +5 −0
  4. drivers/thunderbolt/xdomain.c +541 −68
  5. include/linux/thunderbolt.h +10 −9
drivers/thunderbolt/tb.c+0−6
@@ -169,12 +169,6 @@ static void tb_discover_tunnels(struct tb *tb) · 168 unmodified lines
169169
170170 static int tb_port_configure_xdomain(struct tb_port *port)
171171 {
172− /*
173− * XDomain paths currently only support single lane so we must
174− * disable the other lane according to USB4 spec.
175− */
176− tb_port_disable(port->dual_link_port);
177−
178172 if (tb_switch_is_usb4(port->sw))
179173 return usb4_port_configure_xdomain(port);
180174 return tb_lc_configure_xdomain(port);
drivers/thunderbolt/tb_msgs.h+39−0
@@ -527,6 +527,10 @@ enum tb_xdp_type { · 526 unmodified lines
527527 PROPERTIES_CHANGED_RESPONSE,
528528 ERROR_RESPONSE,
529529 UUID_REQUEST = 12,
530+ LINK_STATE_STATUS_REQUEST = 15,
531+ LINK_STATE_STATUS_RESPONSE,
532+ LINK_STATE_CHANGE_REQUEST,
533+ LINK_STATE_CHANGE_RESPONSE,
530534 };
531535
532536 struct tb_xdp_header {
@@ -540,6 +544,41 @@ struct tb_xdp_error_response { · 7 unmodified lines
540544 u32 error;
541545 };
542546
547+struct tb_xdp_link_state_status {
548+ struct tb_xdp_header hdr;
549+};
550+
551+struct tb_xdp_link_state_status_response {
552+ union {
553+ struct tb_xdp_error_response err;
554+ struct {
555+ struct tb_xdp_header hdr;
556+ u32 status;
557+ u8 slw;
558+ u8 tlw;
559+ u8 sls;
560+ u8 tls;
561+ };
562+ };
563+};
564+
565+struct tb_xdp_link_state_change {
566+ struct tb_xdp_header hdr;
567+ u8 tlw;
568+ u8 tls;
569+ u16 reserved;
570+};
571+
572+struct tb_xdp_link_state_change_response {
573+ union {
574+ struct tb_xdp_error_response err;
575+ struct {
576+ struct tb_xdp_header hdr;
577+ u32 status;
578+ };
579+ };
580+};
581+
543582 struct tb_xdp_uuid {
544583 struct tb_xdp_header hdr;
545584 };
drivers/thunderbolt/tb_regs.h+5−0
@@ -311,11 +311,16 @@ struct tb_regs_port_header { · 310 unmodified lines
311311
312312 /* Lane adapter registers */
313313 #define LANE_ADP_CS_0 0x00
314+#define LANE_ADP_CS_0_SUPPORTED_SPEED_MASK GENMASK(19, 16)
315+#define LANE_ADP_CS_0_SUPPORTED_SPEED_SHIFT 16
314316 #define LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK GENMASK(25, 20)
315317 #define LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT 20
318+#define LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL 0x2
316319 #define LANE_ADP_CS_0_CL0S_SUPPORT BIT(26)
317320 #define LANE_ADP_CS_0_CL1_SUPPORT BIT(27)
318321 #define LANE_ADP_CS_1 0x01
322+#define LANE_ADP_CS_1_TARGET_SPEED_MASK GENMASK(3, 0)
323+#define LANE_ADP_CS_1_TARGET_SPEED_GEN3 0xc
319324 #define LANE_ADP_CS_1_TARGET_WIDTH_MASK GENMASK(9, 4)
320325 #define LANE_ADP_CS_1_TARGET_WIDTH_SHIFT 4
321326 #define LANE_ADP_CS_1_TARGET_WIDTH_SINGLE 0x1
drivers/thunderbolt/xdomain.c+541−68
@@ -19,13 +19,38 @@ · 18 unmodified lines
1919
2020 #include "tb.h"
2121
22−#define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */
23−#define XDOMAIN_UUID_RETRIES 10
24−#define XDOMAIN_PROPERTIES_RETRIES 10
25−#define XDOMAIN_PROPERTIES_CHANGED_RETRIES 10
26−#define XDOMAIN_BONDING_WAIT 100 /* ms */
22+#define XDOMAIN_SHORT_TIMEOUT 100 /* ms */
23+#define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */
24+#define XDOMAIN_BONDING_TIMEOUT 10000 /* ms */
25+#define XDOMAIN_RETRIES 10
2726 #define XDOMAIN_DEFAULT_MAX_HOPID 15
2827
28+enum {
29+ XDOMAIN_STATE_INIT,
30+ XDOMAIN_STATE_UUID,
31+ XDOMAIN_STATE_LINK_STATUS,
32+ XDOMAIN_STATE_LINK_STATE_CHANGE,
33+ XDOMAIN_STATE_LINK_STATUS2,
34+ XDOMAIN_STATE_BONDING_UUID_LOW,
35+ XDOMAIN_STATE_BONDING_UUID_HIGH,
36+ XDOMAIN_STATE_PROPERTIES,
37+ XDOMAIN_STATE_ENUMERATED,
38+ XDOMAIN_STATE_ERROR,
39+};
40+
41+static const char * const state_names[] = {
42+ [XDOMAIN_STATE_INIT] = "INIT",
43+ [XDOMAIN_STATE_UUID] = "UUID",
44+ [XDOMAIN_STATE_LINK_STATUS] = "LINK_STATUS",
45+ [XDOMAIN_STATE_LINK_STATE_CHANGE] = "LINK_STATE_CHANGE",
46+ [XDOMAIN_STATE_LINK_STATUS2] = "LINK_STATUS2",
47+ [XDOMAIN_STATE_BONDING_UUID_LOW] = "BONDING_UUID_LOW",
48+ [XDOMAIN_STATE_BONDING_UUID_HIGH] = "BONDING_UUID_HIGH",
49+ [XDOMAIN_STATE_PROPERTIES] = "PROPERTIES",
50+ [XDOMAIN_STATE_ENUMERATED] = "ENUMERATED",
51+ [XDOMAIN_STATE_ERROR] = "ERROR",
52+};
53+
2954 struct xdomain_request_work {
3055 struct work_struct work;
3156 struct tb_xdp_header *pkg;
@@ -235,7 +260,7 @@ static int tb_xdp_handle_error(const struct tb_xdp_error_response *res) · 203 unmodified lines
235260 }
236261
237262 static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry,
238− uuid_t *uuid)
263+ uuid_t *uuid, u64 *remote_route)
239264 {
240265 struct tb_xdp_uuid_response res;
241266 struct tb_xdp_uuid req;
@@ -258,6 +283,8 @@ static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry, · 16 unmodified lines
258283 return ret;
259284
260285 uuid_copy(uuid, &res.src_uuid);
286+ *remote_route = (u64)res.src_route_hi << 32 | res.src_route_lo;
287+
261288 return 0;
262289 }
263290
@@ -473,6 +500,112 @@ tb_xdp_properties_changed_response(struct tb_ctl *ctl, u64 route, u8 sequence) · 209 unmodified lines
473500 TB_CFG_PKG_XDOMAIN_RESP);
474501 }
475502
503+static int tb_xdp_link_state_status_request(struct tb_ctl *ctl, u64 route,
504+ u8 sequence, u8 *slw, u8 *tlw,
505+ u8 *sls, u8 *tls)
506+{
507+ struct tb_xdp_link_state_status_response res;
508+ struct tb_xdp_link_state_status req;
509+ int ret;
510+
511+ memset(&req, 0, sizeof(req));
512+ tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_STATUS_REQUEST,
513+ sizeof(req));
514+
515+ memset(&res, 0, sizeof(res));
516+ ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ,
517+ &res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP,
518+ XDOMAIN_DEFAULT_TIMEOUT);
519+ if (ret)
520+ return ret;
521+
522+ ret = tb_xdp_handle_error(&res.err);
523+ if (ret)
524+ return ret;
525+
526+ if (res.status != 0)
527+ return -EREMOTEIO;
528+
529+ *slw = res.slw;
530+ *tlw = res.tlw;
531+ *sls = res.sls;
532+ *tls = res.tls;
533+
534+ return 0;
535+}
536+
537+static int tb_xdp_link_state_status_response(struct tb *tb, struct tb_ctl *ctl,
538+ struct tb_xdomain *xd, u8 sequence)
539+{
540+ struct tb_switch *sw = tb_to_switch(xd->dev.parent);
541+ struct tb_xdp_link_state_status_response res;
542+ struct tb_port *port = tb_port_at(xd->route, sw);
543+ u32 val[2];
544+ int ret;
545+
546+ memset(&res, 0, sizeof(res));
547+ tb_xdp_fill_header(&res.hdr, xd->route, sequence,
548+ LINK_STATE_STATUS_RESPONSE, sizeof(res));
549+
550+ ret = tb_port_read(port, val, TB_CFG_PORT,
551+ port->cap_phy + LANE_ADP_CS_0, ARRAY_SIZE(val));
552+ if (ret)
553+ return ret;
554+
555+ res.slw = (val[0] & LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK) >>
556+ LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT;
557+ res.sls = (val[0] & LANE_ADP_CS_0_SUPPORTED_SPEED_MASK) >>
558+ LANE_ADP_CS_0_SUPPORTED_SPEED_SHIFT;
559+ res.tls = val[1] & LANE_ADP_CS_1_TARGET_SPEED_MASK;
560+ res.tlw = (val[1] & LANE_ADP_CS_1_TARGET_WIDTH_MASK) >>
561+ LANE_ADP_CS_1_TARGET_WIDTH_SHIFT;
562+
563+ return __tb_xdomain_response(ctl, &res, sizeof(res),
564+ TB_CFG_PKG_XDOMAIN_RESP);
565+}
566+
567+static int tb_xdp_link_state_change_request(struct tb_ctl *ctl, u64 route,
568+ u8 sequence, u8 tlw, u8 tls)
569+{
570+ struct tb_xdp_link_state_change_response res;
571+ struct tb_xdp_link_state_change req;
572+ int ret;
573+
574+ memset(&req, 0, sizeof(req));
575+ tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_CHANGE_REQUEST,
576+ sizeof(req));
577+ req.tlw = tlw;
578+ req.tls = tls;
579+
580+ memset(&res, 0, sizeof(res));
581+ ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ,
582+ &res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP,
583+ XDOMAIN_DEFAULT_TIMEOUT);
584+ if (ret)
585+ return ret;
586+
587+ ret = tb_xdp_handle_error(&res.err);
588+ if (ret)
589+ return ret;
590+
591+ return res.status != 0 ? -EREMOTEIO : 0;
592+}
593+
594+static int tb_xdp_link_state_change_response(struct tb_ctl *ctl, u64 route,
595+ u8 sequence, u32 status)
596+{
597+ struct tb_xdp_link_state_change_response res;
598+
599+ memset(&res, 0, sizeof(res));
600+ tb_xdp_fill_header(&res.hdr, route, sequence, LINK_STATE_CHANGE_RESPONSE,
601+ sizeof(res));
602+
603+ res.status = status;
604+
605+ return __tb_xdomain_response(ctl, &res, sizeof(res),
606+ TB_CFG_PKG_XDOMAIN_RESP);
607+}
608+
476609 /**
477610 * tb_register_protocol_handler() - Register protocol handler
478611 * @handler: Handler to register
@@ -600,14 +733,13 @@ static void tb_xdp_handle_request(struct work_struct *work) · 121 unmodified lines
600733 goto out;
601734 }
602735
603− tb_dbg(tb, "%llx: received XDomain request %#x\n", route, pkg->type);
604−
605736 xd = tb_xdomain_find_by_route_locked(tb, route);
606737 if (xd)
607738 update_property_block(xd);
608739
609740 switch (pkg->type) {
610741 case PROPERTIES_REQUEST:
742+ tb_dbg(tb, "%llx: received XDomain properties request\n", route);
611743 if (xd) {
612744 ret = tb_xdp_properties_response(tb, ctl, xd, sequence,
613745 (const struct tb_xdp_properties *)pkg);
@@ -615,6 +747,9 @@ static void tb_xdp_handle_request(struct work_struct *work) · 1 unmodified line
615747 break;
616748
617749 case PROPERTIES_CHANGED_REQUEST:
750+ tb_dbg(tb, "%llx: received XDomain properties changed request\n",
751+ route);
752+
618753 ret = tb_xdp_properties_changed_response(ctl, route, sequence);
619754
620755 /*
@@ -622,18 +757,51 @@ static void tb_xdp_handle_request(struct work_struct *work) · 1 unmodified line
622757 * the xdomain related to this connection as well in
623758 * case there is a change in services it offers.
624759 */
625− if (xd && device_is_registered(&xd->dev)) {
626− queue_delayed_work(tb->wq, &xd->get_properties_work,
627− msecs_to_jiffies(50));
628− }
760+ if (xd && device_is_registered(&xd->dev))
761+ queue_delayed_work(tb->wq, &xd->state_work,
762+ msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
629763 break;
630764
631765 case UUID_REQUEST_OLD:
632766 case UUID_REQUEST:
767+ tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
633768 ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
634769 break;
635770
771+ case LINK_STATE_STATUS_REQUEST:
772+ tb_dbg(tb, "%llx: received XDomain link state status request\n",
773+ route);
774+
775+ if (xd) {
776+ ret = tb_xdp_link_state_status_response(tb, ctl, xd,
777+ sequence);
778+ } else {
779+ tb_xdp_error_response(ctl, route, sequence,
780+ ERROR_NOT_READY);
781+ }
782+ break;
783+
784+ case LINK_STATE_CHANGE_REQUEST:
785+ tb_dbg(tb, "%llx: received XDomain link state change request\n",
786+ route);
787+
788+ if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) {
789+ const struct tb_xdp_link_state_change *lsc =
790+ (const struct tb_xdp_link_state_change *)pkg;
791+
792+ ret = tb_xdp_link_state_change_response(ctl, route,
793+ sequence, 0);
794+ xd->target_link_width = lsc->tlw;
795+ queue_delayed_work(tb->wq, &xd->state_work,
796+ msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
797+ } else {
798+ tb_xdp_error_response(ctl, route, sequence,
799+ ERROR_NOT_READY);
800+ }
801+ break;
802+
636803 default:
804+ tb_dbg(tb, "%llx: unknown XDomain request %#x\n", route, pkg->type);
637805 tb_xdp_error_response(ctl, route, sequence,
638806 ERROR_NOT_SUPPORTED);
639807 break;
@@ -1000,32 +1168,38 @@ static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd) · 360 unmodified lines
10001168 return 0;
10011169 }
10021170
1003−static void tb_xdomain_get_uuid(struct work_struct *work)
1171+static int tb_xdomain_get_uuid(struct tb_xdomain *xd)
10041172 {
1005− struct tb_xdomain *xd = container_of(work, typeof(*xd),
1006− get_uuid_work.work);
10071173 struct tb *tb = xd->tb;
10081174 uuid_t uuid;
1175+ u64 route;
10091176 int ret;
10101177
10111178 dev_dbg(&xd->dev, "requesting remote UUID\n");
10121179
1013− ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->uuid_retries, &uuid);
1180+ ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->state_retries, &uuid,
1181+ &route);
10141182 if (ret < 0) {
1015− if (xd->uuid_retries-- > 0) {
1183+ if (xd->state_retries-- > 0) {
10161184 dev_dbg(&xd->dev, "failed to request UUID, retrying\n");
1017− queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
1018− msecs_to_jiffies(100));
1185+ return -EAGAIN;
10191186 } else {
10201187 dev_dbg(&xd->dev, "failed to read remote UUID\n");
10211188 }
1022− return;
1189+ return ret;
10231190 }
10241191
10251192 dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid);
10261193
1027− if (uuid_equal(&uuid, xd->local_uuid))
1028− dev_dbg(&xd->dev, "intra-domain loop detected\n");
1194+ if (uuid_equal(&uuid, xd->local_uuid)) {
1195+ if (route == xd->route)
1196+ dev_dbg(&xd->dev, "loop back detected\n");
1197+ else
1198+ dev_dbg(&xd->dev, "intra-domain loop detected\n");
1199+
1200+ /* Don't bond lanes automatically for loops */
1201+ xd->bonding_possible = false;
1202+ }
10291203
10301204 /*
10311205 * If the UUID is different, there is another domain connected
@@ -1035,27 +1209,152 @@ static void tb_xdomain_get_uuid(struct work_struct *work) · 3 unmodified lines
10351209 if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) {
10361210 dev_dbg(&xd->dev, "remote UUID is different, unplugging\n");
10371211 xd->is_unplugged = true;
1038− return;
1212+ return -ENODEV;
10391213 }
10401214
10411215 /* First time fill in the missing UUID */
10421216 if (!xd->remote_uuid) {
10431217 xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL);
10441218 if (!xd->remote_uuid)
1045− return;
1219+ return -ENOMEM;
10461220 }
10471221
1048− /* Now we can start the normal properties exchange */
1049− queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
1050− msecs_to_jiffies(100));
1051− queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
1052− msecs_to_jiffies(1000));
1222+ return 0;
10531223 }
10541224
1055−static void tb_xdomain_get_properties(struct work_struct *work)
1225+static int tb_xdomain_get_link_status(struct tb_xdomain *xd)
1226+{
1227+ struct tb *tb = xd->tb;
1228+ u8 slw, tlw, sls, tls;
1229+ int ret;
1230+
1231+ dev_dbg(&xd->dev, "sending link state status request to %pUb\n",
1232+ xd->remote_uuid);
1233+
1234+ ret = tb_xdp_link_state_status_request(tb->ctl, xd->route,
1235+ xd->state_retries, &slw, &tlw, &sls,
1236+ &tls);
1237+ if (ret) {
1238+ if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) {
1239+ dev_dbg(&xd->dev,
1240+ "failed to request remote link status, retrying\n");
1241+ return -EAGAIN;
1242+ }
1243+ dev_dbg(&xd->dev, "failed to receive remote link status\n");
1244+ return ret;
1245+ }
1246+
1247+ dev_dbg(&xd->dev, "remote link supports width %#x speed %#x\n", slw, sls);
1248+
1249+ if (slw < LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL) {
1250+ dev_dbg(&xd->dev, "remote adapter is single lane only\n");
1251+ return -EOPNOTSUPP;
1252+ }
1253+
1254+ return 0;
1255+}
1256+
1257+static int tb_xdomain_link_state_change(struct tb_xdomain *xd,
1258+ unsigned int width)
1259+{
1260+ struct tb_switch *sw = tb_to_switch(xd->dev.parent);
1261+ struct tb_port *port = tb_port_at(xd->route, sw);
1262+ struct tb *tb = xd->tb;
1263+ u8 tlw, tls;
1264+ u32 val;
1265+ int ret;
1266+
1267+ if (width == 2)
1268+ tlw = LANE_ADP_CS_1_TARGET_WIDTH_DUAL;
1269+ else if (width == 1)
1270+ tlw = LANE_ADP_CS_1_TARGET_WIDTH_SINGLE;
1271+ else
1272+ return -EINVAL;
1273+
1274+ /* Use the current target speed */
1275+ ret = tb_port_read(port, &val, TB_CFG_PORT, port->cap_phy + LANE_ADP_CS_1, 1);
1276+ if (ret)
1277+ return ret;
1278+ tls = val & LANE_ADP_CS_1_TARGET_SPEED_MASK;
1279+
1280+ dev_dbg(&xd->dev, "sending link state change request with width %#x speed %#x\n",
1281+ tlw, tls);
1282+
1283+ ret = tb_xdp_link_state_change_request(tb->ctl, xd->route,
1284+ xd->state_retries, tlw, tls);
1285+ if (ret) {
1286+ if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) {
1287+ dev_dbg(&xd->dev,
1288+ "failed to change remote link state, retrying\n");
1289+ return -EAGAIN;
1290+ }
1291+ dev_err(&xd->dev, "failed request link state change, aborting\n");
1292+ return ret;
1293+ }
1294+
1295+ dev_dbg(&xd->dev, "received link state change response\n");
1296+ return 0;
1297+}
1298+
1299+static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd)
1300+{
1301+ struct tb_port *port;
1302+ int ret, width;
1303+
1304+ if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_SINGLE) {
1305+ width = 1;
1306+ } else if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_DUAL) {
1307+ width = 2;
1308+ } else {
1309+ if (xd->state_retries-- > 0) {
1310+ dev_dbg(&xd->dev,
1311+ "link state change request not received yet, retrying\n");
1312+ return -EAGAIN;
1313+ }
1314+ dev_dbg(&xd->dev, "timeout waiting for link change request\n");
1315+ return -ETIMEDOUT;
1316+ }
1317+
1318+ port = tb_port_at(xd->route, tb_xdomain_parent(xd));
1319+
1320+ /*
1321+ * We can't use tb_xdomain_lane_bonding_enable() here because it
1322+ * is the other side that initiates lane bonding. So here we
1323+ * just set the width to both lane adapters and wait for the
1324+ * link to transition bonded.
1325+ */
1326+ ret = tb_port_set_link_width(port->dual_link_port, width);
1327+ if (ret) {
1328+ tb_port_warn(port->dual_link_port,
1329+ "failed to set link width to %d\n", width);
1330+ return ret;
1331+ }
1332+
1333+ ret = tb_port_set_link_width(port, width);
1334+ if (ret) {
1335+ tb_port_warn(port, "failed to set link width to %d\n", width);
1336+ return ret;
1337+ }
1338+
1339+ ret = tb_port_wait_for_link_width(port, width, XDOMAIN_BONDING_TIMEOUT);
1340+ if (ret) {
1341+ dev_warn(&xd->dev, "error waiting for link width to become %d\n",
1342+ width);
1343+ return ret;
1344+ }
1345+
1346+ port->bonded = width == 2;
1347+ port->dual_link_port->bonded = width == 2;
1348+
1349+ tb_port_update_credits(port);
1350+ tb_xdomain_update_link_attributes(xd);
1351+
1352+ dev_dbg(&xd->dev, "lane bonding %sabled\n", width == 2 ? "en" : "dis");
1353+ return 0;
1354+}
1355+
1356+static int tb_xdomain_get_properties(struct tb_xdomain *xd)
10561357 {
1057− struct tb_xdomain *xd = container_of(work, typeof(*xd),
1058− get_properties_work.work);
10591358 struct tb_property_dir *dir;
10601359 struct tb *tb = xd->tb;
10611360 bool update = false;
@@ -1066,34 +1365,35 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 4 unmodified lines
10661365 dev_dbg(&xd->dev, "requesting remote properties\n");
10671366
10681367 ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid,
1069− xd->remote_uuid, xd->properties_retries,
1368+ xd->remote_uuid, xd->state_retries,
10701369 &block, &gen);
10711370 if (ret < 0) {
1072− if (xd->properties_retries-- > 0) {
1371+ if (xd->state_retries-- > 0) {
10731372 dev_dbg(&xd->dev,
10741373 "failed to request remote properties, retrying\n");
1075− queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
1076− msecs_to_jiffies(1000));
1374+ return -EAGAIN;
10771375 } else {
10781376 /* Give up now */
10791377 dev_err(&xd->dev,
10801378 "failed read XDomain properties from %pUb\n",
10811379 xd->remote_uuid);
10821380 }
1083− return;
1084− }
10851381
1086− xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;
1382+ return ret;
1383+ }
10871384
10881385 mutex_lock(&xd->lock);
10891386
10901387 /* Only accept newer generation properties */
1091− if (xd->remote_properties && gen <= xd->remote_property_block_gen)
1388+ if (xd->remote_properties && gen <= xd->remote_property_block_gen) {
1389+ ret = 0;
10921390 goto err_free_block;
1391+ }
10931392
10941393 dir = tb_property_parse_dir(block, ret);
10951394 if (!dir) {
10961395 dev_err(&xd->dev, "failed to parse XDomain properties\n");
1396+ ret = -ENOMEM;
10971397 goto err_free_block;
10981398 }
10991399
@@ -1124,9 +1424,16 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 24 unmodified lines
11241424 * registered, we notify the userspace that it has changed.
11251425 */
11261426 if (!update) {
1427+ struct tb_port *port;
1428+
1429+ /* Now disable lane 1 if bonding was not enabled */
1430+ port = tb_port_at(xd->route, tb_xdomain_parent(xd));
1431+ if (!port->bonded)
1432+ tb_port_disable(port->dual_link_port);
1433+
11271434 if (device_add(&xd->dev)) {
11281435 dev_err(&xd->dev, "failed to add XDomain device\n");
1129− return;
1436+ return -ENODEV;
11301437 }
11311438 dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n",
11321439 xd->vendor, xd->device);
@@ -1138,13 +1445,193 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 5 unmodified lines
11381445 }
11391446
11401447 enumerate_services(xd);
1141− return;
1448+ return 0;
11421449
11431450 err_free_dir:
11441451 tb_property_free_dir(dir);
11451452 err_free_block:
11461453 kfree(block);
11471454 mutex_unlock(&xd->lock);
1455+
1456+ return ret;
1457+}
1458+
1459+static void tb_xdomain_queue_uuid(struct tb_xdomain *xd)
1460+{
1461+ xd->state = XDOMAIN_STATE_UUID;
1462+ xd->state_retries = XDOMAIN_RETRIES;
1463+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1464+ msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
1465+}
1466+
1467+static void tb_xdomain_queue_link_status(struct tb_xdomain *xd)
1468+{
1469+ xd->state = XDOMAIN_STATE_LINK_STATUS;
1470+ xd->state_retries = XDOMAIN_RETRIES;
1471+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1472+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1473+}
1474+
1475+static void tb_xdomain_queue_link_status2(struct tb_xdomain *xd)
1476+{
1477+ xd->state = XDOMAIN_STATE_LINK_STATUS2;
1478+ xd->state_retries = XDOMAIN_RETRIES;
1479+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1480+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1481+}
1482+
1483+static void tb_xdomain_queue_bonding(struct tb_xdomain *xd)
1484+{
1485+ if (memcmp(xd->local_uuid, xd->remote_uuid, UUID_SIZE) > 0) {
1486+ dev_dbg(&xd->dev, "we have higher UUID, other side bonds the lanes\n");
1487+ xd->state = XDOMAIN_STATE_BONDING_UUID_HIGH;
1488+ } else {
1489+ dev_dbg(&xd->dev, "we have lower UUID, bonding lanes\n");
1490+ xd->state = XDOMAIN_STATE_LINK_STATE_CHANGE;
1491+ }
1492+
1493+ xd->state_retries = XDOMAIN_RETRIES;
1494+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1495+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1496+}
1497+
1498+static void tb_xdomain_queue_bonding_uuid_low(struct tb_xdomain *xd)
1499+{
1500+ xd->state = XDOMAIN_STATE_BONDING_UUID_LOW;
1501+ xd->state_retries = XDOMAIN_RETRIES;
1502+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1503+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1504+}
1505+
1506+static void tb_xdomain_queue_properties(struct tb_xdomain *xd)
1507+{
1508+ xd->state = XDOMAIN_STATE_PROPERTIES;
1509+ xd->state_retries = XDOMAIN_RETRIES;
1510+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1511+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
1512+}
1513+
1514+static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
1515+{
1516+ xd->properties_changed_retries = XDOMAIN_RETRIES;
1517+ queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
1518+ msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
1519+}
1520+
1521+static void tb_xdomain_state_work(struct work_struct *work)
1522+{
1523+ struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
1524+ int ret, state = xd->state;
1525+
1526+ if (WARN_ON_ONCE(state < XDOMAIN_STATE_INIT ||
1527+ state > XDOMAIN_STATE_ERROR))
1528+ return;
1529+
1530+ dev_dbg(&xd->dev, "running state %s\n", state_names[state]);
1531+
1532+ switch (state) {
1533+ case XDOMAIN_STATE_INIT:
1534+ if (xd->needs_uuid) {
1535+ tb_xdomain_queue_uuid(xd);
1536+ } else {
1537+ tb_xdomain_queue_properties_changed(xd);
1538+ tb_xdomain_queue_properties(xd);
1539+ }
1540+ break;
1541+
1542+ case XDOMAIN_STATE_UUID:
1543+ ret = tb_xdomain_get_uuid(xd);
1544+ if (ret) {
1545+ if (ret == -EAGAIN)
1546+ goto retry_state;
1547+ xd->state = XDOMAIN_STATE_ERROR;
1548+ } else {
1549+ tb_xdomain_queue_properties_changed(xd);
1550+ if (xd->bonding_possible)
1551+ tb_xdomain_queue_link_status(xd);
1552+ else
1553+ tb_xdomain_queue_properties(xd);
1554+ }
1555+ break;
1556+
1557+ case XDOMAIN_STATE_LINK_STATUS:
1558+ ret = tb_xdomain_get_link_status(xd);
1559+ if (ret) {
1560+ if (ret == -EAGAIN)
1561+ goto retry_state;
1562+
1563+ /*
1564+ * If any of the lane bonding states fail we skip
1565+ * bonding completely and try to continue from
1566+ * reading properties.
1567+ */
1568+ tb_xdomain_queue_properties(xd);
1569+ } else {
1570+ tb_xdomain_queue_bonding(xd);
1571+ }
1572+ break;
1573+
1574+ case XDOMAIN_STATE_LINK_STATE_CHANGE:
1575+ ret = tb_xdomain_link_state_change(xd, 2);
1576+ if (ret) {
1577+ if (ret == -EAGAIN)
1578+ goto retry_state;
1579+ tb_xdomain_queue_properties(xd);
1580+ } else {
1581+ tb_xdomain_queue_link_status2(xd);
1582+ }
1583+ break;
1584+
1585+ case XDOMAIN_STATE_LINK_STATUS2:
1586+ ret = tb_xdomain_get_link_status(xd);
1587+ if (ret) {
1588+ if (ret == -EAGAIN)
1589+ goto retry_state;
1590+ tb_xdomain_queue_properties(xd);
1591+ } else {
1592+ tb_xdomain_queue_bonding_uuid_low(xd);
1593+ }
1594+ break;
1595+
1596+ case XDOMAIN_STATE_BONDING_UUID_LOW:
1597+ tb_xdomain_lane_bonding_enable(xd);
1598+ tb_xdomain_queue_properties(xd);
1599+ break;
1600+
1601+ case XDOMAIN_STATE_BONDING_UUID_HIGH:
1602+ if (tb_xdomain_bond_lanes_uuid_high(xd) == -EAGAIN)
1603+ goto retry_state;
1604+ tb_xdomain_queue_properties(xd);
1605+ break;
1606+
1607+ case XDOMAIN_STATE_PROPERTIES:
1608+ ret = tb_xdomain_get_properties(xd);
1609+ if (ret) {
1610+ if (ret == -EAGAIN)
1611+ goto retry_state;
1612+ xd->state = XDOMAIN_STATE_ERROR;
1613+ } else {
1614+ xd->state = XDOMAIN_STATE_ENUMERATED;
1615+ }
1616+ break;
1617+
1618+ case XDOMAIN_STATE_ENUMERATED:
1619+ tb_xdomain_queue_properties(xd);
1620+ break;
1621+
1622+ case XDOMAIN_STATE_ERROR:
1623+ break;
1624+
1625+ default:
1626+ dev_warn(&xd->dev, "unexpected state %d\n", state);
1627+ break;
1628+ }
1629+
1630+ return;
1631+
1632+retry_state:
1633+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1634+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
11481635 }
11491636
11501637 static void tb_xdomain_properties_changed(struct work_struct *work)
@@ -1163,13 +1650,13 @@ static void tb_xdomain_properties_changed(struct work_struct *work) · 12 unmodified lines
11631650 "failed to send properties changed notification, retrying\n");
11641651 queue_delayed_work(xd->tb->wq,
11651652 &xd->properties_changed_work,
1166− msecs_to_jiffies(1000));
1653+ msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
11671654 }
11681655 dev_err(&xd->dev, "failed to send properties changed notification\n");
11691656 return;
11701657 }
11711658
1172− xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES;
1659+ xd->properties_changed_retries = XDOMAIN_RETRIES;
11731660 }
11741661
11751662 static ssize_t device_show(struct device *dev, struct device_attribute *attr,
@@ -1304,31 +1791,17 @@ static void tb_xdomain_release(struct device *dev) · 128 unmodified lines
13041791
13051792 static void start_handshake(struct tb_xdomain *xd)
13061793 {
1307− xd->uuid_retries = XDOMAIN_UUID_RETRIES;
1308− xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;
1309− xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES;
1310−
1311− if (xd->needs_uuid) {
1312− queue_delayed_work(xd->tb->wq, &xd->get_uuid_work,
1313− msecs_to_jiffies(100));
1314− } else {
1315− /* Start exchanging properties with the other host */
1316− queue_delayed_work(xd->tb->wq, &xd->properties_changed_work,
1317− msecs_to_jiffies(100));
1318− queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
1319− msecs_to_jiffies(1000));
1320− }
1794+ xd->state = XDOMAIN_STATE_INIT;
1795+ queue_delayed_work(xd->tb->wq, &xd->state_work,
1796+ msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
13211797 }
13221798
13231799 static void stop_handshake(struct tb_xdomain *xd)
13241800 {
1325− xd->uuid_retries = 0;
1326− xd->properties_retries = 0;
1327− xd->properties_changed_retries = 0;
1328−
1329− cancel_delayed_work_sync(&xd->get_uuid_work);
1330− cancel_delayed_work_sync(&xd->get_properties_work);
13311801 cancel_delayed_work_sync(&xd->properties_changed_work);
1802+ cancel_delayed_work_sync(&xd->state_work);
1803+ xd->properties_changed_retries = 0;
1804+ xd->state_retries = 0;
13321805 }
13331806
13341807 static int __maybe_unused tb_xdomain_suspend(struct device *dev)
@@ -1389,8 +1862,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, · 54 unmodified lines
13891862 ida_init(&xd->in_hopids);
13901863 ida_init(&xd->out_hopids);
13911864 mutex_init(&xd->lock);
1392− INIT_DELAYED_WORK(&xd->get_uuid_work, tb_xdomain_get_uuid);
1393− INIT_DELAYED_WORK(&xd->get_properties_work, tb_xdomain_get_properties);
1865+ INIT_DELAYED_WORK(&xd->state_work, tb_xdomain_state_work);
13941866 INIT_DELAYED_WORK(&xd->properties_changed_work,
13951867 tb_xdomain_properties_changed);
13961868
@@ -1405,6 +1877,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, · 8 unmodified lines
14051877 goto err_free_local_uuid;
14061878 } else {
14071879 xd->needs_uuid = true;
1880+ xd->bonding_possible = !!down->dual_link_port;
14081881 }
14091882
14101883 device_initialize(&xd->dev);
@@ -1523,9 +1996,9 @@ int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd) · 112 unmodified lines
15231996 return ret;
15241997 }
15251998
1526− ret = tb_port_wait_for_link_width(port, 2, 100);
1999+ ret = tb_port_wait_for_link_width(port, 2, XDOMAIN_BONDING_TIMEOUT);
15272000 if (ret) {
1528− tb_port_warn(port, "timeout enabling lane bonding\n");
2001+ tb_port_warn(port, "failed to enable lane bonding\n");
15292002 return ret;
15302003 }
15312004
include/linux/thunderbolt.h+10−9
@@ -198,15 +198,15 @@ void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir); · 197 unmodified lines
198198 * @local_property_block_len: Length of the @local_property_block in dwords
199199 * @remote_properties: Properties exported by the remote domain
200200 * @remote_property_block_gen: Generation of @remote_properties
201− * @get_uuid_work: Work used to retrieve @remote_uuid
202− * @uuid_retries: Number of times left @remote_uuid is requested before
203− * giving up
204− * @get_properties_work: Work used to get remote domain properties
205− * @properties_retries: Number of times left to read properties
201+ * @state: Next XDomain discovery state to run
202+ * @state_work: Work used to run the next state
203+ * @state_retries: Number of retries remain for the state
206204 * @properties_changed_work: Work used to notify the remote domain that
207205 * our properties have changed
208206 * @properties_changed_retries: Number of times left to send properties
209207 * changed notification
208+ * @bonding_possible: True if lane bonding is possible on local side
209+ * @target_link_width: Target link width from the remote host
210210 * @link: Root switch link the remote domain is connected (ICM only)
211211 * @depth: Depth in the chain the remote domain is connected (ICM only)
212212 *
@@ -244,12 +244,13 @@ struct tb_xdomain { · 31 unmodified lines
244244 u32 local_property_block_len;
245245 struct tb_property_dir *remote_properties;
246246 u32 remote_property_block_gen;
247− struct delayed_work get_uuid_work;
248− int uuid_retries;
249− struct delayed_work get_properties_work;
250− int properties_retries;
247+ int state;
248+ struct delayed_work state_work;
249+ int state_retries;
251250 struct delayed_work properties_changed_work;
252251 int properties_changed_retries;
252+ bool bonding_possible;
253+ u8 target_link_width;
253254 u8 link;
254255 u8 depth;
255256 };

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t