FILE
en_tx.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
1/* 2 * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/tcp.h> 34#include <linux/if_vlan.h> 35#include <net/geneve.h> 36#include <net/dsfield.h> 37#include "en.h" 38#include "en/txrx.h" 39#include "ipoib/ipoib.h" 40#include "en_accel/en_accel.h" 41#include "en_accel/ipsec_rxtx.h" 42#include "en_accel/psp_rxtx.h" 43#include "en_accel/macsec.h" 44#include "en/ptp.h" 45#include <net/ipv6.h> 46 47static void mlx5e_dma_unmap_wqe_err(struct mlx5e_txqsq *sq, u8 num_dma) 48{ 49 int i; 50 51 for (i = 0; i < num_dma; i++) { 52 struct mlx5e_sq_dma *last_pushed_dma = 53 mlx5e_dma_get(sq, --sq->dma_fifo_pc); 54 55 mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma); 56 } 57} 58 59static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb) 60{ 61#define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN) 62 63 return max(skb_network_offset(skb), MLX5E_MIN_INLINE); 64} 65 66static inline int mlx5e_skb_l3_header_offset(struct sk_buff *skb) 67{ 68 if (skb_transport_header_was_set(skb)) 69 return skb_transport_offset(skb); 70 else 71 return mlx5e_skb_l2_header_offset(skb); 72} 73 74static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode, 75 struct sk_buff *skb) 76{ 77 u16 hlen; 78 79 switch (mode) { 80 case MLX5_INLINE_MODE_NONE: 81 return 0; 82 case MLX5_INLINE_MODE_TCP_UDP: 83 hlen = eth_get_headlen(skb->dev, skb->data, skb_headlen(skb)); 84 if (hlen == ETH_HLEN && !skb_vlan_tag_present(skb)) 85 hlen += VLAN_HLEN; 86 break; 87 case MLX5_INLINE_MODE_IP: 88 hlen = mlx5e_skb_l3_header_offset(skb); 89 break; 90 case MLX5_INLINE_MODE_L2: 91 default: 92 hlen = mlx5e_skb_l2_header_offset(skb); 93 } 94 return min_t(u16, hlen, skb_headlen(skb)); 95} 96 97#define MLX5_UNSAFE_MEMCPY_DISCLAIMER \ 98 "This copy has been bounds-checked earlier in " \ 99 "mlx5i_sq_calc_wqe_attr() and intentionally " \ 100 "crosses a flex array boundary. Since it is " \ 101 "performance sensitive, splitting the copy is " \ 102 "undesirable." 103 104static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs) 105{ 106 struct vlan_ethhdr *vhdr = (struct vlan_ethhdr *)start; 107 int cpy1_sz = 2 * ETH_ALEN; 108 int cpy2_sz = ihs - cpy1_sz; 109 110 memcpy(&vhdr->addrs, skb->data, cpy1_sz); 111 vhdr->h_vlan_proto = skb->vlan_proto; 112 vhdr->h_vlan_TCI = cpu_to_be16(skb_vlan_tag_get(skb)); 113 unsafe_memcpy(&vhdr->h_vlan_encapsulated_proto, 114 skb->data + cpy1_sz, 115 cpy2_sz, 116 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 117} 118 119static inline void 120mlx5e_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb, 121 struct mlx5e_accel_tx_state *accel, 122 struct mlx5_wqe_eth_seg *eseg) 123{ 124#ifdef CONFIG_MLX5_EN_PSP 125 if (unlikely(mlx5e_psp_txwqe_build_eseg_csum(sq, skb, &accel->psp_st, eseg))) 126 return; 127#endif 128 129 if (unlikely(mlx5e_ipsec_txwqe_build_eseg_csum(sq, skb, eseg))) 130 return; 131 132 if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { 133 eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM; 134 if (skb->encapsulation) { 135 eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM | 136 MLX5_ETH_WQE_L4_INNER_CSUM; 137 sq->stats->csum_partial_inner++; 138 } else { 139 eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM; 140 sq->stats->csum_partial++; 141 } 142#ifdef CONFIG_MLX5_EN_TLS 143 } else if (unlikely(accel && accel->tls.tls_tisn)) { 144 eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 145 sq->stats->csum_partial++; 146#endif 147 } else 148 sq->stats->csum_none++; 149} 150 151/* Returns the number of header bytes that we plan 152 * to inline later in the transmit descriptor 153 */ 154static inline u16 155mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int *hopbyhop) 156{ 157 struct mlx5e_sq_stats *stats = sq->stats; 158 u16 ihs; 159 160 *hopbyhop = 0; 161 if (skb->encapsulation) { 162 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) 163 ihs = skb_inner_transport_offset(skb) + 164 sizeof(struct udphdr); 165 else 166 ihs = skb_inner_tcp_all_headers(skb); 167 stats->tso_inner_packets++; 168 stats->tso_inner_bytes += skb->len - ihs; 169 } else { 170 if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { 171 ihs = skb_transport_offset(skb) + sizeof(struct udphdr); 172 } else { 173 ihs = skb_tcp_all_headers(skb); 174 if (ipv6_has_hopopt_jumbo(skb)) { 175 *hopbyhop = sizeof(struct hop_jumbo_hdr); 176 ihs -= sizeof(struct hop_jumbo_hdr); 177 } 178 } 179 stats->tso_packets++; 180 stats->tso_bytes += skb->len - ihs - *hopbyhop; 181 } 182 183 return ihs; 184} 185 186static inline int 187mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb, 188 unsigned char *skb_data, u16 headlen, 189 struct mlx5_wqe_data_seg *dseg) 190{ 191 dma_addr_t dma_addr = 0; 192 u8 num_dma = 0; 193 int i; 194 195 if (headlen) { 196 dma_addr = dma_map_single(sq->pdev, skb_data, headlen, 197 DMA_TO_DEVICE); 198 if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) 199 goto dma_unmap_wqe_err; 200 201 dseg->addr = cpu_to_be64(dma_addr); 202 dseg->lkey = sq->mkey_be; 203 dseg->byte_count = cpu_to_be32(headlen); 204 205 mlx5e_dma_push_single(sq, dma_addr, headlen); 206 num_dma++; 207 dseg++; 208 } 209 210 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 211 skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 212 int fsz = skb_frag_size(frag); 213 214 dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz, 215 DMA_TO_DEVICE); 216 if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) 217 goto dma_unmap_wqe_err; 218 219 dseg->addr = cpu_to_be64(dma_addr); 220 dseg->lkey = sq->mkey_be; 221 dseg->byte_count = cpu_to_be32(fsz); 222 223 mlx5e_dma_push_netmem(sq, skb_frag_netmem(frag), dma_addr, fsz); 224 num_dma++; 225 dseg++; 226 } 227 228 return num_dma; 229 230dma_unmap_wqe_err: 231 mlx5e_dma_unmap_wqe_err(sq, num_dma); 232 return -ENOMEM; 233} 234 235struct mlx5e_tx_attr { 236 u32 num_bytes; 237 u16 headlen; 238 u16 ihs; 239 __be16 mss; 240 u16 insz; 241 u8 opcode; 242 u8 hopbyhop; 243}; 244 245struct mlx5e_tx_wqe_attr { 246 u16 ds_cnt; 247 u16 ds_cnt_inl; 248 u16 ds_cnt_ids; 249 u8 num_wqebbs; 250}; 251 252static u8 253mlx5e_tx_wqe_inline_mode(struct mlx5e_txqsq *sq, struct sk_buff *skb, 254 struct mlx5e_accel_tx_state *accel) 255{ 256 u8 mode; 257 258#ifdef CONFIG_MLX5_EN_TLS 259 if (accel->tls.tls_tisn) 260 return MLX5_INLINE_MODE_TCP_UDP; 261#endif 262 263 mode = sq->min_inline_mode; 264 265 if (skb_vlan_tag_present(skb)) 266 mode = max_t(u8, MLX5_INLINE_MODE_L2, mode); 267 268 return mode; 269} 270 271static void mlx5e_sq_xmit_prepare(struct mlx5e_txqsq *sq, struct sk_buff *skb, 272 struct mlx5e_accel_tx_state *accel, 273 struct mlx5e_tx_attr *attr) 274{ 275 struct mlx5e_sq_stats *stats = sq->stats; 276 277 if (skb_is_gso(skb)) { 278 int hopbyhop; 279 u16 ihs = mlx5e_tx_get_gso_ihs(sq, skb, &hopbyhop); 280 281 *attr = (struct mlx5e_tx_attr) { 282 .opcode = MLX5_OPCODE_LSO, 283 .mss = cpu_to_be16(skb_shinfo(skb)->gso_size), 284 .ihs = ihs, 285 .num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs, 286 .headlen = skb_headlen(skb) - ihs - hopbyhop, 287 .hopbyhop = hopbyhop, 288 }; 289 290 stats->packets += skb_shinfo(skb)->gso_segs; 291 } else { 292 u8 mode = mlx5e_tx_wqe_inline_mode(sq, skb, accel); 293 u16 ihs = mlx5e_calc_min_inline(mode, skb); 294 295 *attr = (struct mlx5e_tx_attr) { 296 .opcode = MLX5_OPCODE_SEND, 297 .mss = cpu_to_be16(0), 298 .ihs = ihs, 299 .num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN), 300 .headlen = skb_headlen(skb) - ihs, 301 }; 302 303 stats->packets++; 304 } 305 306 attr->insz = mlx5e_accel_tx_ids_len(sq, skb, accel); 307 stats->bytes += attr->num_bytes; 308} 309 310static void mlx5e_sq_calc_wqe_attr(struct sk_buff *skb, const struct mlx5e_tx_attr *attr, 311 struct mlx5e_tx_wqe_attr *wqe_attr) 312{ 313 u16 ds_cnt = MLX5E_TX_WQE_EMPTY_DS_COUNT; 314 u16 ds_cnt_inl = 0; 315 u16 ds_cnt_ids = 0; 316 317 /* Sync the calculation with MLX5E_MAX_TX_WQEBBS. */ 318 319 if (attr->insz) 320 ds_cnt_ids = DIV_ROUND_UP(sizeof(struct mlx5_wqe_inline_seg) + attr->insz, 321 MLX5_SEND_WQE_DS); 322 323 ds_cnt += !!attr->headlen + skb_shinfo(skb)->nr_frags + ds_cnt_ids; 324 if (attr->ihs) { 325 u16 inl = attr->ihs - INL_HDR_START_SZ; 326 327 if (skb_vlan_tag_present(skb)) 328 inl += VLAN_HLEN; 329 330 ds_cnt_inl = DIV_ROUND_UP(inl, MLX5_SEND_WQE_DS); 331 if (WARN_ON_ONCE(ds_cnt_inl > MLX5E_MAX_TX_INLINE_DS)) 332 netdev_warn(skb->dev, "ds_cnt_inl = %u > max %u\n", ds_cnt_inl, 333 (u16)MLX5E_MAX_TX_INLINE_DS); 334 ds_cnt += ds_cnt_inl; 335 } 336 337 *wqe_attr = (struct mlx5e_tx_wqe_attr) { 338 .ds_cnt = ds_cnt, 339 .ds_cnt_inl = ds_cnt_inl, 340 .ds_cnt_ids = ds_cnt_ids, 341 .num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS), 342 }; 343} 344 345static void mlx5e_tx_skb_update_ts_flags(struct sk_buff *skb) 346{ 347 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 348 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 349 skb_tx_timestamp(skb); 350} 351 352static void mlx5e_tx_check_stop(struct mlx5e_txqsq *sq) 353{ 354 if (unlikely(!mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room))) { 355 netif_tx_stop_queue(sq->txq); 356 sq->stats->stopped++; 357 } 358} 359 360static void mlx5e_tx_flush(struct mlx5e_txqsq *sq) 361{ 362 struct mlx5e_tx_wqe_info *wi; 363 struct mlx5e_tx_wqe *wqe; 364 u16 pi; 365 366 /* Must not be called when a MPWQE session is active but empty. */ 367 mlx5e_tx_mpwqe_ensure_complete(sq); 368 369 pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc); 370 wi = &sq->db.wqe_info[pi]; 371 372 *wi = (struct mlx5e_tx_wqe_info) { 373 .num_wqebbs = 1, 374 }; 375 376 wqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc); 377 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl); 378} 379 380static inline void 381mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb, 382 const struct mlx5e_tx_attr *attr, 383 const struct mlx5e_tx_wqe_attr *wqe_attr, u8 num_dma, 384 struct mlx5e_tx_wqe_info *wi, struct mlx5_wqe_ctrl_seg *cseg, 385 struct mlx5_wqe_eth_seg *eseg, bool xmit_more) 386{ 387 struct mlx5_wq_cyc *wq = &sq->wq; 388 bool send_doorbell; 389 390 *wi = (struct mlx5e_tx_wqe_info) { 391 .skb = skb, 392 .num_bytes = attr->num_bytes, 393 .num_dma = num_dma, 394 .num_wqebbs = wqe_attr->num_wqebbs, 395 .num_fifo_pkts = 0, 396 }; 397 398 cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | attr->opcode); 399 cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | wqe_attr->ds_cnt); 400 401 mlx5e_tx_skb_update_ts_flags(skb); 402 403 sq->pc += wi->num_wqebbs; 404 405 mlx5e_tx_check_stop(sq); 406 407 if (unlikely(sq->ptpsq && 408 (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) { 409 u8 metadata_index = be32_to_cpu(eseg->flow_table_metadata); 410 411 mlx5e_ptp_metadata_fifo_pop(&sq->ptpsq->metadata_freelist); 412 413 mlx5e_skb_cb_hwtstamp_init(skb); 414 mlx5e_ptp_metadata_map_put(&sq->ptpsq->metadata_map, skb, 415 metadata_index); 416 /* ensure skb is put on metadata_map before tracking the index */ 417 wmb(); 418 mlx5e_ptpsq_track_metadata(sq->ptpsq, metadata_index); 419 if (!netif_tx_queue_stopped(sq->txq) && 420 mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq)) { 421 netif_tx_stop_queue(sq->txq); 422 sq->stats->stopped++; 423 } 424 skb_get(skb); 425 } 426 427 send_doorbell = __netdev_tx_sent_queue(sq->txq, attr->num_bytes, xmit_more); 428 if (send_doorbell) 429 mlx5e_notify_hw(wq, sq->pc, sq->uar_map, cseg); 430} 431 432static void 433mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb, 434 const struct mlx5e_tx_attr *attr, const struct mlx5e_tx_wqe_attr *wqe_attr, 435 struct mlx5e_tx_wqe *wqe, u16 pi, bool xmit_more) 436{ 437 struct mlx5_wqe_ctrl_seg *cseg; 438 struct mlx5_wqe_eth_seg *eseg; 439 struct mlx5_wqe_data_seg *dseg; 440 struct mlx5e_tx_wqe_info *wi; 441 u16 ihs = attr->ihs; 442 struct ipv6hdr *h6; 443 struct mlx5e_sq_stats *stats = sq->stats; 444 int num_dma; 445 446 stats->xmit_more += xmit_more; 447 448 /* fill wqe */ 449 wi = &sq->db.wqe_info[pi]; 450 cseg = &wqe->ctrl; 451 eseg = &wqe->eth; 452 dseg = wqe->data; 453 454 eseg->mss = attr->mss; 455 456 if (ihs) { 457 u8 *start = eseg->inline_hdr.start; 458 459 if (unlikely(attr->hopbyhop)) { 460 /* remove the HBH header. 461 * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 462 */ 463 if (skb_vlan_tag_present(skb)) { 464 mlx5e_insert_vlan(start, skb, ETH_HLEN + sizeof(*h6)); 465 ihs += VLAN_HLEN; 466 h6 = (struct ipv6hdr *)(start + sizeof(struct vlan_ethhdr)); 467 } else { 468 unsafe_memcpy(start, skb->data, 469 ETH_HLEN + sizeof(*h6), 470 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 471 h6 = (struct ipv6hdr *)(start + ETH_HLEN); 472 } 473 h6->nexthdr = IPPROTO_TCP; 474 /* Copy the TCP header after the IPv6 one */ 475 memcpy(h6 + 1, 476 skb->data + ETH_HLEN + sizeof(*h6) + 477 sizeof(struct hop_jumbo_hdr), 478 tcp_hdrlen(skb)); 479 /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 480 } else if (skb_vlan_tag_present(skb)) { 481 mlx5e_insert_vlan(start, skb, ihs); 482 ihs += VLAN_HLEN; 483 stats->added_vlan_packets++; 484 } else { 485 unsafe_memcpy(eseg->inline_hdr.start, skb->data, 486 attr->ihs, 487 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 488 } 489 eseg->inline_hdr.sz |= cpu_to_be16(ihs); 490 dseg += wqe_attr->ds_cnt_inl; 491 } 492 493 dseg += wqe_attr->ds_cnt_ids; 494 num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr->ihs + attr->hopbyhop, 495 attr->headlen, dseg); 496 if (unlikely(num_dma < 0)) 497 goto err_drop; 498 499 mlx5e_txwqe_complete(sq, skb, attr, wqe_attr, num_dma, wi, cseg, eseg, xmit_more); 500 501 return; 502 503err_drop: 504 stats->dropped++; 505 dev_kfree_skb_any(skb); 506 mlx5e_tx_flush(sq); 507} 508 509static bool mlx5e_tx_skb_supports_mpwqe(struct sk_buff *skb, struct mlx5e_tx_attr *attr) 510{ 511 return !skb_is_nonlinear(skb) && !skb_vlan_tag_present(skb) && !attr->ihs && 512 !attr->insz && !mlx5e_macsec_skb_is_offload(skb); 513} 514 515static bool mlx5e_tx_mpwqe_same_eseg(struct mlx5e_txqsq *sq, struct mlx5_wqe_eth_seg *eseg) 516{ 517 struct mlx5e_tx_mpwqe *session = &sq->mpwqe; 518 519 /* Assumes the session is already running and has at least one packet. */ 520 return !memcmp(&session->wqe->eth, eseg, MLX5E_ACCEL_ESEG_LEN); 521} 522 523static void mlx5e_tx_mpwqe_session_start(struct mlx5e_txqsq *sq, 524 struct mlx5_wqe_eth_seg *eseg) 525{ 526 struct mlx5e_tx_mpwqe *session = &sq->mpwqe; 527 struct mlx5e_tx_wqe *wqe; 528 u16 pi, num_wqebbs; 529 530 pi = mlx5e_txqsq_get_next_pi_anysize(sq, &num_wqebbs); 531 wqe = MLX5E_TX_FETCH_WQE(sq, pi); 532 net_prefetchw(wqe->data); 533 534 *session = (struct mlx5e_tx_mpwqe) { 535 .wqe = wqe, 536 .bytes_count = 0, 537 .ds_count = MLX5E_TX_WQE_EMPTY_DS_COUNT, 538 .ds_count_max = num_wqebbs * MLX5_SEND_WQEBB_NUM_DS, 539 .pkt_count = 0, 540 .inline_on = 0, 541 }; 542 543 memcpy(&session->wqe->eth, eseg, MLX5E_ACCEL_ESEG_LEN); 544 545 sq->stats->mpwqe_blks++; 546} 547 548static bool mlx5e_tx_mpwqe_session_is_active(struct mlx5e_txqsq *sq) 549{ 550 return sq->mpwqe.wqe; 551} 552 553static void mlx5e_tx_mpwqe_add_dseg(struct mlx5e_txqsq *sq, struct mlx5e_xmit_data *txd) 554{ 555 struct mlx5e_tx_mpwqe *session = &sq->mpwqe; 556 struct mlx5_wqe_data_seg *dseg; 557 558 dseg = (struct mlx5_wqe_data_seg *)session->wqe + session->ds_count; 559 560 session->pkt_count++; 561 session->bytes_count += txd->len; 562 563 dseg->addr = cpu_to_be64(txd->dma_addr); 564 dseg->byte_count = cpu_to_be32(txd->len); 565 dseg->lkey = sq->mkey_be; 566 session->ds_count++; 567 568 sq->stats->mpwqe_pkts++; 569} 570 571static struct mlx5_wqe_ctrl_seg *mlx5e_tx_mpwqe_session_complete(struct mlx5e_txqsq *sq) 572{ 573 struct mlx5e_tx_mpwqe *session = &sq->mpwqe; 574 u8 ds_count = session->ds_count; 575 struct mlx5_wqe_ctrl_seg *cseg; 576 struct mlx5e_tx_wqe_info *wi; 577 u16 pi; 578 579 cseg = &session->wqe->ctrl; 580 cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | MLX5_OPCODE_ENHANCED_MPSW); 581 cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_count); 582 583 pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc); 584 wi = &sq->db.wqe_info[pi]; 585 *wi = (struct mlx5e_tx_wqe_info) { 586 .skb = NULL, 587 .num_bytes = session->bytes_count, 588 .num_wqebbs = DIV_ROUND_UP(ds_count, MLX5_SEND_WQEBB_NUM_DS), 589 .num_dma = session->pkt_count, 590 .num_fifo_pkts = session->pkt_count, 591 }; 592 593 sq->pc += wi->num_wqebbs; 594 595 session->wqe = NULL; 596 597 mlx5e_tx_check_stop(sq); 598 599 return cseg; 600} 601 602static void 603mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb, 604 struct mlx5_wqe_eth_seg *eseg, bool xmit_more) 605{ 606 struct mlx5_wqe_ctrl_seg *cseg; 607 struct mlx5e_xmit_data txd; 608 609 txd.data = skb->data; 610 txd.len = skb->len; 611 612 txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE); 613 if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr))) 614 goto err_unmap; 615 616 if (!mlx5e_tx_mpwqe_session_is_active(sq)) { 617 mlx5e_tx_mpwqe_session_start(sq, eseg); 618 } else if (!mlx5e_tx_mpwqe_same_eseg(sq, eseg)) { 619 mlx5e_tx_mpwqe_session_complete(sq); 620 mlx5e_tx_mpwqe_session_start(sq, eseg); 621 } 622 623 sq->stats->xmit_more += xmit_more; 624 625 mlx5e_dma_push_single(sq, txd.dma_addr, txd.len); 626 mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb); 627 mlx5e_tx_mpwqe_add_dseg(sq, &txd); 628 mlx5e_tx_skb_update_ts_flags(skb); 629 630 if (unlikely(mlx5e_tx_mpwqe_is_full(&sq->mpwqe))) { 631 /* Might stop the queue and affect the retval of __netdev_tx_sent_queue. */ 632 cseg = mlx5e_tx_mpwqe_session_complete(sq); 633 634 if (__netdev_tx_sent_queue(sq->txq, txd.len, xmit_more)) 635 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg); 636 } else if (__netdev_tx_sent_queue(sq->txq, txd.len, xmit_more)) { 637 /* Might stop the queue, but we were asked to ring the doorbell anyway. */ 638 cseg = mlx5e_tx_mpwqe_session_complete(sq); 639 640 mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, cseg); 641 } 642 643 return; 644 645err_unmap: 646 sq->stats->dropped++; 647 dev_kfree_skb_any(skb); 648 mlx5e_tx_flush(sq); 649} 650 651void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq) 652{ 653 /* Unlikely in non-MPWQE workloads; not important in MPWQE workloads. */ 654 if (unlikely(mlx5e_tx_mpwqe_session_is_active(sq))) 655 mlx5e_tx_mpwqe_session_complete(sq); 656} 657 658static void mlx5e_cqe_ts_id_eseg(struct mlx5e_ptpsq *ptpsq, struct sk_buff *skb, 659 struct mlx5_wqe_eth_seg *eseg) 660{ 661 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 662 eseg->flow_table_metadata |= 663 cpu_to_be32(mlx5e_ptp_metadata_fifo_peek(&ptpsq->metadata_freelist)); 664} 665 666static void mlx5e_txwqe_build_eseg(struct mlx5e_priv *priv, struct mlx5e_txqsq *sq, 667 struct sk_buff *skb, struct mlx5e_accel_tx_state *accel, 668 struct mlx5_wqe_eth_seg *eseg, u16 ihs) 669{ 670 mlx5e_accel_tx_eseg(priv, skb, accel, eseg, ihs); 671 mlx5e_txwqe_build_eseg_csum(sq, skb, accel, eseg); 672 if (unlikely(sq->ptpsq)) 673 mlx5e_cqe_ts_id_eseg(sq->ptpsq, skb, eseg); 674} 675 676netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev) 677{ 678 struct mlx5e_priv *priv = netdev_priv(dev); 679 struct mlx5e_accel_tx_state accel = {}; 680 struct mlx5e_tx_wqe_attr wqe_attr; 681 struct mlx5e_tx_attr attr; 682 struct mlx5e_tx_wqe *wqe; 683 struct mlx5e_txqsq *sq; 684 u16 pi; 685 686 /* All changes to txq2sq are performed in sync with mlx5e_xmit, when the 687 * queue being changed is disabled, and smp_wmb guarantees that the 688 * changes are visible before mlx5e_xmit tries to read from txq2sq. It 689 * guarantees that the value of txq2sq[qid] doesn't change while 690 * mlx5e_xmit is running on queue number qid. smb_wmb is paired with 691 * HARD_TX_LOCK around ndo_start_xmit, which serves as an ACQUIRE. 692 */ 693 sq = priv->txq2sq[skb_get_queue_mapping(skb)]; 694 if (unlikely(!sq)) { 695 /* Two cases when sq can be NULL: 696 * 1. The HTB node is registered, and mlx5e_select_queue 697 * selected its queue ID, but the SQ itself is not yet created. 698 * 2. HTB SQ creation failed. Similar to the previous case, but 699 * the SQ won't be created. 700 */ 701 dev_kfree_skb_any(skb); 702 return NETDEV_TX_OK; 703 } 704 705 /* May send SKBs and WQEs. */ 706 if (unlikely(!mlx5e_accel_tx_begin(dev, sq, skb, &accel))) 707 return NETDEV_TX_OK; 708 709 mlx5e_sq_xmit_prepare(sq, skb, &accel, &attr); 710 711 if (test_bit(MLX5E_SQ_STATE_MPWQE, &sq->state)) { 712 if (mlx5e_tx_skb_supports_mpwqe(skb, &attr)) { 713 struct mlx5_wqe_eth_seg eseg = {}; 714 715 mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &eseg, attr.ihs); 716 mlx5e_sq_xmit_mpwqe(sq, skb, &eseg, netdev_xmit_more()); 717 return NETDEV_TX_OK; 718 } 719 720 mlx5e_tx_mpwqe_ensure_complete(sq); 721 } 722 723 mlx5e_sq_calc_wqe_attr(skb, &attr, &wqe_attr); 724 pi = mlx5e_txqsq_get_next_pi(sq, wqe_attr.num_wqebbs); 725 wqe = MLX5E_TX_FETCH_WQE(sq, pi); 726 727 /* May update the WQE, but may not post other WQEs. */ 728 mlx5e_accel_tx_finish(sq, wqe, &accel, 729 (struct mlx5_wqe_inline_seg *)(wqe->data + wqe_attr.ds_cnt_inl)); 730 mlx5e_txwqe_build_eseg(priv, sq, skb, &accel, &wqe->eth, attr.ihs); 731 mlx5e_sq_xmit_wqe(sq, skb, &attr, &wqe_attr, wqe, pi, netdev_xmit_more()); 732 733 return NETDEV_TX_OK; 734} 735 736static void mlx5e_tx_wi_dma_unmap(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi, 737 u32 *dma_fifo_cc) 738{ 739 int i; 740 741 for (i = 0; i < wi->num_dma; i++) { 742 struct mlx5e_sq_dma *dma = mlx5e_dma_get(sq, (*dma_fifo_cc)++); 743 744 mlx5e_tx_dma_unmap(sq->pdev, dma); 745 } 746} 747 748static void mlx5e_consume_skb(struct mlx5e_txqsq *sq, struct sk_buff *skb, 749 struct mlx5_cqe64 *cqe, int napi_budget) 750{ 751 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 752 struct skb_shared_hwtstamps hwts = {}; 753 u64 ts = get_cqe_ts(cqe); 754 755 hwts.hwtstamp = mlx5e_cqe_ts_to_ns(sq->ptp_cyc2time, sq->clock, ts); 756 if (sq->ptpsq) { 757 mlx5e_skb_cb_hwtstamp_handler(skb, MLX5E_SKB_CB_CQE_HWTSTAMP, 758 hwts.hwtstamp, sq->ptpsq); 759 } else { 760 skb_tstamp_tx(skb, &hwts); 761 sq->stats->timestamps++; 762 } 763 } 764 765 napi_consume_skb(skb, napi_budget); 766} 767 768static void mlx5e_tx_wi_consume_fifo_skbs(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi, 769 struct mlx5_cqe64 *cqe, int napi_budget) 770{ 771 int i; 772 773 for (i = 0; i < wi->num_fifo_pkts; i++) { 774 struct sk_buff *skb = mlx5e_skb_fifo_pop(&sq->db.skb_fifo); 775 776 mlx5e_consume_skb(sq, skb, cqe, napi_budget); 777 } 778} 779 780void mlx5e_txqsq_wake(struct mlx5e_txqsq *sq) 781{ 782 if (netif_tx_queue_stopped(sq->txq) && 783 mlx5e_wqc_has_room_for(&sq->wq, sq->cc, sq->pc, sq->stop_room) && 784 !mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq) && 785 !test_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { 786 netif_tx_wake_queue(sq->txq); 787 sq->stats->wake++; 788 } 789} 790 791bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) 792{ 793 struct mlx5e_sq_stats *stats; 794 struct mlx5e_txqsq *sq; 795 struct mlx5_cqe64 *cqe; 796 u32 dma_fifo_cc; 797 u32 nbytes; 798 u16 npkts; 799 u16 sqcc; 800 int i; 801 802 sq = container_of(cq, struct mlx5e_txqsq, cq); 803 804 if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state))) 805 return false; 806 807 cqe = mlx5_cqwq_get_cqe(&cq->wq); 808 if (!cqe) 809 return false; 810 811 stats = sq->stats; 812 813 npkts = 0; 814 nbytes = 0; 815 816 /* sq->cc must be updated only after mlx5_cqwq_update_db_record(), 817 * otherwise a cq overrun may occur 818 */ 819 sqcc = sq->cc; 820 821 /* avoid dirtying sq cache line every cqe */ 822 dma_fifo_cc = sq->dma_fifo_cc; 823 824 i = 0; 825 do { 826 struct mlx5e_tx_wqe_info *wi; 827 u16 wqe_counter; 828 bool last_wqe; 829 u16 ci; 830 831 mlx5_cqwq_pop(&cq->wq); 832 833 wqe_counter = be16_to_cpu(cqe->wqe_counter); 834 835 do { 836 last_wqe = (sqcc == wqe_counter); 837 838 ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc); 839 wi = &sq->db.wqe_info[ci]; 840 841 sqcc += wi->num_wqebbs; 842 843 if (likely(wi->skb)) { 844 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc); 845 mlx5e_consume_skb(sq, wi->skb, cqe, napi_budget); 846 847 npkts++; 848 nbytes += wi->num_bytes; 849 continue; 850 } 851 852 if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, 853 &dma_fifo_cc))) 854 continue; 855 856 if (wi->num_fifo_pkts) { 857 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc); 858 mlx5e_tx_wi_consume_fifo_skbs(sq, wi, cqe, napi_budget); 859 860 npkts += wi->num_fifo_pkts; 861 nbytes += wi->num_bytes; 862 } 863 } while (!last_wqe); 864 865 if (unlikely(get_cqe_opcode(cqe) == MLX5_CQE_REQ_ERR)) { 866 if (!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, 867 &sq->state)) { 868 mlx5e_dump_error_cqe(&sq->cq, sq->sqn, 869 (struct mlx5_err_cqe *)cqe); 870 mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs); 871 queue_work(cq->workqueue, &sq->recover_work); 872 } 873 stats->cqe_err++; 874 } 875 876 } while ((++i < MLX5E_TX_CQ_POLL_BUDGET) && (cqe = mlx5_cqwq_get_cqe(&cq->wq))); 877 878 stats->cqes += i; 879 880 mlx5_cqwq_update_db_record(&cq->wq); 881 882 /* ensure cq space is freed before enabling more cqes */ 883 wmb(); 884 885 sq->dma_fifo_cc = dma_fifo_cc; 886 sq->cc = sqcc; 887 888 netdev_tx_completed_queue(sq->txq, npkts, nbytes); 889 890 mlx5e_txqsq_wake(sq); 891 892 return (i == MLX5E_TX_CQ_POLL_BUDGET); 893} 894 895static void mlx5e_tx_wi_kfree_fifo_skbs(struct mlx5e_txqsq *sq, struct mlx5e_tx_wqe_info *wi) 896{ 897 int i; 898 899 for (i = 0; i < wi->num_fifo_pkts; i++) 900 dev_kfree_skb_any(mlx5e_skb_fifo_pop(&sq->db.skb_fifo)); 901} 902 903void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq) 904{ 905 struct mlx5e_tx_wqe_info *wi; 906 u32 dma_fifo_cc, nbytes = 0; 907 u16 ci, sqcc, npkts = 0; 908 909 sqcc = sq->cc; 910 dma_fifo_cc = sq->dma_fifo_cc; 911 912 while (sqcc != sq->pc) { 913 ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc); 914 wi = &sq->db.wqe_info[ci]; 915 916 sqcc += wi->num_wqebbs; 917 918 if (likely(wi->skb)) { 919 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc); 920 dev_kfree_skb_any(wi->skb); 921 922 npkts++; 923 nbytes += wi->num_bytes; 924 continue; 925 } 926 927 if (unlikely(mlx5e_ktls_tx_try_handle_resync_dump_comp(sq, wi, &dma_fifo_cc))) 928 continue; 929 930 if (wi->num_fifo_pkts) { 931 mlx5e_tx_wi_dma_unmap(sq, wi, &dma_fifo_cc); 932 mlx5e_tx_wi_kfree_fifo_skbs(sq, wi); 933 934 npkts += wi->num_fifo_pkts; 935 nbytes += wi->num_bytes; 936 } 937 } 938 939 sq->dma_fifo_cc = dma_fifo_cc; 940 sq->cc = sqcc; 941 942 /* Do not update BQL for TXQs that got replaced by new active ones, as 943 * netdev_tx_reset_queue() is called for them in mlx5e_activate_txqsq(). 944 */ 945 if (sq == sq->priv->txq2sq[sq->txq_ix]) 946 netdev_tx_completed_queue(sq->txq, npkts, nbytes); 947} 948 949#ifdef CONFIG_MLX5_CORE_IPOIB 950static inline void 951mlx5i_txwqe_build_datagram(struct mlx5_av *av, u32 dqpn, u32 dqkey, 952 struct mlx5_wqe_datagram_seg *dseg) 953{ 954 memcpy(&dseg->av, av, sizeof(struct mlx5_av)); 955 dseg->av.dqp_dct = cpu_to_be32(dqpn | MLX5_EXTENDED_UD_AV); 956 dseg->av.key.qkey.qkey = cpu_to_be32(dqkey); 957} 958 959static void mlx5i_sq_calc_wqe_attr(struct sk_buff *skb, 960 const struct mlx5e_tx_attr *attr, 961 struct mlx5e_tx_wqe_attr *wqe_attr) 962{ 963 u16 ds_cnt = sizeof(struct mlx5i_tx_wqe) / MLX5_SEND_WQE_DS; 964 u16 ds_cnt_inl = 0; 965 966 ds_cnt += !!attr->headlen + skb_shinfo(skb)->nr_frags; 967 968 if (attr->ihs) { 969 u16 inl = attr->ihs - INL_HDR_START_SZ; 970 971 ds_cnt_inl = DIV_ROUND_UP(inl, MLX5_SEND_WQE_DS); 972 ds_cnt += ds_cnt_inl; 973 } 974 975 *wqe_attr = (struct mlx5e_tx_wqe_attr) { 976 .ds_cnt = ds_cnt, 977 .ds_cnt_inl = ds_cnt_inl, 978 .num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS), 979 }; 980} 981 982void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb, 983 struct mlx5_av *av, u32 dqpn, u32 dqkey, bool xmit_more) 984{ 985 struct mlx5e_tx_wqe_attr wqe_attr; 986 struct mlx5e_tx_attr attr; 987 struct mlx5i_tx_wqe *wqe; 988 989 struct mlx5e_accel_tx_state accel = {}; 990 struct mlx5_wqe_datagram_seg *datagram; 991 struct mlx5_wqe_ctrl_seg *cseg; 992 struct mlx5_wqe_eth_seg *eseg; 993 struct mlx5_wqe_data_seg *dseg; 994 struct mlx5e_tx_wqe_info *wi; 995 996 struct mlx5e_sq_stats *stats = sq->stats; 997 int num_dma; 998 u16 pi; 999 1000 mlx5e_sq_xmit_prepare(sq, skb, &accel, &attr); 1001 mlx5i_sq_calc_wqe_attr(skb, &attr, &wqe_attr); 1002 1003 pi = mlx5e_txqsq_get_next_pi(sq, wqe_attr.num_wqebbs); 1004 wqe = MLX5I_SQ_FETCH_WQE(sq, pi); 1005 1006 stats->xmit_more += xmit_more; 1007 1008 /* fill wqe */ 1009 wi = &sq->db.wqe_info[pi]; 1010 cseg = &wqe->ctrl; 1011 datagram = &wqe->datagram; 1012 eseg = &wqe->eth; 1013 dseg = wqe->data; 1014 1015 mlx5i_txwqe_build_datagram(av, dqpn, dqkey, datagram); 1016 1017 mlx5e_txwqe_build_eseg_csum(sq, skb, &accel, eseg); 1018 1019 eseg->mss = attr.mss; 1020 1021 if (attr.ihs) { 1022 if (unlikely(attr.hopbyhop)) { 1023 struct ipv6hdr *h6; 1024 1025 /* remove the HBH header. 1026 * Layout: [Ethernet header][IPv6 header][HBH][TCP header] 1027 */ 1028 unsafe_memcpy(eseg->inline_hdr.start, skb->data, 1029 ETH_HLEN + sizeof(*h6), 1030 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1031 h6 = (struct ipv6hdr *)((char *)eseg->inline_hdr.start + ETH_HLEN); 1032 h6->nexthdr = IPPROTO_TCP; 1033 /* Copy the TCP header after the IPv6 one */ 1034 unsafe_memcpy(h6 + 1, 1035 skb->data + ETH_HLEN + sizeof(*h6) + 1036 sizeof(struct hop_jumbo_hdr), 1037 tcp_hdrlen(skb), 1038 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1039 /* Leave ipv6 payload_len set to 0, as LSO v2 specs request. */ 1040 } else { 1041 unsafe_memcpy(eseg->inline_hdr.start, skb->data, 1042 attr.ihs, 1043 MLX5_UNSAFE_MEMCPY_DISCLAIMER); 1044 } 1045 eseg->inline_hdr.sz = cpu_to_be16(attr.ihs); 1046 dseg += wqe_attr.ds_cnt_inl; 1047 } 1048 1049 num_dma = mlx5e_txwqe_build_dsegs(sq, skb, skb->data + attr.ihs + attr.hopbyhop, 1050 attr.headlen, dseg); 1051 if (unlikely(num_dma < 0)) 1052 goto err_drop; 1053 1054 mlx5e_txwqe_complete(sq, skb, &attr, &wqe_attr, num_dma, wi, cseg, eseg, xmit_more); 1055 1056 return; 1057 1058err_drop: 1059 stats->dropped++; 1060 dev_kfree_skb_any(skb); 1061 mlx5e_tx_flush(sq); 1062} 1063#endif
~/
Read-only file preview.