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

thunderbolt: Allocate credits according to router preferences

The USB4 Connection Manager guide provides detailed information how the
USB4 router buffer (credit) allocation information should be used by the
connection manager when it allocates buffers for different paths. This
patch implements it for Linux. For USB 3.x and DisplayPort we use
directly the router preferences. The rest of the buffer space is then
used for PCIe and DMA (peer-to-peer, XDomain) traffic. DMA tunnels
require at least one buffer and PCIe six, so if there is not enough
buffers we fail the tunnel creation.

For the legacy Thunderbolt 1-3 devices we use the existing hard-coded
scheme except for DMA where we use the values suggested by the USB4 spec
chapter 13.

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

+346 -74
+14
drivers/thunderbolt/tb.h
··· 213 213 * @list: Used to link ports to DP resources list 214 214 * @total_credits: Total number of buffers available for this port 215 215 * @ctl_credits: Buffers reserved for control path 216 + * @dma_credits: Number of credits allocated for DMA tunneling for all 217 + * DMA paths through this port. 216 218 * 217 219 * In USB4 terminology this structure represents an adapter (protocol or 218 220 * lane adapter). ··· 238 236 struct list_head list; 239 237 unsigned int total_credits; 240 238 unsigned int ctl_credits; 239 + unsigned int dma_credits; 241 240 }; 242 241 243 242 /** ··· 943 940 bool tb_path_is_invalid(struct tb_path *path); 944 941 bool tb_path_port_on_path(const struct tb_path *path, 945 942 const struct tb_port *port); 943 + 944 + /** 945 + * tb_path_for_each_hop() - Iterate over each hop on path 946 + * @path: Path whose hops to iterate 947 + * @hop: Hop used as iterator 948 + * 949 + * Iterates over each hop on path. 950 + */ 951 + #define tb_path_for_each_hop(path, hop) \ 952 + for ((hop) = &(path)->hops[0]; \ 953 + (hop) <= &(path)->hops[(path)->path_length - 1]; (hop)++) 946 954 947 955 int tb_drom_read(struct tb_switch *sw); 948 956 int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid);
+330 -74
drivers/thunderbolt/tunnel.c
··· 34 34 #define TB_DP_AUX_PATH_OUT 1 35 35 #define TB_DP_AUX_PATH_IN 2 36 36 37 + /* Minimum number of credits needed for PCIe path */ 38 + #define TB_MIN_PCIE_CREDITS 6U 39 + /* 40 + * Number of credits we try to allocate for each DMA path if not limited 41 + * by the host router baMaxHI. 42 + */ 43 + #define TB_DMA_CREDITS 14U 44 + /* Minimum number of credits for DMA path */ 45 + #define TB_MIN_DMA_CREDITS 1U 46 + 37 47 static const char * const tb_tunnel_names[] = { "PCI", "DP", "DMA", "USB3" }; 38 48 39 49 #define __TB_TUNNEL_PRINT(level, tunnel, fmt, arg...) \ ··· 66 56 __TB_TUNNEL_PRINT(tb_info, tunnel, fmt, ##arg) 67 57 #define tb_tunnel_dbg(tunnel, fmt, arg...) \ 68 58 __TB_TUNNEL_PRINT(tb_dbg, tunnel, fmt, ##arg) 59 + 60 + static inline unsigned int tb_usable_credits(const struct tb_port *port) 61 + { 62 + return port->total_credits - port->ctl_credits; 63 + } 64 + 65 + /** 66 + * tb_available_credits() - Available credits for PCIe and DMA 67 + * @port: Lane adapter to check 68 + * @max_dp_streams: If non-%NULL stores maximum number of simultaneous DP 69 + * streams possible through this lane adapter 70 + */ 71 + static unsigned int tb_available_credits(const struct tb_port *port, 72 + size_t *max_dp_streams) 73 + { 74 + const struct tb_switch *sw = port->sw; 75 + int credits, usb3, pcie, spare; 76 + size_t ndp; 77 + 78 + usb3 = tb_acpi_may_tunnel_usb3() ? sw->max_usb3_credits : 0; 79 + pcie = tb_acpi_may_tunnel_pcie() ? sw->max_pcie_credits : 0; 80 + 81 + if (tb_acpi_is_xdomain_allowed()) { 82 + spare = min_not_zero(sw->max_dma_credits, TB_DMA_CREDITS); 83 + /* Add some credits for potential second DMA tunnel */ 84 + spare += TB_MIN_DMA_CREDITS; 85 + } else { 86 + spare = 0; 87 + } 88 + 89 + credits = tb_usable_credits(port); 90 + if (tb_acpi_may_tunnel_dp()) { 91 + /* 92 + * Maximum number of DP streams possible through the 93 + * lane adapter. 94 + */ 95 + ndp = (credits - (usb3 + pcie + spare)) / 96 + (sw->min_dp_aux_credits + sw->min_dp_main_credits); 97 + } else { 98 + ndp = 0; 99 + } 100 + credits -= ndp * (sw->min_dp_aux_credits + sw->min_dp_main_credits); 101 + credits -= usb3; 102 + 103 + if (max_dp_streams) 104 + *max_dp_streams = ndp; 105 + 106 + return credits > 0 ? credits : 0; 107 + } 69 108 70 109 static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths, 71 110 enum tb_tunnel_type type) ··· 153 94 return 0; 154 95 } 155 96 156 - static int tb_initial_credits(const struct tb_switch *sw) 97 + static int tb_pci_init_credits(struct tb_path_hop *hop) 157 98 { 158 - /* If the path is complete sw is not NULL */ 159 - if (sw) { 160 - /* More credits for faster link */ 161 - switch (sw->link_speed * sw->link_width) { 162 - case 40: 163 - return 32; 164 - case 20: 165 - return 24; 166 - } 99 + struct tb_port *port = hop->in_port; 100 + struct tb_switch *sw = port->sw; 101 + unsigned int credits; 102 + 103 + if (tb_port_use_credit_allocation(port)) { 104 + unsigned int available; 105 + 106 + available = tb_available_credits(port, NULL); 107 + credits = min(sw->max_pcie_credits, available); 108 + 109 + if (credits < TB_MIN_PCIE_CREDITS) 110 + return -ENOSPC; 111 + 112 + credits = max(TB_MIN_PCIE_CREDITS, credits); 113 + } else { 114 + if (tb_port_is_null(port)) 115 + credits = port->bonded ? 32 : 16; 116 + else 117 + credits = 7; 167 118 } 168 119 169 - return 16; 120 + hop->initial_credits = credits; 121 + return 0; 170 122 } 171 123 172 - static void tb_pci_init_path(struct tb_path *path) 124 + static int tb_pci_init_path(struct tb_path *path) 173 125 { 126 + struct tb_path_hop *hop; 127 + 174 128 path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; 175 129 path->egress_shared_buffer = TB_PATH_NONE; 176 130 path->ingress_fc_enable = TB_PATH_ALL; ··· 191 119 path->priority = 3; 192 120 path->weight = 1; 193 121 path->drop_packages = 0; 194 - path->hops[0].initial_credits = 7; 195 - if (path->path_length > 1) 196 - path->hops[1].initial_credits = 197 - tb_initial_credits(path->hops[1].in_port->sw); 122 + 123 + tb_path_for_each_hop(path, hop) { 124 + int ret; 125 + 126 + ret = tb_pci_init_credits(hop); 127 + if (ret) 128 + return ret; 129 + } 130 + 131 + return 0; 198 132 } 199 133 200 134 /** ··· 240 162 goto err_free; 241 163 } 242 164 tunnel->paths[TB_PCI_PATH_UP] = path; 243 - tb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP]); 165 + if (tb_pci_init_path(tunnel->paths[TB_PCI_PATH_UP])) 166 + goto err_free; 244 167 245 168 path = tb_path_discover(tunnel->dst_port, -1, down, TB_PCI_HOPID, NULL, 246 169 "PCIe Down"); 247 170 if (!path) 248 171 goto err_deactivate; 249 172 tunnel->paths[TB_PCI_PATH_DOWN] = path; 250 - tb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN]); 173 + if (tb_pci_init_path(tunnel->paths[TB_PCI_PATH_DOWN])) 174 + goto err_deactivate; 251 175 252 176 /* Validate that the tunnel is complete */ 253 177 if (!tb_port_is_pcie_up(tunnel->dst_port)) { ··· 307 227 308 228 path = tb_path_alloc(tb, down, TB_PCI_HOPID, up, TB_PCI_HOPID, 0, 309 229 "PCIe Down"); 310 - if (!path) { 311 - tb_tunnel_free(tunnel); 312 - return NULL; 313 - } 314 - tb_pci_init_path(path); 230 + if (!path) 231 + goto err_free; 315 232 tunnel->paths[TB_PCI_PATH_DOWN] = path; 233 + if (tb_pci_init_path(path)) 234 + goto err_free; 316 235 317 236 path = tb_path_alloc(tb, up, TB_PCI_HOPID, down, TB_PCI_HOPID, 0, 318 237 "PCIe Up"); 319 - if (!path) { 320 - tb_tunnel_free(tunnel); 321 - return NULL; 322 - } 323 - tb_pci_init_path(path); 238 + if (!path) 239 + goto err_free; 324 240 tunnel->paths[TB_PCI_PATH_UP] = path; 241 + if (tb_pci_init_path(path)) 242 + goto err_free; 325 243 326 244 return tunnel; 245 + 246 + err_free: 247 + tb_tunnel_free(tunnel); 248 + return NULL; 327 249 } 328 250 329 251 static bool tb_dp_is_usb4(const struct tb_switch *sw) ··· 680 598 return 0; 681 599 } 682 600 601 + static void tb_dp_init_aux_credits(struct tb_path_hop *hop) 602 + { 603 + struct tb_port *port = hop->in_port; 604 + struct tb_switch *sw = port->sw; 605 + 606 + if (tb_port_use_credit_allocation(port)) 607 + hop->initial_credits = sw->min_dp_aux_credits; 608 + else 609 + hop->initial_credits = 1; 610 + } 611 + 683 612 static void tb_dp_init_aux_path(struct tb_path *path) 684 613 { 685 - int i; 614 + struct tb_path_hop *hop; 686 615 687 616 path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; 688 617 path->egress_shared_buffer = TB_PATH_NONE; ··· 702 609 path->priority = 2; 703 610 path->weight = 1; 704 611 705 - for (i = 0; i < path->path_length; i++) 706 - path->hops[i].initial_credits = 1; 612 + tb_path_for_each_hop(path, hop) 613 + tb_dp_init_aux_credits(hop); 707 614 } 708 615 709 - static void tb_dp_init_video_path(struct tb_path *path, bool discover) 616 + static int tb_dp_init_video_credits(struct tb_path_hop *hop) 710 617 { 711 - int i; 618 + struct tb_port *port = hop->in_port; 619 + struct tb_switch *sw = port->sw; 620 + 621 + if (tb_port_use_credit_allocation(port)) { 622 + unsigned int nfc_credits; 623 + size_t max_dp_streams; 624 + 625 + tb_available_credits(port, &max_dp_streams); 626 + /* 627 + * Read the number of currently allocated NFC credits 628 + * from the lane adapter. Since we only use them for DP 629 + * tunneling we can use that to figure out how many DP 630 + * tunnels already go through the lane adapter. 631 + */ 632 + nfc_credits = port->config.nfc_credits & 633 + ADP_CS_4_NFC_BUFFERS_MASK; 634 + if (nfc_credits / sw->min_dp_main_credits > max_dp_streams) 635 + return -ENOSPC; 636 + 637 + hop->nfc_credits = sw->min_dp_main_credits; 638 + } else { 639 + hop->nfc_credits = min(port->total_credits - 2, 12U); 640 + } 641 + 642 + return 0; 643 + } 644 + 645 + static int tb_dp_init_video_path(struct tb_path *path) 646 + { 647 + struct tb_path_hop *hop; 712 648 713 649 path->egress_fc_enable = TB_PATH_NONE; 714 650 path->egress_shared_buffer = TB_PATH_NONE; ··· 746 624 path->priority = 1; 747 625 path->weight = 1; 748 626 749 - for (i = 0; i < path->path_length; i++) { 750 - u32 nfc_credits = path->hops[i].in_port->config.nfc_credits; 627 + tb_path_for_each_hop(path, hop) { 628 + int ret; 751 629 752 - if (discover) { 753 - path->hops[i].nfc_credits = 754 - nfc_credits & ADP_CS_4_NFC_BUFFERS_MASK; 755 - } else { 756 - u32 max_credits; 757 - 758 - max_credits = (nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >> 759 - ADP_CS_4_TOTAL_BUFFERS_SHIFT; 760 - /* Leave some credits for AUX path */ 761 - path->hops[i].nfc_credits = min(max_credits - 2, 12U); 762 - } 630 + ret = tb_dp_init_video_credits(hop); 631 + if (ret) 632 + return ret; 763 633 } 634 + 635 + return 0; 764 636 } 765 637 766 638 /** ··· 794 678 goto err_free; 795 679 } 796 680 tunnel->paths[TB_DP_VIDEO_PATH_OUT] = path; 797 - tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT], true); 681 + if (tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT])) 682 + goto err_free; 798 683 799 684 path = tb_path_discover(in, TB_DP_AUX_TX_HOPID, NULL, -1, NULL, "AUX TX"); 800 685 if (!path) ··· 882 765 1, "Video"); 883 766 if (!path) 884 767 goto err_free; 885 - tb_dp_init_video_path(path, false); 768 + tb_dp_init_video_path(path); 886 769 paths[TB_DP_VIDEO_PATH_OUT] = path; 887 770 888 771 path = tb_path_alloc(tb, in, TB_DP_AUX_TX_HOPID, out, ··· 906 789 return NULL; 907 790 } 908 791 909 - static u32 tb_dma_credits(struct tb_port *nhi) 792 + static unsigned int tb_dma_available_credits(const struct tb_port *port) 910 793 { 911 - u32 max_credits; 794 + const struct tb_switch *sw = port->sw; 795 + int credits; 912 796 913 - max_credits = (nhi->config.nfc_credits & ADP_CS_4_TOTAL_BUFFERS_MASK) >> 914 - ADP_CS_4_TOTAL_BUFFERS_SHIFT; 915 - return min(max_credits, 13U); 797 + credits = tb_available_credits(port, NULL); 798 + if (tb_acpi_may_tunnel_pcie()) 799 + credits -= sw->max_pcie_credits; 800 + credits -= port->dma_credits; 801 + 802 + return credits > 0 ? credits : 0; 916 803 } 917 804 918 - static void tb_dma_init_path(struct tb_path *path, unsigned int efc, u32 credits) 805 + static int tb_dma_reserve_credits(struct tb_path_hop *hop, unsigned int credits) 919 806 { 920 - int i; 807 + struct tb_port *port = hop->in_port; 921 808 922 - path->egress_fc_enable = efc; 809 + if (tb_port_use_credit_allocation(port)) { 810 + unsigned int available = tb_dma_available_credits(port); 811 + 812 + /* 813 + * Need to have at least TB_MIN_DMA_CREDITS, otherwise 814 + * DMA path cannot be established. 815 + */ 816 + if (available < TB_MIN_DMA_CREDITS) 817 + return -ENOSPC; 818 + 819 + while (credits > available) 820 + credits--; 821 + 822 + tb_port_dbg(port, "reserving %u credits for DMA path\n", 823 + credits); 824 + 825 + port->dma_credits += credits; 826 + } else { 827 + if (tb_port_is_null(port)) 828 + credits = port->bonded ? 14 : 6; 829 + else 830 + credits = min(port->total_credits, credits); 831 + } 832 + 833 + hop->initial_credits = credits; 834 + return 0; 835 + } 836 + 837 + /* Path from lane adapter to NHI */ 838 + static int tb_dma_init_rx_path(struct tb_path *path, unsigned int credits) 839 + { 840 + struct tb_path_hop *hop; 841 + unsigned int i, tmp; 842 + 843 + path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; 923 844 path->ingress_fc_enable = TB_PATH_ALL; 924 845 path->egress_shared_buffer = TB_PATH_NONE; 925 846 path->ingress_shared_buffer = TB_PATH_NONE; ··· 965 810 path->weight = 1; 966 811 path->clear_fc = true; 967 812 968 - for (i = 0; i < path->path_length; i++) 969 - path->hops[i].initial_credits = credits; 813 + /* 814 + * First lane adapter is the one connected to the remote host. 815 + * We don't tunnel other traffic over this link so can use all 816 + * the credits (except the ones reserved for control traffic). 817 + */ 818 + hop = &path->hops[0]; 819 + tmp = min(tb_usable_credits(hop->in_port), credits); 820 + hop->initial_credits = tmp; 821 + hop->in_port->dma_credits += tmp; 822 + 823 + for (i = 1; i < path->path_length; i++) { 824 + int ret; 825 + 826 + ret = tb_dma_reserve_credits(&path->hops[i], credits); 827 + if (ret) 828 + return ret; 829 + } 830 + 831 + return 0; 832 + } 833 + 834 + /* Path from NHI to lane adapter */ 835 + static int tb_dma_init_tx_path(struct tb_path *path, unsigned int credits) 836 + { 837 + struct tb_path_hop *hop; 838 + 839 + path->egress_fc_enable = TB_PATH_ALL; 840 + path->ingress_fc_enable = TB_PATH_ALL; 841 + path->egress_shared_buffer = TB_PATH_NONE; 842 + path->ingress_shared_buffer = TB_PATH_NONE; 843 + path->priority = 5; 844 + path->weight = 1; 845 + path->clear_fc = true; 846 + 847 + tb_path_for_each_hop(path, hop) { 848 + int ret; 849 + 850 + ret = tb_dma_reserve_credits(hop, credits); 851 + if (ret) 852 + return ret; 853 + } 854 + 855 + return 0; 856 + } 857 + 858 + static void tb_dma_release_credits(struct tb_path_hop *hop) 859 + { 860 + struct tb_port *port = hop->in_port; 861 + 862 + if (tb_port_use_credit_allocation(port)) { 863 + port->dma_credits -= hop->initial_credits; 864 + 865 + tb_port_dbg(port, "released %u DMA path credits\n", 866 + hop->initial_credits); 867 + } 868 + } 869 + 870 + static void tb_dma_deinit_path(struct tb_path *path) 871 + { 872 + struct tb_path_hop *hop; 873 + 874 + tb_path_for_each_hop(path, hop) 875 + tb_dma_release_credits(hop); 876 + } 877 + 878 + static void tb_dma_deinit(struct tb_tunnel *tunnel) 879 + { 880 + int i; 881 + 882 + for (i = 0; i < tunnel->npaths; i++) { 883 + if (!tunnel->paths[i]) 884 + continue; 885 + tb_dma_deinit_path(tunnel->paths[i]); 886 + } 970 887 } 971 888 972 889 /** ··· 1063 836 struct tb_tunnel *tunnel; 1064 837 size_t npaths = 0, i = 0; 1065 838 struct tb_path *path; 1066 - u32 credits; 839 + int credits; 1067 840 1068 841 if (receive_ring > 0) 1069 842 npaths++; ··· 1079 852 1080 853 tunnel->src_port = nhi; 1081 854 tunnel->dst_port = dst; 855 + tunnel->deinit = tb_dma_deinit; 1082 856 1083 - credits = tb_dma_credits(nhi); 857 + credits = min_not_zero(TB_DMA_CREDITS, nhi->sw->max_dma_credits); 1084 858 1085 859 if (receive_ring > 0) { 1086 860 path = tb_path_alloc(tb, dst, receive_path, nhi, receive_ring, 0, 1087 861 "DMA RX"); 1088 - if (!path) { 1089 - tb_tunnel_free(tunnel); 1090 - return NULL; 1091 - } 1092 - tb_dma_init_path(path, TB_PATH_SOURCE | TB_PATH_INTERNAL, credits); 862 + if (!path) 863 + goto err_free; 1093 864 tunnel->paths[i++] = path; 865 + if (tb_dma_init_rx_path(path, credits)) { 866 + tb_tunnel_dbg(tunnel, "not enough buffers for RX path\n"); 867 + goto err_free; 868 + } 1094 869 } 1095 870 1096 871 if (transmit_ring > 0) { 1097 872 path = tb_path_alloc(tb, nhi, transmit_ring, dst, transmit_path, 0, 1098 873 "DMA TX"); 1099 - if (!path) { 1100 - tb_tunnel_free(tunnel); 1101 - return NULL; 1102 - } 1103 - tb_dma_init_path(path, TB_PATH_ALL, credits); 874 + if (!path) 875 + goto err_free; 1104 876 tunnel->paths[i++] = path; 877 + if (tb_dma_init_tx_path(path, credits)) { 878 + tb_tunnel_dbg(tunnel, "not enough buffers for TX path\n"); 879 + goto err_free; 880 + } 1105 881 } 1106 882 1107 883 return tunnel; 884 + 885 + err_free: 886 + tb_tunnel_free(tunnel); 887 + return NULL; 1108 888 } 1109 889 1110 890 /** ··· 1305 1071 tunnel->allocated_up, tunnel->allocated_down); 1306 1072 } 1307 1073 1074 + static void tb_usb3_init_credits(struct tb_path_hop *hop) 1075 + { 1076 + struct tb_port *port = hop->in_port; 1077 + struct tb_switch *sw = port->sw; 1078 + unsigned int credits; 1079 + 1080 + if (tb_port_use_credit_allocation(port)) { 1081 + credits = sw->max_usb3_credits; 1082 + } else { 1083 + if (tb_port_is_null(port)) 1084 + credits = port->bonded ? 32 : 16; 1085 + else 1086 + credits = 7; 1087 + } 1088 + 1089 + hop->initial_credits = credits; 1090 + } 1091 + 1308 1092 static void tb_usb3_init_path(struct tb_path *path) 1309 1093 { 1094 + struct tb_path_hop *hop; 1095 + 1310 1096 path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; 1311 1097 path->egress_shared_buffer = TB_PATH_NONE; 1312 1098 path->ingress_fc_enable = TB_PATH_ALL; ··· 1334 1080 path->priority = 3; 1335 1081 path->weight = 3; 1336 1082 path->drop_packages = 0; 1337 - path->hops[0].initial_credits = 7; 1338 - if (path->path_length > 1) 1339 - path->hops[1].initial_credits = 1340 - tb_initial_credits(path->hops[1].in_port->sw); 1083 + 1084 + tb_path_for_each_hop(path, hop) 1085 + tb_usb3_init_credits(hop); 1341 1086 } 1342 1087 1343 1088 /** ··· 1535 1282 1536 1283 if (!tunnel) 1537 1284 return; 1285 + 1286 + if (tunnel->deinit) 1287 + tunnel->deinit(tunnel); 1538 1288 1539 1289 for (i = 0; i < tunnel->npaths; i++) { 1540 1290 if (tunnel->paths[i])
+2
drivers/thunderbolt/tunnel.h
··· 27 27 * @paths: All paths required by the tunnel 28 28 * @npaths: Number of paths in @paths 29 29 * @init: Optional tunnel specific initialization 30 + * @deinit: Optional tunnel specific de-initialization 30 31 * @activate: Optional tunnel specific activation/deactivation 31 32 * @consumed_bandwidth: Return how much bandwidth the tunnel consumes 32 33 * @release_unused_bandwidth: Release all unused bandwidth ··· 48 47 struct tb_path **paths; 49 48 size_t npaths; 50 49 int (*init)(struct tb_tunnel *tunnel); 50 + void (*deinit)(struct tb_tunnel *tunnel); 51 51 int (*activate)(struct tb_tunnel *tunnel, bool activate); 52 52 int (*consumed_bandwidth)(struct tb_tunnel *tunnel, int *consumed_up, 53 53 int *consumed_down);