Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thunderbolt: Add support for USB4 v2 80 Gb/s link

USB4 v2 bumps the per-lane speed up to 40 Gb/s. Also the lanes are
always bonded which gives 80 Gb/s symmetric link (and 120/40 Gb/s
asymmetric). This updates the speed and width of routers and XDomain
connections to support the Gen 4 link. For now we keep the link as is
even if it is already asymmetric.

While there make tb_port_set_link_width() static.

Signed-off-by: Gil Fine <gil.fine@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

authored by

Gil Fine and committed by
Mika Westerberg
e111fb92 6e21007d

+266 -88
+7 -3
drivers/thunderbolt/dma_test.c
··· 412 412 static int speed_validate(u64 val) 413 413 { 414 414 switch (val) { 415 + case 40: 415 416 case 20: 416 417 case 10: 417 418 case 0: ··· 490 489 if (!dt->error_code) { 491 490 if (dt->link_speed && dt->xd->link_speed != dt->link_speed) { 492 491 dt->error_code = DMA_TEST_SPEED_ERROR; 493 - } else if (dt->link_width && 494 - dt->xd->link_width != dt->link_width) { 495 - dt->error_code = DMA_TEST_WIDTH_ERROR; 492 + } else if (dt->link_width) { 493 + const struct tb_xdomain *xd = dt->xd; 494 + 495 + if ((dt->link_width == 1 && xd->link_width != TB_LINK_WIDTH_SINGLE) || 496 + (dt->link_width == 2 && xd->link_width < TB_LINK_WIDTH_DUAL)) 497 + dt->error_code = DMA_TEST_WIDTH_ERROR; 496 498 } else if (dt->packets_to_send != dt->packets_sent || 497 499 dt->packets_to_receive != dt->packets_received || 498 500 dt->crc_errors || dt->buffer_overflow_errors) {
+4 -2
drivers/thunderbolt/icm.c
··· 850 850 sw->security_level = security_level; 851 851 sw->boot = boot; 852 852 sw->link_speed = speed_gen3 ? 20 : 10; 853 - sw->link_width = dual_lane ? 2 : 1; 853 + sw->link_width = dual_lane ? TB_LINK_WIDTH_DUAL : 854 + TB_LINK_WIDTH_SINGLE; 854 855 sw->rpm = intel_vss_is_rtd3(pkg->ep_name, sizeof(pkg->ep_name)); 855 856 856 857 if (add_switch(parent_sw, sw)) ··· 1273 1272 sw->security_level = security_level; 1274 1273 sw->boot = boot; 1275 1274 sw->link_speed = speed_gen3 ? 20 : 10; 1276 - sw->link_width = dual_lane ? 2 : 1; 1275 + sw->link_width = dual_lane ? TB_LINK_WIDTH_DUAL : 1276 + TB_LINK_WIDTH_SINGLE; 1277 1277 sw->rpm = force_rtd3; 1278 1278 if (!sw->rpm) 1279 1279 sw->rpm = intel_vss_is_rtd3(pkg->ep_name,
+128 -57
drivers/thunderbolt/switch.c
··· 903 903 904 904 speed = (val & LANE_ADP_CS_1_CURRENT_SPEED_MASK) >> 905 905 LANE_ADP_CS_1_CURRENT_SPEED_SHIFT; 906 - return speed == LANE_ADP_CS_1_CURRENT_SPEED_GEN3 ? 20 : 10; 906 + 907 + switch (speed) { 908 + case LANE_ADP_CS_1_CURRENT_SPEED_GEN4: 909 + return 40; 910 + case LANE_ADP_CS_1_CURRENT_SPEED_GEN3: 911 + return 20; 912 + default: 913 + return 10; 914 + } 907 915 } 908 916 909 917 /** 910 918 * tb_port_get_link_width() - Get current link width 911 919 * @port: Port to check (USB4 or CIO) 912 920 * 913 - * Returns link width. Return values can be 1 (Single-Lane), 2 (Dual-Lane) 914 - * or negative errno in case of failure. 921 + * Returns link width. Return the link width as encoded in &enum 922 + * tb_link_width or negative errno in case of failure. 915 923 */ 916 924 int tb_port_get_link_width(struct tb_port *port) 917 925 { ··· 934 926 if (ret) 935 927 return ret; 936 928 929 + /* Matches the values in enum tb_link_width */ 937 930 return (val & LANE_ADP_CS_1_CURRENT_WIDTH_MASK) >> 938 931 LANE_ADP_CS_1_CURRENT_WIDTH_SHIFT; 939 932 } 940 933 941 - static bool tb_port_is_width_supported(struct tb_port *port, int width) 934 + static bool tb_port_is_width_supported(struct tb_port *port, 935 + unsigned int width_mask) 942 936 { 943 937 u32 phy, widths; 944 938 int ret; ··· 956 946 widths = (phy & LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK) >> 957 947 LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT; 958 948 959 - return !!(widths & width); 949 + return widths & width_mask; 950 + } 951 + 952 + static bool is_gen4_link(struct tb_port *port) 953 + { 954 + return tb_port_get_link_speed(port) > 20; 960 955 } 961 956 962 957 /** 963 958 * tb_port_set_link_width() - Set target link width of the lane adapter 964 959 * @port: Lane adapter 965 - * @width: Target link width (%1 or %2) 960 + * @width: Target link width 966 961 * 967 962 * Sets the target link width of the lane adapter to @width. Does not 968 963 * enable/disable lane bonding. For that call tb_port_set_lane_bonding(). 969 964 * 970 965 * Return: %0 in case of success and negative errno in case of error 971 966 */ 972 - int tb_port_set_link_width(struct tb_port *port, unsigned int width) 967 + int tb_port_set_link_width(struct tb_port *port, enum tb_link_width width) 973 968 { 974 969 u32 val; 975 970 int ret; ··· 989 974 990 975 val &= ~LANE_ADP_CS_1_TARGET_WIDTH_MASK; 991 976 switch (width) { 992 - case 1: 977 + case TB_LINK_WIDTH_SINGLE: 978 + /* Gen 4 link cannot be single */ 979 + if (is_gen4_link(port)) 980 + return -EOPNOTSUPP; 993 981 val |= LANE_ADP_CS_1_TARGET_WIDTH_SINGLE << 994 982 LANE_ADP_CS_1_TARGET_WIDTH_SHIFT; 995 983 break; 996 - case 2: 984 + case TB_LINK_WIDTH_DUAL: 997 985 val |= LANE_ADP_CS_1_TARGET_WIDTH_DUAL << 998 986 LANE_ADP_CS_1_TARGET_WIDTH_SHIFT; 999 987 break; ··· 1018 1000 * cases one should use tb_port_lane_bonding_enable() instead to enable 1019 1001 * lane bonding. 1020 1002 * 1021 - * As a side effect sets @port->bonding accordingly (and does the same 1022 - * for lane 1 too). 1023 - * 1024 1003 * Return: %0 in case of success and negative errno in case of error 1025 1004 */ 1026 - int tb_port_set_lane_bonding(struct tb_port *port, bool bonding) 1005 + static int tb_port_set_lane_bonding(struct tb_port *port, bool bonding) 1027 1006 { 1028 1007 u32 val; 1029 1008 int ret; ··· 1038 1023 else 1039 1024 val &= ~LANE_ADP_CS_1_LB; 1040 1025 1041 - ret = tb_port_write(port, &val, TB_CFG_PORT, 1042 - port->cap_phy + LANE_ADP_CS_1, 1); 1043 - if (ret) 1044 - return ret; 1045 - 1046 - /* 1047 - * When lane 0 bonding is set it will affect lane 1 too so 1048 - * update both. 1049 - */ 1050 - port->bonded = bonding; 1051 - port->dual_link_port->bonded = bonding; 1052 - 1053 - return 0; 1026 + return tb_port_write(port, &val, TB_CFG_PORT, 1027 + port->cap_phy + LANE_ADP_CS_1, 1); 1054 1028 } 1055 1029 1056 1030 /** ··· 1056 1052 */ 1057 1053 int tb_port_lane_bonding_enable(struct tb_port *port) 1058 1054 { 1055 + enum tb_link_width width; 1059 1056 int ret; 1060 1057 1061 1058 /* 1062 1059 * Enable lane bonding for both links if not already enabled by 1063 1060 * for example the boot firmware. 1064 1061 */ 1065 - ret = tb_port_get_link_width(port); 1066 - if (ret == 1) { 1067 - ret = tb_port_set_link_width(port, 2); 1062 + width = tb_port_get_link_width(port); 1063 + if (width == TB_LINK_WIDTH_SINGLE) { 1064 + ret = tb_port_set_link_width(port, TB_LINK_WIDTH_DUAL); 1068 1065 if (ret) 1069 1066 goto err_lane0; 1070 1067 } 1071 1068 1072 - ret = tb_port_get_link_width(port->dual_link_port); 1073 - if (ret == 1) { 1074 - ret = tb_port_set_link_width(port->dual_link_port, 2); 1069 + width = tb_port_get_link_width(port->dual_link_port); 1070 + if (width == TB_LINK_WIDTH_SINGLE) { 1071 + ret = tb_port_set_link_width(port->dual_link_port, 1072 + TB_LINK_WIDTH_DUAL); 1075 1073 if (ret) 1076 1074 goto err_lane0; 1077 1075 } 1078 1076 1079 - ret = tb_port_set_lane_bonding(port, true); 1080 - if (ret) 1081 - goto err_lane1; 1077 + /* 1078 + * Only set bonding if the link was not already bonded. This 1079 + * avoids the lane adapter to re-enter bonding state. 1080 + */ 1081 + if (width == TB_LINK_WIDTH_SINGLE) { 1082 + ret = tb_port_set_lane_bonding(port, true); 1083 + if (ret) 1084 + goto err_lane1; 1085 + } 1086 + 1087 + /* 1088 + * When lane 0 bonding is set it will affect lane 1 too so 1089 + * update both. 1090 + */ 1091 + port->bonded = true; 1092 + port->dual_link_port->bonded = true; 1082 1093 1083 1094 return 0; 1084 1095 1085 1096 err_lane1: 1086 - tb_port_set_link_width(port->dual_link_port, 1); 1097 + tb_port_set_link_width(port->dual_link_port, TB_LINK_WIDTH_SINGLE); 1087 1098 err_lane0: 1088 - tb_port_set_link_width(port, 1); 1099 + tb_port_set_link_width(port, TB_LINK_WIDTH_SINGLE); 1100 + 1089 1101 return ret; 1090 1102 } 1091 1103 ··· 1115 1095 void tb_port_lane_bonding_disable(struct tb_port *port) 1116 1096 { 1117 1097 tb_port_set_lane_bonding(port, false); 1118 - tb_port_set_link_width(port->dual_link_port, 1); 1119 - tb_port_set_link_width(port, 1); 1098 + tb_port_set_link_width(port->dual_link_port, TB_LINK_WIDTH_SINGLE); 1099 + tb_port_set_link_width(port, TB_LINK_WIDTH_SINGLE); 1100 + port->dual_link_port->bonded = false; 1101 + port->bonded = false; 1120 1102 } 1121 1103 1122 1104 /** 1123 1105 * tb_port_wait_for_link_width() - Wait until link reaches specific width 1124 1106 * @port: Port to wait for 1125 - * @width: Expected link width (%1 or %2) 1107 + * @width_mask: Expected link width mask 1126 1108 * @timeout_msec: Timeout in ms how long to wait 1127 1109 * 1128 1110 * Should be used after both ends of the link have been bonded (or 1129 1111 * bonding has been disabled) to wait until the link actually reaches 1130 - * the expected state. Returns %-ETIMEDOUT if the @width was not reached 1131 - * within the given timeout, %0 if it did. 1112 + * the expected state. Returns %-ETIMEDOUT if the width was not reached 1113 + * within the given timeout, %0 if it did. Can be passed a mask of 1114 + * expected widths and succeeds if any of the widths is reached. 1132 1115 */ 1133 - int tb_port_wait_for_link_width(struct tb_port *port, int width, 1116 + int tb_port_wait_for_link_width(struct tb_port *port, unsigned int width_mask, 1134 1117 int timeout_msec) 1135 1118 { 1136 1119 ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec); 1137 1120 int ret; 1121 + 1122 + /* Gen 4 link does not support single lane */ 1123 + if ((width_mask & TB_LINK_WIDTH_SINGLE) && is_gen4_link(port)) 1124 + return -EOPNOTSUPP; 1138 1125 1139 1126 do { 1140 1127 ret = tb_port_get_link_width(port); ··· 1153 1126 */ 1154 1127 if (ret != -EACCES) 1155 1128 return ret; 1156 - } else if (ret == width) { 1129 + } else if (ret & width_mask) { 1157 1130 return 0; 1158 1131 } 1159 1132 ··· 1805 1778 static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL); 1806 1779 static DEVICE_ATTR(tx_speed, 0444, speed_show, NULL); 1807 1780 1808 - static ssize_t lanes_show(struct device *dev, struct device_attribute *attr, 1809 - char *buf) 1781 + static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr, 1782 + char *buf) 1810 1783 { 1811 1784 struct tb_switch *sw = tb_to_switch(dev); 1785 + unsigned int width; 1812 1786 1813 - return sysfs_emit(buf, "%u\n", sw->link_width); 1787 + switch (sw->link_width) { 1788 + case TB_LINK_WIDTH_SINGLE: 1789 + case TB_LINK_WIDTH_ASYM_TX: 1790 + width = 1; 1791 + break; 1792 + case TB_LINK_WIDTH_DUAL: 1793 + width = 2; 1794 + break; 1795 + case TB_LINK_WIDTH_ASYM_RX: 1796 + width = 3; 1797 + break; 1798 + default: 1799 + WARN_ON_ONCE(1); 1800 + return -EINVAL; 1801 + } 1802 + 1803 + return sysfs_emit(buf, "%u\n", width); 1814 1804 } 1805 + static DEVICE_ATTR(rx_lanes, 0444, rx_lanes_show, NULL); 1815 1806 1816 - /* 1817 - * Currently link has same amount of lanes both directions (1 or 2) but 1818 - * expose them separately to allow possible asymmetric links in the future. 1819 - */ 1820 - static DEVICE_ATTR(rx_lanes, 0444, lanes_show, NULL); 1821 - static DEVICE_ATTR(tx_lanes, 0444, lanes_show, NULL); 1807 + static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr, 1808 + char *buf) 1809 + { 1810 + struct tb_switch *sw = tb_to_switch(dev); 1811 + unsigned int width; 1812 + 1813 + switch (sw->link_width) { 1814 + case TB_LINK_WIDTH_SINGLE: 1815 + case TB_LINK_WIDTH_ASYM_RX: 1816 + width = 1; 1817 + break; 1818 + case TB_LINK_WIDTH_DUAL: 1819 + width = 2; 1820 + break; 1821 + case TB_LINK_WIDTH_ASYM_TX: 1822 + width = 3; 1823 + break; 1824 + default: 1825 + WARN_ON_ONCE(1); 1826 + return -EINVAL; 1827 + } 1828 + 1829 + return sysfs_emit(buf, "%u\n", width); 1830 + } 1831 + static DEVICE_ATTR(tx_lanes, 0444, tx_lanes_show, NULL); 1822 1832 1823 1833 static ssize_t nvm_authenticate_show(struct device *dev, 1824 1834 struct device_attribute *attr, char *buf) ··· 2688 2624 { 2689 2625 struct tb_port *up, *down; 2690 2626 u64 route = tb_route(sw); 2627 + unsigned int width_mask; 2691 2628 int ret; 2692 2629 2693 2630 if (!route) ··· 2700 2635 up = tb_upstream_port(sw); 2701 2636 down = tb_switch_downstream_port(sw); 2702 2637 2703 - if (!tb_port_is_width_supported(up, 2) || 2704 - !tb_port_is_width_supported(down, 2)) 2638 + if (!tb_port_is_width_supported(up, TB_LINK_WIDTH_DUAL) || 2639 + !tb_port_is_width_supported(down, TB_LINK_WIDTH_DUAL)) 2705 2640 return 0; 2706 2641 2707 2642 ret = tb_port_lane_bonding_enable(up); ··· 2717 2652 return ret; 2718 2653 } 2719 2654 2720 - ret = tb_port_wait_for_link_width(down, 2, 100); 2655 + /* Any of the widths are all bonded */ 2656 + width_mask = TB_LINK_WIDTH_DUAL | TB_LINK_WIDTH_ASYM_TX | 2657 + TB_LINK_WIDTH_ASYM_RX; 2658 + 2659 + ret = tb_port_wait_for_link_width(down, width_mask, 100); 2721 2660 if (ret) { 2722 2661 tb_port_warn(down, "timeout enabling lane bonding\n"); 2723 2662 return ret; ··· 2745 2676 void tb_switch_lane_bonding_disable(struct tb_switch *sw) 2746 2677 { 2747 2678 struct tb_port *up, *down; 2679 + int ret; 2748 2680 2749 2681 if (!tb_route(sw)) 2750 2682 return; ··· 2763 2693 * It is fine if we get other errors as the router might have 2764 2694 * been unplugged. 2765 2695 */ 2766 - if (tb_port_wait_for_link_width(down, 1, 100) == -ETIMEDOUT) 2696 + ret = tb_port_wait_for_link_width(down, TB_LINK_WIDTH_SINGLE, 100); 2697 + if (ret == -ETIMEDOUT) 2767 2698 tb_sw_warn(sw, "timeout disabling lane bonding\n"); 2768 2699 2769 2700 tb_port_update_credits(down);
+33 -5
drivers/thunderbolt/tb.c
··· 570 570 usb3_consumed_down = 0; 571 571 } 572 572 573 - *available_up = *available_down = 40000; 573 + /* Maximum possible bandwidth asymmetric Gen 4 link is 120 Gb/s */ 574 + *available_up = *available_down = 120000; 574 575 575 576 /* Find the minimum available bandwidth over all links */ 576 577 tb_for_each_port_on_path(src_port, dst_port, port) { ··· 582 581 583 582 if (tb_is_upstream_port(port)) { 584 583 link_speed = port->sw->link_speed; 584 + /* 585 + * sw->link_width is from upstream perspective 586 + * so we use the opposite for downstream of the 587 + * host router. 588 + */ 589 + if (port->sw->link_width == TB_LINK_WIDTH_ASYM_TX) { 590 + up_bw = link_speed * 3 * 1000; 591 + down_bw = link_speed * 1 * 1000; 592 + } else if (port->sw->link_width == TB_LINK_WIDTH_ASYM_RX) { 593 + up_bw = link_speed * 1 * 1000; 594 + down_bw = link_speed * 3 * 1000; 595 + } else { 596 + up_bw = link_speed * port->sw->link_width * 1000; 597 + down_bw = up_bw; 598 + } 585 599 } else { 586 600 link_speed = tb_port_get_link_speed(port); 587 601 if (link_speed < 0) 588 602 return link_speed; 603 + 604 + link_width = tb_port_get_link_width(port); 605 + if (link_width < 0) 606 + return link_width; 607 + 608 + if (link_width == TB_LINK_WIDTH_ASYM_TX) { 609 + up_bw = link_speed * 1 * 1000; 610 + down_bw = link_speed * 3 * 1000; 611 + } else if (link_width == TB_LINK_WIDTH_ASYM_RX) { 612 + up_bw = link_speed * 3 * 1000; 613 + down_bw = link_speed * 1 * 1000; 614 + } else { 615 + up_bw = link_speed * link_width * 1000; 616 + down_bw = up_bw; 617 + } 589 618 } 590 619 591 - link_width = port->bonded ? 2 : 1; 592 - 593 - up_bw = link_speed * link_width * 1000; /* Mb/s */ 594 620 /* Leave 10% guard band */ 595 621 up_bw -= up_bw / 10; 596 - down_bw = up_bw; 622 + down_bw -= down_bw / 10; 597 623 598 624 tb_port_dbg(port, "link total bandwidth %d/%d Mb/s\n", up_bw, 599 625 down_bw);
+9 -5
drivers/thunderbolt/tb.h
··· 135 135 * @vendor_name: Name of the vendor (or %NULL if not known) 136 136 * @device_name: Name of the device (or %NULL if not known) 137 137 * @link_speed: Speed of the link in Gb/s 138 - * @link_width: Width of the link (1 or 2) 138 + * @link_width: Width of the upstream facing link 139 139 * @link_usb4: Upstream link is USB4 140 140 * @generation: Switch Thunderbolt generation 141 141 * @cap_plug_events: Offset to the plug events capability (%0 if not found) ··· 173 173 * switches) you need to have domain lock held. 174 174 * 175 175 * In USB4 terminology this structure represents a router. 176 + * 177 + * Note @link_width is not the same as whether link is bonded or not. 178 + * For Gen 4 links the link is also bonded when it is asymmetric. The 179 + * correct way to find out whether the link is bonded or not is to look 180 + * @bonded field of the upstream port. 176 181 */ 177 182 struct tb_switch { 178 183 struct device dev; ··· 193 188 const char *vendor_name; 194 189 const char *device_name; 195 190 unsigned int link_speed; 196 - unsigned int link_width; 191 + enum tb_link_width link_width; 197 192 bool link_usb4; 198 193 unsigned int generation; 199 194 int cap_plug_events; ··· 1055 1050 1056 1051 int tb_port_get_link_speed(struct tb_port *port); 1057 1052 int tb_port_get_link_width(struct tb_port *port); 1058 - int tb_port_set_link_width(struct tb_port *port, unsigned int width); 1059 - int tb_port_set_lane_bonding(struct tb_port *port, bool bonding); 1053 + int tb_port_set_link_width(struct tb_port *port, enum tb_link_width width); 1060 1054 int tb_port_lane_bonding_enable(struct tb_port *port); 1061 1055 void tb_port_lane_bonding_disable(struct tb_port *port); 1062 - int tb_port_wait_for_link_width(struct tb_port *port, int width, 1056 + int tb_port_wait_for_link_width(struct tb_port *port, unsigned int width_mask, 1063 1057 int timeout_msec); 1064 1058 int tb_port_update_credits(struct tb_port *port); 1065 1059
+1
drivers/thunderbolt/tb_regs.h
··· 346 346 #define LANE_ADP_CS_1_CURRENT_SPEED_SHIFT 16 347 347 #define LANE_ADP_CS_1_CURRENT_SPEED_GEN2 0x8 348 348 #define LANE_ADP_CS_1_CURRENT_SPEED_GEN3 0x4 349 + #define LANE_ADP_CS_1_CURRENT_SPEED_GEN4 0x2 349 350 #define LANE_ADP_CS_1_CURRENT_WIDTH_MASK GENMASK(25, 20) 350 351 #define LANE_ADP_CS_1_CURRENT_WIDTH_SHIFT 20 351 352 #define LANE_ADP_CS_1_PMS BIT(30)
+68 -14
drivers/thunderbolt/xdomain.c
··· 1290 1290 1291 1291 static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd) 1292 1292 { 1293 + unsigned int width, width_mask; 1293 1294 struct tb_port *port; 1294 - int ret, width; 1295 + int ret; 1295 1296 1296 1297 if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_SINGLE) { 1297 - width = 1; 1298 + width = TB_LINK_WIDTH_SINGLE; 1299 + width_mask = width; 1298 1300 } else if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_DUAL) { 1299 - width = 2; 1301 + width = TB_LINK_WIDTH_DUAL; 1302 + width_mask = width | TB_LINK_WIDTH_ASYM_TX | TB_LINK_WIDTH_ASYM_RX; 1300 1303 } else { 1301 1304 if (xd->state_retries-- > 0) { 1302 1305 dev_dbg(&xd->dev, ··· 1331 1328 return ret; 1332 1329 } 1333 1330 1334 - ret = tb_port_wait_for_link_width(port, width, XDOMAIN_BONDING_TIMEOUT); 1331 + ret = tb_port_wait_for_link_width(port, width_mask, 1332 + XDOMAIN_BONDING_TIMEOUT); 1335 1333 if (ret) { 1336 1334 dev_warn(&xd->dev, "error waiting for link width to become %d\n", 1337 - width); 1335 + width_mask); 1338 1336 return ret; 1339 1337 } 1340 1338 1341 - port->bonded = width == 2; 1342 - port->dual_link_port->bonded = width == 2; 1339 + port->bonded = width > TB_LINK_WIDTH_SINGLE; 1340 + port->dual_link_port->bonded = width > TB_LINK_WIDTH_SINGLE; 1343 1341 1344 1342 tb_port_update_credits(port); 1345 1343 tb_xdomain_update_link_attributes(xd); ··· 1739 1735 static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL); 1740 1736 static DEVICE_ATTR(tx_speed, 0444, speed_show, NULL); 1741 1737 1742 - static ssize_t lanes_show(struct device *dev, struct device_attribute *attr, 1743 - char *buf) 1738 + static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr, 1739 + char *buf) 1744 1740 { 1745 1741 struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1742 + unsigned int width; 1746 1743 1747 - return sysfs_emit(buf, "%u\n", xd->link_width); 1744 + switch (xd->link_width) { 1745 + case TB_LINK_WIDTH_SINGLE: 1746 + case TB_LINK_WIDTH_ASYM_RX: 1747 + width = 1; 1748 + break; 1749 + case TB_LINK_WIDTH_DUAL: 1750 + width = 2; 1751 + break; 1752 + case TB_LINK_WIDTH_ASYM_TX: 1753 + width = 3; 1754 + break; 1755 + default: 1756 + WARN_ON_ONCE(1); 1757 + return -EINVAL; 1758 + } 1759 + 1760 + return sysfs_emit(buf, "%u\n", width); 1748 1761 } 1762 + static DEVICE_ATTR(rx_lanes, 0444, rx_lanes_show, NULL); 1749 1763 1750 - static DEVICE_ATTR(rx_lanes, 0444, lanes_show, NULL); 1751 - static DEVICE_ATTR(tx_lanes, 0444, lanes_show, NULL); 1764 + static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr, 1765 + char *buf) 1766 + { 1767 + struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1768 + unsigned int width; 1769 + 1770 + switch (xd->link_width) { 1771 + case TB_LINK_WIDTH_SINGLE: 1772 + case TB_LINK_WIDTH_ASYM_TX: 1773 + width = 1; 1774 + break; 1775 + case TB_LINK_WIDTH_DUAL: 1776 + width = 2; 1777 + break; 1778 + case TB_LINK_WIDTH_ASYM_RX: 1779 + width = 3; 1780 + break; 1781 + default: 1782 + WARN_ON_ONCE(1); 1783 + return -EINVAL; 1784 + } 1785 + 1786 + return sysfs_emit(buf, "%u\n", width); 1787 + } 1788 + static DEVICE_ATTR(tx_lanes, 0444, tx_lanes_show, NULL); 1752 1789 1753 1790 static struct attribute *xdomain_attrs[] = { 1754 1791 &dev_attr_device.attr, ··· 2019 1974 */ 2020 1975 int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd) 2021 1976 { 1977 + unsigned int width_mask; 2022 1978 struct tb_port *port; 2023 1979 int ret; 2024 1980 ··· 2043 1997 return ret; 2044 1998 } 2045 1999 2046 - ret = tb_port_wait_for_link_width(port, 2, XDOMAIN_BONDING_TIMEOUT); 2000 + /* Any of the widths are all bonded */ 2001 + width_mask = TB_LINK_WIDTH_DUAL | TB_LINK_WIDTH_ASYM_TX | 2002 + TB_LINK_WIDTH_ASYM_RX; 2003 + 2004 + ret = tb_port_wait_for_link_width(port, width_mask, 2005 + XDOMAIN_BONDING_TIMEOUT); 2047 2006 if (ret) { 2048 2007 tb_port_warn(port, "failed to enable lane bonding\n"); 2049 2008 return ret; ··· 2075 2024 2076 2025 port = tb_xdomain_downstream_port(xd); 2077 2026 if (port->dual_link_port) { 2027 + int ret; 2028 + 2078 2029 tb_port_lane_bonding_disable(port); 2079 - if (tb_port_wait_for_link_width(port, 1, 100) == -ETIMEDOUT) 2030 + ret = tb_port_wait_for_link_width(port, TB_LINK_WIDTH_SINGLE, 100); 2031 + if (ret == -ETIMEDOUT) 2080 2032 tb_port_warn(port, "timeout disabling lane bonding\n"); 2081 2033 tb_port_disable(port->dual_link_port); 2082 2034 tb_port_update_credits(port);
+16 -2
include/linux/thunderbolt.h
··· 172 172 void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir); 173 173 174 174 /** 175 + * enum tb_link_width - Thunderbolt/USB4 link width 176 + * @TB_LINK_WIDTH_SINGLE: Single lane link 177 + * @TB_LINK_WIDTH_DUAL: Dual lane symmetric link 178 + * @TB_LINK_WIDTH_ASYM_TX: Dual lane asymmetric Gen 4 link with 3 trasmitters 179 + * @TB_LINK_WIDTH_ASYM_RX: Dual lane asymmetric Gen 4 link with 3 receivers 180 + */ 181 + enum tb_link_width { 182 + TB_LINK_WIDTH_SINGLE = BIT(0), 183 + TB_LINK_WIDTH_DUAL = BIT(1), 184 + TB_LINK_WIDTH_ASYM_TX = BIT(2), 185 + TB_LINK_WIDTH_ASYM_RX = BIT(3), 186 + }; 187 + 188 + /** 175 189 * struct tb_xdomain - Cross-domain (XDomain) connection 176 190 * @dev: XDomain device 177 191 * @tb: Pointer to the domain ··· 200 186 * @vendor_name: Name of the vendor (or %NULL if not known) 201 187 * @device_name: Name of the device (or %NULL if not known) 202 188 * @link_speed: Speed of the link in Gb/s 203 - * @link_width: Width of the link (1 or 2) 189 + * @link_width: Width of the downstream facing link 204 190 * @link_usb4: Downstream link is USB4 205 191 * @is_unplugged: The XDomain is unplugged 206 192 * @needs_uuid: If the XDomain does not have @remote_uuid it will be ··· 248 234 const char *vendor_name; 249 235 const char *device_name; 250 236 unsigned int link_speed; 251 - unsigned int link_width; 237 + enum tb_link_width link_width; 252 238 bool link_usb4; 253 239 bool is_unplugged; 254 240 bool needs_uuid;