| @@ -19,13 +19,38 @@ · 18 unmodified lines |
| 19 | | 19 | |
| 20 | #include "tb.h" | 20 | #include "tb.h" |
| 21 | | 21 | |
| 22 | #define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */ | 22 | #define XDOMAIN_SHORT_TIMEOUT 100 /* ms */ |
| 23 | #define XDOMAIN_UUID_RETRIES 10 | 23 | #define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */ |
| 24 | #define XDOMAIN_PROPERTIES_RETRIES 10 | 24 | #define XDOMAIN_BONDING_TIMEOUT 10000 /* ms */ |
| 25 | #define XDOMAIN_PROPERTIES_CHANGED_RETRIES 10 | 25 | #define XDOMAIN_RETRIES 10 |
| 26 | #define XDOMAIN_BONDING_WAIT 100 /* ms */ | | |
| 27 | #define XDOMAIN_DEFAULT_MAX_HOPID 15 | 26 | #define XDOMAIN_DEFAULT_MAX_HOPID 15 |
| 28 | | 27 | |
| | 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 | |
| 29 | struct xdomain_request_work { | 54 | struct xdomain_request_work { |
| 30 | struct work_struct work; | 55 | struct work_struct work; |
| 31 | struct tb_xdp_header *pkg; | 56 | 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 |
| 235 | } | 260 | } |
| 236 | | 261 | |
| 237 | static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry, | 262 | 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) |
| 239 | { | 264 | { |
| 240 | struct tb_xdp_uuid_response res; | 265 | struct tb_xdp_uuid_response res; |
| 241 | struct tb_xdp_uuid req; | 266 | 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 |
| 258 | return ret; | 283 | return ret; |
| 259 | | 284 | |
| 260 | uuid_copy(uuid, &res.src_uuid); | 285 | uuid_copy(uuid, &res.src_uuid); |
| | 286 | *remote_route = (u64)res.src_route_hi << 32 | res.src_route_lo; |
| | 287 | |
| 261 | return 0; | 288 | return 0; |
| 262 | } | 289 | } |
| 263 | | 290 | |
| @@ -473,6 +500,112 @@ tb_xdp_properties_changed_response(struct tb_ctl *ctl, u64 route, u8 sequence) · 209 unmodified lines |
| 473 | TB_CFG_PKG_XDOMAIN_RESP); | 500 | TB_CFG_PKG_XDOMAIN_RESP); |
| 474 | } | 501 | } |
| 475 | | 502 | |
| | 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 | |
| 476 | /** | 609 | /** |
| 477 | * tb_register_protocol_handler() - Register protocol handler | 610 | * tb_register_protocol_handler() - Register protocol handler |
| 478 | * @handler: Handler to register | 611 | * @handler: Handler to register |
| @@ -600,14 +733,13 @@ static void tb_xdp_handle_request(struct work_struct *work) · 121 unmodified lines |
| 600 | goto out; | 733 | goto out; |
| 601 | } | 734 | } |
| 602 | | 735 | |
| 603 | tb_dbg(tb, "%llx: received XDomain request %#x\n", route, pkg->type); | | |
| 604 | | | |
| 605 | xd = tb_xdomain_find_by_route_locked(tb, route); | 736 | xd = tb_xdomain_find_by_route_locked(tb, route); |
| 606 | if (xd) | 737 | if (xd) |
| 607 | update_property_block(xd); | 738 | update_property_block(xd); |
| 608 | | 739 | |
| 609 | switch (pkg->type) { | 740 | switch (pkg->type) { |
| 610 | case PROPERTIES_REQUEST: | 741 | case PROPERTIES_REQUEST: |
| | 742 | tb_dbg(tb, "%llx: received XDomain properties request\n", route); |
| 611 | if (xd) { | 743 | if (xd) { |
| 612 | ret = tb_xdp_properties_response(tb, ctl, xd, sequence, | 744 | ret = tb_xdp_properties_response(tb, ctl, xd, sequence, |
| 613 | (const struct tb_xdp_properties *)pkg); | 745 | (const struct tb_xdp_properties *)pkg); |
| @@ -615,6 +747,9 @@ static void tb_xdp_handle_request(struct work_struct *work) · 1 unmodified line |
| 615 | break; | 747 | break; |
| 616 | | 748 | |
| 617 | case PROPERTIES_CHANGED_REQUEST: | 749 | case PROPERTIES_CHANGED_REQUEST: |
| | 750 | tb_dbg(tb, "%llx: received XDomain properties changed request\n", |
| | 751 | route); |
| | 752 | |
| 618 | ret = tb_xdp_properties_changed_response(ctl, route, sequence); | 753 | ret = tb_xdp_properties_changed_response(ctl, route, sequence); |
| 619 | | 754 | |
| 620 | /* | 755 | /* |
| @@ -622,18 +757,51 @@ static void tb_xdp_handle_request(struct work_struct *work) · 1 unmodified line |
| 622 | * the xdomain related to this connection as well in | 757 | * the xdomain related to this connection as well in |
| 623 | * case there is a change in services it offers. | 758 | * case there is a change in services it offers. |
| 624 | */ | 759 | */ |
| 625 | if (xd && device_is_registered(&xd->dev)) { | 760 | if (xd && device_is_registered(&xd->dev)) |
| 626 | queue_delayed_work(tb->wq, &xd->get_properties_work, | 761 | queue_delayed_work(tb->wq, &xd->state_work, |
| 627 | msecs_to_jiffies(50)); | 762 | msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); |
| 628 | } | | |
| 629 | break; | 763 | break; |
| 630 | | 764 | |
| 631 | case UUID_REQUEST_OLD: | 765 | case UUID_REQUEST_OLD: |
| 632 | case UUID_REQUEST: | 766 | case UUID_REQUEST: |
| | 767 | tb_dbg(tb, "%llx: received XDomain UUID request\n", route); |
| 633 | ret = tb_xdp_uuid_response(ctl, route, sequence, uuid); | 768 | ret = tb_xdp_uuid_response(ctl, route, sequence, uuid); |
| 634 | break; | 769 | break; |
| 635 | | 770 | |
| | 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 | |
| 636 | default: | 803 | default: |
| | 804 | tb_dbg(tb, "%llx: unknown XDomain request %#x\n", route, pkg->type); |
| 637 | tb_xdp_error_response(ctl, route, sequence, | 805 | tb_xdp_error_response(ctl, route, sequence, |
| 638 | ERROR_NOT_SUPPORTED); | 806 | ERROR_NOT_SUPPORTED); |
| 639 | break; | 807 | break; |
| @@ -1000,32 +1168,38 @@ static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd) · 360 unmodified lines |
| 1000 | return 0; | 1168 | return 0; |
| 1001 | } | 1169 | } |
| 1002 | | 1170 | |
| 1003 | static void tb_xdomain_get_uuid(struct work_struct *work) | 1171 | static int tb_xdomain_get_uuid(struct tb_xdomain *xd) |
| 1004 | { | 1172 | { |
| 1005 | struct tb_xdomain *xd = container_of(work, typeof(*xd), | | |
| 1006 | get_uuid_work.work); | | |
| 1007 | struct tb *tb = xd->tb; | 1173 | struct tb *tb = xd->tb; |
| 1008 | uuid_t uuid; | 1174 | uuid_t uuid; |
| | 1175 | u64 route; |
| 1009 | int ret; | 1176 | int ret; |
| 1010 | | 1177 | |
| 1011 | dev_dbg(&xd->dev, "requesting remote UUID\n"); | 1178 | dev_dbg(&xd->dev, "requesting remote UUID\n"); |
| 1012 | | 1179 | |
| 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); |
| 1014 | if (ret < 0) { | 1182 | if (ret < 0) { |
| 1015 | if (xd->uuid_retries-- > 0) { | 1183 | if (xd->state_retries-- > 0) { |
| 1016 | dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); | 1184 | dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); |
| 1017 | queue_delayed_work(xd->tb->wq, &xd->get_uuid_work, | 1185 | return -EAGAIN; |
| 1018 | msecs_to_jiffies(100)); | | |
| 1019 | } else { | 1186 | } else { |
| 1020 | dev_dbg(&xd->dev, "failed to read remote UUID\n"); | 1187 | dev_dbg(&xd->dev, "failed to read remote UUID\n"); |
| 1021 | } | 1188 | } |
| 1022 | return; | 1189 | return ret; |
| 1023 | } | 1190 | } |
| 1024 | | 1191 | |
| 1025 | dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid); | 1192 | dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid); |
| 1026 | | 1193 | |
| 1027 | if (uuid_equal(&uuid, xd->local_uuid)) | 1194 | if (uuid_equal(&uuid, xd->local_uuid)) { |
| 1028 | dev_dbg(&xd->dev, "intra-domain loop detected\n"); | 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 | } |
| 1029 | | 1203 | |
| 1030 | /* | 1204 | /* |
| 1031 | * If the UUID is different, there is another domain connected | 1205 | * 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 |
| 1035 | if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) { | 1209 | if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) { |
| 1036 | dev_dbg(&xd->dev, "remote UUID is different, unplugging\n"); | 1210 | dev_dbg(&xd->dev, "remote UUID is different, unplugging\n"); |
| 1037 | xd->is_unplugged = true; | 1211 | xd->is_unplugged = true; |
| 1038 | return; | 1212 | return -ENODEV; |
| 1039 | } | 1213 | } |
| 1040 | | 1214 | |
| 1041 | /* First time fill in the missing UUID */ | 1215 | /* First time fill in the missing UUID */ |
| 1042 | if (!xd->remote_uuid) { | 1216 | if (!xd->remote_uuid) { |
| 1043 | xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL); | 1217 | xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL); |
| 1044 | if (!xd->remote_uuid) | 1218 | if (!xd->remote_uuid) |
| 1045 | return; | 1219 | return -ENOMEM; |
| 1046 | } | 1220 | } |
| 1047 | | 1221 | |
| 1048 | /* Now we can start the normal properties exchange */ | 1222 | return 0; |
| 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)); | | |
| 1053 | } | 1223 | } |
| 1054 | | 1224 | |
| 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) |
| 1056 | { | 1357 | { |
| 1057 | struct tb_xdomain *xd = container_of(work, typeof(*xd), | | |
| 1058 | get_properties_work.work); | | |
| 1059 | struct tb_property_dir *dir; | 1358 | struct tb_property_dir *dir; |
| 1060 | struct tb *tb = xd->tb; | 1359 | struct tb *tb = xd->tb; |
| 1061 | bool update = false; | 1360 | bool update = false; |
| @@ -1066,34 +1365,35 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 4 unmodified lines |
| 1066 | dev_dbg(&xd->dev, "requesting remote properties\n"); | 1365 | dev_dbg(&xd->dev, "requesting remote properties\n"); |
| 1067 | | 1366 | |
| 1068 | ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid, | 1367 | 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, |
| 1070 | &block, &gen); | 1369 | &block, &gen); |
| 1071 | if (ret < 0) { | 1370 | if (ret < 0) { |
| 1072 | if (xd->properties_retries-- > 0) { | 1371 | if (xd->state_retries-- > 0) { |
| 1073 | dev_dbg(&xd->dev, | 1372 | dev_dbg(&xd->dev, |
| 1074 | "failed to request remote properties, retrying\n"); | 1373 | "failed to request remote properties, retrying\n"); |
| 1075 | queue_delayed_work(xd->tb->wq, &xd->get_properties_work, | 1374 | return -EAGAIN; |
| 1076 | msecs_to_jiffies(1000)); | | |
| 1077 | } else { | 1375 | } else { |
| 1078 | /* Give up now */ | 1376 | /* Give up now */ |
| 1079 | dev_err(&xd->dev, | 1377 | dev_err(&xd->dev, |
| 1080 | "failed read XDomain properties from %pUb\n", | 1378 | "failed read XDomain properties from %pUb\n", |
| 1081 | xd->remote_uuid); | 1379 | xd->remote_uuid); |
| 1082 | } | 1380 | } |
| 1083 | return; | | |
| 1084 | } | | |
| 1085 | | 1381 | |
| 1086 | xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES; | 1382 | return ret; |
| | 1383 | } |
| 1087 | | 1384 | |
| 1088 | mutex_lock(&xd->lock); | 1385 | mutex_lock(&xd->lock); |
| 1089 | | 1386 | |
| 1090 | /* Only accept newer generation properties */ | 1387 | /* 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; |
| 1092 | goto err_free_block; | 1390 | goto err_free_block; |
| | 1391 | } |
| 1093 | | 1392 | |
| 1094 | dir = tb_property_parse_dir(block, ret); | 1393 | dir = tb_property_parse_dir(block, ret); |
| 1095 | if (!dir) { | 1394 | if (!dir) { |
| 1096 | dev_err(&xd->dev, "failed to parse XDomain properties\n"); | 1395 | dev_err(&xd->dev, "failed to parse XDomain properties\n"); |
| | 1396 | ret = -ENOMEM; |
| 1097 | goto err_free_block; | 1397 | goto err_free_block; |
| 1098 | } | 1398 | } |
| 1099 | | 1399 | |
| @@ -1124,9 +1424,16 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 24 unmodified lines |
| 1124 | * registered, we notify the userspace that it has changed. | 1424 | * registered, we notify the userspace that it has changed. |
| 1125 | */ | 1425 | */ |
| 1126 | if (!update) { | 1426 | 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 | |
| 1127 | if (device_add(&xd->dev)) { | 1434 | if (device_add(&xd->dev)) { |
| 1128 | dev_err(&xd->dev, "failed to add XDomain device\n"); | 1435 | dev_err(&xd->dev, "failed to add XDomain device\n"); |
| 1129 | return; | 1436 | return -ENODEV; |
| 1130 | } | 1437 | } |
| 1131 | dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n", | 1438 | dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n", |
| 1132 | xd->vendor, xd->device); | 1439 | xd->vendor, xd->device); |
| @@ -1138,13 +1445,193 @@ static void tb_xdomain_get_properties(struct work_struct *work) · 5 unmodified lines |
| 1138 | } | 1445 | } |
| 1139 | | 1446 | |
| 1140 | enumerate_services(xd); | 1447 | enumerate_services(xd); |
| 1141 | return; | 1448 | return 0; |
| 1142 | | 1449 | |
| 1143 | err_free_dir: | 1450 | err_free_dir: |
| 1144 | tb_property_free_dir(dir); | 1451 | tb_property_free_dir(dir); |
| 1145 | err_free_block: | 1452 | err_free_block: |
| 1146 | kfree(block); | 1453 | kfree(block); |
| 1147 | mutex_unlock(&xd->lock); | 1454 | 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)); |
| 1148 | } | 1635 | } |
| 1149 | | 1636 | |
| 1150 | static void tb_xdomain_properties_changed(struct work_struct *work) | 1637 | 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 |
| 1163 | "failed to send properties changed notification, retrying\n"); | 1650 | "failed to send properties changed notification, retrying\n"); |
| 1164 | queue_delayed_work(xd->tb->wq, | 1651 | queue_delayed_work(xd->tb->wq, |
| 1165 | &xd->properties_changed_work, | 1652 | &xd->properties_changed_work, |
| 1166 | msecs_to_jiffies(1000)); | 1653 | msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); |
| 1167 | } | 1654 | } |
| 1168 | dev_err(&xd->dev, "failed to send properties changed notification\n"); | 1655 | dev_err(&xd->dev, "failed to send properties changed notification\n"); |
| 1169 | return; | 1656 | return; |
| 1170 | } | 1657 | } |
| 1171 | | 1658 | |
| 1172 | xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES; | 1659 | xd->properties_changed_retries = XDOMAIN_RETRIES; |
| 1173 | } | 1660 | } |
| 1174 | | 1661 | |
| 1175 | static ssize_t device_show(struct device *dev, struct device_attribute *attr, | 1662 | 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 |
| 1304 | | 1791 | |
| 1305 | static void start_handshake(struct tb_xdomain *xd) | 1792 | static void start_handshake(struct tb_xdomain *xd) |
| 1306 | { | 1793 | { |
| 1307 | xd->uuid_retries = XDOMAIN_UUID_RETRIES; | 1794 | xd->state = XDOMAIN_STATE_INIT; |
| 1308 | xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES; | 1795 | queue_delayed_work(xd->tb->wq, &xd->state_work, |
| 1309 | xd->properties_changed_retries = XDOMAIN_PROPERTIES_CHANGED_RETRIES; | 1796 | msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); |
| 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 | } | | |
| 1321 | } | 1797 | } |
| 1322 | | 1798 | |
| 1323 | static void stop_handshake(struct tb_xdomain *xd) | 1799 | static void stop_handshake(struct tb_xdomain *xd) |
| 1324 | { | 1800 | { |
| 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); | | |
| 1331 | cancel_delayed_work_sync(&xd->properties_changed_work); | 1801 | 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; |
| 1332 | } | 1805 | } |
| 1333 | | 1806 | |
| 1334 | static int __maybe_unused tb_xdomain_suspend(struct device *dev) | 1807 | 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 |
| 1389 | ida_init(&xd->in_hopids); | 1862 | ida_init(&xd->in_hopids); |
| 1390 | ida_init(&xd->out_hopids); | 1863 | ida_init(&xd->out_hopids); |
| 1391 | mutex_init(&xd->lock); | 1864 | mutex_init(&xd->lock); |
| 1392 | INIT_DELAYED_WORK(&xd->get_uuid_work, tb_xdomain_get_uuid); | 1865 | INIT_DELAYED_WORK(&xd->state_work, tb_xdomain_state_work); |
| 1393 | INIT_DELAYED_WORK(&xd->get_properties_work, tb_xdomain_get_properties); | | |
| 1394 | INIT_DELAYED_WORK(&xd->properties_changed_work, | 1866 | INIT_DELAYED_WORK(&xd->properties_changed_work, |
| 1395 | tb_xdomain_properties_changed); | 1867 | tb_xdomain_properties_changed); |
| 1396 | | 1868 | |
| @@ -1405,6 +1877,7 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, · 8 unmodified lines |
| 1405 | goto err_free_local_uuid; | 1877 | goto err_free_local_uuid; |
| 1406 | } else { | 1878 | } else { |
| 1407 | xd->needs_uuid = true; | 1879 | xd->needs_uuid = true; |
| | 1880 | xd->bonding_possible = !!down->dual_link_port; |
| 1408 | } | 1881 | } |
| 1409 | | 1882 | |
| 1410 | device_initialize(&xd->dev); | 1883 | device_initialize(&xd->dev); |
| @@ -1523,9 +1996,9 @@ int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd) · 112 unmodified lines |
| 1523 | return ret; | 1996 | return ret; |
| 1524 | } | 1997 | } |
| 1525 | | 1998 | |
| 1526 | ret = tb_port_wait_for_link_width(port, 2, 100); | 1999 | ret = tb_port_wait_for_link_width(port, 2, XDOMAIN_BONDING_TIMEOUT); |
| 1527 | if (ret) { | 2000 | if (ret) { |
| 1528 | tb_port_warn(port, "timeout enabling lane bonding\n"); | 2001 | tb_port_warn(port, "failed to enable lane bonding\n"); |
| 1529 | return ret; | 2002 | return ret; |
| 1530 | } | 2003 | } |
| 1531 | | 2004 | |