1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2021, Intel Corporation. */ 3 4 /* advanced RSS configuration ethtool support for iavf */ 5 6 #include "iavf.h" 7 8 /** 9 * iavf_fill_adv_rss_ip4_hdr - fill the IPv4 RSS protocol header 10 * @hdr: the virtchnl message protocol header data structure 11 * @hash_flds: the RSS configuration protocol hash fields 12 */ 13 static void 14 iavf_fill_adv_rss_ip4_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds) 15 { 16 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4); 17 18 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_SA) 19 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC); 20 21 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_DA) 22 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST); 23 } 24 25 /** 26 * iavf_fill_adv_rss_ip6_hdr - fill the IPv6 RSS protocol header 27 * @hdr: the virtchnl message protocol header data structure 28 * @hash_flds: the RSS configuration protocol hash fields 29 */ 30 static void 31 iavf_fill_adv_rss_ip6_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds) 32 { 33 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6); 34 35 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_SA) 36 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC); 37 38 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_DA) 39 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST); 40 } 41 42 /** 43 * iavf_fill_adv_rss_tcp_hdr - fill the TCP RSS protocol header 44 * @hdr: the virtchnl message protocol header data structure 45 * @hash_flds: the RSS configuration protocol hash fields 46 */ 47 static void 48 iavf_fill_adv_rss_tcp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds) 49 { 50 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP); 51 52 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT) 53 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT); 54 55 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT) 56 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT); 57 } 58 59 /** 60 * iavf_fill_adv_rss_udp_hdr - fill the UDP RSS protocol header 61 * @hdr: the virtchnl message protocol header data structure 62 * @hash_flds: the RSS configuration protocol hash fields 63 */ 64 static void 65 iavf_fill_adv_rss_udp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds) 66 { 67 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP); 68 69 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT) 70 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT); 71 72 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT) 73 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT); 74 } 75 76 /** 77 * iavf_fill_adv_rss_sctp_hdr - fill the SCTP RSS protocol header 78 * @hdr: the virtchnl message protocol header data structure 79 * @hash_flds: the RSS configuration protocol hash fields 80 */ 81 static void 82 iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds) 83 { 84 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP); 85 86 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT) 87 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT); 88 89 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT) 90 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT); 91 } 92 93 /** 94 * iavf_fill_adv_rss_gtp_hdr - Fill GTP-related RSS protocol headers 95 * @proto_hdrs: pointer to the virtchnl protocol headers structure to populate 96 * @packet_hdrs: bitmask of packet header types to configure 97 * @hash_flds: RSS hash field configuration 98 * 99 * This function populates the virtchnl protocol header structure with 100 * appropriate GTP-related header types based on the specified packet_hdrs. 101 * It supports GTPC, GTPU with extension headers, and uplink/downlink PDU 102 * types. For certain GTPU types, it also appends an IPv4 header to enable 103 * hashing on the destination IP address. 104 * 105 * Return: 0 on success or -EOPNOTSUPP if the packet_hdrs value is unsupported. 106 */ 107 static int 108 iavf_fill_adv_rss_gtp_hdr(struct virtchnl_proto_hdrs *proto_hdrs, 109 u32 packet_hdrs, u64 hash_flds) 110 { 111 struct virtchnl_proto_hdr *hdr; 112 113 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 114 115 switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) { 116 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID: 117 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC: 118 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPC); 119 break; 120 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH: 121 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH); 122 break; 123 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP: 124 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_UP); 125 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 126 iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA); 127 break; 128 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN: 129 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_DWN); 130 fallthrough; 131 case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP: 132 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 133 iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA); 134 break; 135 default: 136 return -EOPNOTSUPP; 137 } 138 139 return 0; 140 } 141 142 /** 143 * iavf_fill_adv_rss_cfg_msg - fill the RSS configuration into virtchnl message 144 * @rss_cfg: the virtchnl message to be filled with RSS configuration setting 145 * @packet_hdrs: the RSS configuration protocol header types 146 * @hash_flds: the RSS configuration protocol hash fields 147 * @symm: if true, symmetric hash is required 148 * 149 * Returns 0 if the RSS configuration virtchnl message is filled successfully 150 */ 151 int 152 iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg, 153 u32 packet_hdrs, u64 hash_flds, bool symm) 154 { 155 const u32 packet_l3_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L3; 156 const u32 packet_l4_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L4; 157 struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs; 158 struct virtchnl_proto_hdr *hdr; 159 160 if (symm) 161 rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC; 162 else 163 rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC; 164 165 proto_hdrs->tunnel_level = 0; /* always outer layer */ 166 167 if (packet_l3_hdrs) { 168 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 169 switch (packet_l3_hdrs) { 170 case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4: 171 iavf_fill_adv_rss_ip4_hdr(hdr, hash_flds); 172 break; 173 case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6: 174 iavf_fill_adv_rss_ip6_hdr(hdr, hash_flds); 175 break; 176 default: 177 return -EINVAL; 178 } 179 } 180 181 if (packet_l4_hdrs) { 182 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 183 switch (packet_l4_hdrs) { 184 case IAVF_ADV_RSS_FLOW_SEG_HDR_TCP: 185 iavf_fill_adv_rss_tcp_hdr(hdr, hash_flds); 186 break; 187 case IAVF_ADV_RSS_FLOW_SEG_HDR_UDP: 188 iavf_fill_adv_rss_udp_hdr(hdr, hash_flds); 189 break; 190 case IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP: 191 iavf_fill_adv_rss_sctp_hdr(hdr, hash_flds); 192 break; 193 default: 194 return -EINVAL; 195 } 196 } 197 198 if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) { 199 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 200 if (iavf_fill_adv_rss_gtp_hdr(proto_hdrs, packet_hdrs, hash_flds)) 201 return -EINVAL; 202 } 203 204 return 0; 205 } 206 207 /** 208 * iavf_find_adv_rss_cfg_by_hdrs - find RSS configuration with header type 209 * @adapter: pointer to the VF adapter structure 210 * @packet_hdrs: protocol header type to find. 211 * 212 * Returns pointer to advance RSS configuration if found or null 213 */ 214 struct iavf_adv_rss * 215 iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs) 216 { 217 struct iavf_adv_rss *rss; 218 219 list_for_each_entry(rss, &adapter->adv_rss_list_head, list) 220 if (rss->packet_hdrs == packet_hdrs) 221 return rss; 222 223 return NULL; 224 } 225 226 /** 227 * iavf_print_adv_rss_cfg 228 * @adapter: pointer to the VF adapter structure 229 * @rss: pointer to the advance RSS configuration to print 230 * @action: the string description about how to handle the RSS 231 * @result: the string description about the virtchnl result 232 * 233 * Print the advance RSS configuration 234 **/ 235 void 236 iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss, 237 const char *action, const char *result) 238 { 239 u32 packet_hdrs = rss->packet_hdrs; 240 u64 hash_flds = rss->hash_flds; 241 static char hash_opt[300]; 242 const char *proto; 243 244 if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_TCP) 245 proto = "TCP"; 246 else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_UDP) 247 proto = "UDP"; 248 else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP) 249 proto = "SCTP"; 250 else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) 251 proto = "GTP"; 252 else 253 return; 254 255 memset(hash_opt, 0, sizeof(hash_opt)); 256 257 strcat(hash_opt, proto); 258 if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4) 259 strcat(hash_opt, "v4 "); 260 else 261 strcat(hash_opt, "v6 "); 262 263 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA | 264 IAVF_ADV_RSS_HASH_FLD_IPV6_SA)) 265 strcat(hash_opt, "IP SA,"); 266 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA | 267 IAVF_ADV_RSS_HASH_FLD_IPV6_DA)) 268 strcat(hash_opt, "IP DA,"); 269 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT | 270 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT | 271 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT)) 272 strcat(hash_opt, "src port,"); 273 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT | 274 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT | 275 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT)) 276 strcat(hash_opt, "dst port,"); 277 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPC_TEID) 278 strcat(hash_opt, "gtp-c,"); 279 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_IP_TEID) 280 strcat(hash_opt, "gtp-u ip,"); 281 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_EH_TEID) 282 strcat(hash_opt, "gtp-u ext,"); 283 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_UP_TEID) 284 strcat(hash_opt, "gtp-u ul,"); 285 if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_DWN_TEID) 286 strcat(hash_opt, "gtp-u dl,"); 287 288 if (!action) 289 action = ""; 290 291 if (!result) 292 result = ""; 293 294 dev_info(&adapter->pdev->dev, "%s %s %s\n", action, hash_opt, result); 295 } 296