1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2023, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the Intel Corporation nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /*$FreeBSD$*/ 32 33 /** 34 * @file ice_common_txrx.h 35 * @brief common Tx/Rx utility functions 36 * 37 * Contains common utility functions for the Tx/Rx hot path. 38 * 39 * The functions do depend on the if_pkt_info_t structure. A suitable 40 * implementation of this structure must be provided if these functions are to 41 * be used without the iflib networking stack. 42 */ 43 44 #ifndef _ICE_COMMON_TXRX_H_ 45 #define _ICE_COMMON_TXRX_H_ 46 47 #include <netinet/udp.h> 48 #include <netinet/sctp.h> 49 50 /** 51 * ice_tso_detect_sparse - detect TSO packets with too many segments 52 * @pi: packet information 53 * 54 * Hardware only transmits packets with a maximum of 8 descriptors. For TSO 55 * packets, hardware needs to be able to build the split packets using 8 or 56 * fewer descriptors. Additionally, the header must be contained within at 57 * most 3 descriptors. 58 * 59 * To verify this, we walk the headers to find out how many descriptors the 60 * headers require (usually 1). Then we ensure that, for each TSO segment, its 61 * data plus the headers are contained within 8 or fewer descriptors. 62 */ 63 static inline int 64 ice_tso_detect_sparse(if_pkt_info_t pi) 65 { 66 int count, curseg, i, hlen, segsz, seglen, tsolen, hdrs, maxsegs; 67 bus_dma_segment_t *segs = pi->ipi_segs; 68 int nsegs = pi->ipi_nsegs; 69 70 curseg = hdrs = 0; 71 72 hlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen; 73 tsolen = pi->ipi_len - hlen; 74 75 /* First, count the number of descriptors for the header. 76 * Additionally, make sure it does not span more than 3 segments. 77 */ 78 i = 0; 79 curseg = segs[0].ds_len; 80 while (hlen > 0) { 81 hdrs++; 82 if (hdrs > ICE_MAX_TSO_HDR_SEGS) 83 return (1); 84 if (curseg == 0) { 85 i++; 86 if (__predict_false(i == nsegs)) 87 return (1); 88 89 curseg = segs[i].ds_len; 90 } 91 seglen = min(curseg, hlen); 92 curseg -= seglen; 93 hlen -= seglen; 94 } 95 96 maxsegs = ICE_MAX_TX_SEGS - hdrs; 97 98 /* We must count the headers, in order to verify that they take up 99 * 3 or fewer descriptors. However, we don't need to check the data 100 * if the total segments is small. 101 */ 102 if (nsegs <= maxsegs) 103 return (0); 104 105 count = 0; 106 107 /* Now check the data to make sure that each TSO segment is made up of 108 * no more than maxsegs descriptors. This ensures that hardware will 109 * be capable of performing TSO offload. 110 */ 111 while (tsolen > 0) { 112 segsz = pi->ipi_tso_segsz; 113 while (segsz > 0 && tsolen != 0) { 114 count++; 115 if (count > maxsegs) { 116 return (1); 117 } 118 if (curseg == 0) { 119 i++; 120 if (__predict_false(i == nsegs)) { 121 return (1); 122 } 123 curseg = segs[i].ds_len; 124 } 125 seglen = min(curseg, segsz); 126 segsz -= seglen; 127 curseg -= seglen; 128 tsolen -= seglen; 129 } 130 count = 0; 131 } 132 133 return (0); 134 } 135 136 /** 137 * ice_tso_setup - Setup a context descriptor to prepare for a TSO packet 138 * @txq: the Tx queue to use 139 * @pi: the packet info to prepare for 140 * 141 * Setup a context descriptor in preparation for sending a Tx packet that 142 * requires the TSO offload. Returns the index of the descriptor to use when 143 * encapsulating the Tx packet data into descriptors. 144 */ 145 static inline int 146 ice_tso_setup(struct ice_tx_queue *txq, if_pkt_info_t pi) 147 { 148 struct ice_tx_ctx_desc *txd; 149 u32 cmd, mss, type, tsolen; 150 int idx; 151 u64 type_cmd_tso_mss; 152 153 idx = pi->ipi_pidx; 154 txd = (struct ice_tx_ctx_desc *)&txq->tx_base[idx]; 155 tsolen = pi->ipi_len - (pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen); 156 157 type = ICE_TX_DESC_DTYPE_CTX; 158 cmd = ICE_TX_CTX_DESC_TSO; 159 /* TSO MSS must not be less than 64 */ 160 if (pi->ipi_tso_segsz < ICE_MIN_TSO_MSS) { 161 txq->stats.mss_too_small++; 162 pi->ipi_tso_segsz = ICE_MIN_TSO_MSS; 163 } 164 mss = pi->ipi_tso_segsz; 165 166 type_cmd_tso_mss = ((u64)type << ICE_TXD_CTX_QW1_DTYPE_S) | 167 ((u64)cmd << ICE_TXD_CTX_QW1_CMD_S) | 168 ((u64)tsolen << ICE_TXD_CTX_QW1_TSO_LEN_S) | 169 ((u64)mss << ICE_TXD_CTX_QW1_MSS_S); 170 txd->qw1 = htole64(type_cmd_tso_mss); 171 172 txd->tunneling_params = htole32(0); 173 txq->tso++; 174 175 return ((idx + 1) & (txq->desc_count-1)); 176 } 177 178 /** 179 * ice_tx_setup_offload - Setup register values for performing a Tx offload 180 * @txq: The Tx queue, used to track checksum offload stats 181 * @pi: the packet info to program for 182 * @cmd: the cmd register value to update 183 * @off: the off register value to update 184 * 185 * Based on the packet info provided, update the cmd and off values for 186 * enabling Tx offloads. This depends on the packet type and which offloads 187 * have been requested. 188 * 189 * We also track the total number of times that we've requested hardware 190 * offload a particular type of checksum for debugging purposes. 191 */ 192 static inline void 193 ice_tx_setup_offload(struct ice_tx_queue *txq, if_pkt_info_t pi, u32 *cmd, u32 *off) 194 { 195 u32 remaining_csum_flags = pi->ipi_csum_flags; 196 197 switch (pi->ipi_etype) { 198 #ifdef INET 199 case ETHERTYPE_IP: 200 if (pi->ipi_csum_flags & ICE_CSUM_IP) { 201 *cmd |= ICE_TX_DESC_CMD_IIPT_IPV4_CSUM; 202 txq->stats.cso[ICE_CSO_STAT_TX_IP4]++; 203 remaining_csum_flags &= ~CSUM_IP; 204 } else 205 *cmd |= ICE_TX_DESC_CMD_IIPT_IPV4; 206 break; 207 #endif 208 #ifdef INET6 209 case ETHERTYPE_IPV6: 210 *cmd |= ICE_TX_DESC_CMD_IIPT_IPV6; 211 /* 212 * This indicates that the IIPT flag was set to the IPV6 value; 213 * there's no checksum for IPv6 packets. 214 */ 215 txq->stats.cso[ICE_CSO_STAT_TX_IP6]++; 216 break; 217 #endif 218 default: 219 txq->stats.cso[ICE_CSO_STAT_TX_L3_ERR]++; 220 break; 221 } 222 223 *off |= (pi->ipi_ehdrlen >> 1) << ICE_TX_DESC_LEN_MACLEN_S; 224 *off |= (pi->ipi_ip_hlen >> 2) << ICE_TX_DESC_LEN_IPLEN_S; 225 226 if (!(remaining_csum_flags & ~ICE_RX_CSUM_FLAGS)) 227 return; 228 229 switch (pi->ipi_ipproto) { 230 case IPPROTO_TCP: 231 if (pi->ipi_csum_flags & ICE_CSUM_TCP) { 232 *cmd |= ICE_TX_DESC_CMD_L4T_EOFT_TCP; 233 *off |= (pi->ipi_tcp_hlen >> 2) << 234 ICE_TX_DESC_LEN_L4_LEN_S; 235 txq->stats.cso[ICE_CSO_STAT_TX_TCP]++; 236 } 237 break; 238 case IPPROTO_UDP: 239 if (pi->ipi_csum_flags & ICE_CSUM_UDP) { 240 *cmd |= ICE_TX_DESC_CMD_L4T_EOFT_UDP; 241 *off |= (sizeof(struct udphdr) >> 2) << 242 ICE_TX_DESC_LEN_L4_LEN_S; 243 txq->stats.cso[ICE_CSO_STAT_TX_UDP]++; 244 } 245 break; 246 case IPPROTO_SCTP: 247 if (pi->ipi_csum_flags & ICE_CSUM_SCTP) { 248 *cmd |= ICE_TX_DESC_CMD_L4T_EOFT_SCTP; 249 *off |= (sizeof(struct sctphdr) >> 2) << 250 ICE_TX_DESC_LEN_L4_LEN_S; 251 txq->stats.cso[ICE_CSO_STAT_TX_SCTP]++; 252 } 253 break; 254 default: 255 txq->stats.cso[ICE_CSO_STAT_TX_L4_ERR]++; 256 break; 257 } 258 } 259 260 /** 261 * ice_rx_checksum - verify hardware checksum is valid or not 262 * @rxq: the Rx queue structure 263 * @flags: checksum flags to update 264 * @data: checksum data to update 265 * @status0: descriptor status data 266 * @ptype: packet type 267 * 268 * Determine whether the hardware indicated that the Rx checksum is valid. If 269 * so, update the checksum flags and data, informing the stack of the status 270 * of the checksum so that it does not spend time verifying it manually. 271 */ 272 static void 273 ice_rx_checksum(struct ice_rx_queue *rxq, uint32_t *flags, uint32_t *data, 274 u16 status0, u16 ptype) 275 { 276 const u16 l3_error = (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) | 277 BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)); 278 const u16 l4_error = (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_L4E_S) | 279 BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EUDPE_S)); 280 const u16 xsum_errors = (l3_error | l4_error | 281 BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S)); 282 struct ice_rx_ptype_decoded decoded; 283 bool is_ipv4, is_ipv6; 284 285 /* No L3 or L4 checksum was calculated */ 286 if (!(status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S))) { 287 return; 288 } 289 290 decoded = ice_decode_rx_desc_ptype(ptype); 291 *flags = 0; 292 293 if (!(decoded.known && decoded.outer_ip)) 294 return; 295 296 is_ipv4 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && 297 (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4); 298 is_ipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && 299 (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6); 300 301 /* No checksum errors were reported */ 302 if (!(status0 & xsum_errors)) { 303 if (is_ipv4) 304 *flags |= CSUM_L3_CALC | CSUM_L3_VALID; 305 306 switch (decoded.inner_prot) { 307 case ICE_RX_PTYPE_INNER_PROT_TCP: 308 case ICE_RX_PTYPE_INNER_PROT_UDP: 309 case ICE_RX_PTYPE_INNER_PROT_SCTP: 310 *flags |= CSUM_L4_CALC | CSUM_L4_VALID; 311 *data |= htons(0xffff); 312 break; 313 default: 314 break; 315 } 316 317 return; 318 } 319 320 /* 321 * Certain IPv6 extension headers impact the validity of L4 checksums. 322 * If one of these headers exist, hardware will set the IPV6EXADD bit 323 * in the descriptor. If the bit is set then pretend like hardware 324 * didn't checksum this packet. 325 */ 326 if (is_ipv6 && (status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S))) { 327 rxq->stats.cso[ICE_CSO_STAT_RX_IP6_ERR]++; 328 return; 329 } 330 331 /* 332 * At this point, status0 must have at least one of the l3_error or 333 * l4_error bits set. 334 */ 335 336 if (status0 & l3_error) { 337 if (is_ipv4) { 338 rxq->stats.cso[ICE_CSO_STAT_RX_IP4_ERR]++; 339 *flags |= CSUM_L3_CALC; 340 } else { 341 /* Hardware indicated L3 error but this isn't IPv4? */ 342 rxq->stats.cso[ICE_CSO_STAT_RX_L3_ERR]++; 343 } 344 /* don't bother reporting L4 errors if we got an L3 error */ 345 return; 346 } else if (is_ipv4) { 347 *flags |= CSUM_L3_CALC | CSUM_L3_VALID; 348 } 349 350 if (status0 & l4_error) { 351 switch (decoded.inner_prot) { 352 case ICE_RX_PTYPE_INNER_PROT_TCP: 353 rxq->stats.cso[ICE_CSO_STAT_RX_TCP_ERR]++; 354 *flags |= CSUM_L4_CALC; 355 break; 356 case ICE_RX_PTYPE_INNER_PROT_UDP: 357 rxq->stats.cso[ICE_CSO_STAT_RX_UDP_ERR]++; 358 *flags |= CSUM_L4_CALC; 359 break; 360 case ICE_RX_PTYPE_INNER_PROT_SCTP: 361 rxq->stats.cso[ICE_CSO_STAT_RX_SCTP_ERR]++; 362 *flags |= CSUM_L4_CALC; 363 break; 364 default: 365 /* 366 * Hardware indicated L4 error, but this isn't one of 367 * the expected protocols. 368 */ 369 rxq->stats.cso[ICE_CSO_STAT_RX_L4_ERR]++; 370 } 371 } 372 } 373 374 /** 375 * ice_ptype_to_hash - Convert packet type to a hash value 376 * @ptype: the packet type to convert 377 * 378 * Given the packet type, convert to a suitable hashtype to report to the 379 * upper stack via the iri_rsstype value of the if_rxd_info_t structure. 380 * 381 * If the hash type is unknown we'll report M_HASHTYPE_OPAQUE. 382 */ 383 static inline int 384 ice_ptype_to_hash(u16 ptype) 385 { 386 struct ice_rx_ptype_decoded decoded; 387 388 if (ptype >= ARRAY_SIZE(ice_ptype_lkup)) 389 return M_HASHTYPE_OPAQUE; 390 391 decoded = ice_decode_rx_desc_ptype(ptype); 392 393 if (!decoded.known) 394 return M_HASHTYPE_OPAQUE; 395 396 if (decoded.outer_ip == ICE_RX_PTYPE_OUTER_L2) 397 return M_HASHTYPE_OPAQUE; 398 399 /* Note: anything that gets to this point is IP */ 400 if (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6) { 401 switch (decoded.inner_prot) { 402 case ICE_RX_PTYPE_INNER_PROT_TCP: 403 return M_HASHTYPE_RSS_TCP_IPV6; 404 case ICE_RX_PTYPE_INNER_PROT_UDP: 405 return M_HASHTYPE_RSS_UDP_IPV6; 406 default: 407 return M_HASHTYPE_RSS_IPV6; 408 } 409 } 410 if (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4) { 411 switch (decoded.inner_prot) { 412 case ICE_RX_PTYPE_INNER_PROT_TCP: 413 return M_HASHTYPE_RSS_TCP_IPV4; 414 case ICE_RX_PTYPE_INNER_PROT_UDP: 415 return M_HASHTYPE_RSS_UDP_IPV4; 416 default: 417 return M_HASHTYPE_RSS_IPV4; 418 } 419 } 420 421 /* We should never get here!! */ 422 return M_HASHTYPE_OPAQUE; 423 } 424 #endif 425