1377b69fbSMichael Baum /* SPDX-License-Identifier: BSD-3-Clause 2377b69fbSMichael Baum * Copyright 2021 6WIND S.A. 3377b69fbSMichael Baum * Copyright 2021 Mellanox Technologies, Ltd 4377b69fbSMichael Baum */ 5377b69fbSMichael Baum 6377b69fbSMichael Baum #ifndef RTE_PMD_MLX5_TX_H_ 7377b69fbSMichael Baum #define RTE_PMD_MLX5_TX_H_ 8377b69fbSMichael Baum 9377b69fbSMichael Baum #include <stdint.h> 10377b69fbSMichael Baum #include <sys/queue.h> 11377b69fbSMichael Baum 12377b69fbSMichael Baum #include <rte_mbuf.h> 13377b69fbSMichael Baum #include <rte_mempool.h> 14377b69fbSMichael Baum #include <rte_common.h> 15377b69fbSMichael Baum #include <rte_spinlock.h> 16a1e910f5SViacheslav Ovsiienko #include <rte_trace_point.h> 17377b69fbSMichael Baum 185dfa003dSMichael Baum #include <mlx5_common.h> 19377b69fbSMichael Baum #include <mlx5_common_mr.h> 20377b69fbSMichael Baum 21377b69fbSMichael Baum #include "mlx5.h" 22377b69fbSMichael Baum #include "mlx5_autoconf.h" 23a1e910f5SViacheslav Ovsiienko #include "mlx5_rxtx.h" 24a1e910f5SViacheslav Ovsiienko #include "mlx5_trace.h" 25377b69fbSMichael Baum 26256fb0e3SMichael Baum /* TX burst subroutines return codes. */ 27256fb0e3SMichael Baum enum mlx5_txcmp_code { 28256fb0e3SMichael Baum MLX5_TXCMP_CODE_EXIT = 0, 29256fb0e3SMichael Baum MLX5_TXCMP_CODE_ERROR, 30256fb0e3SMichael Baum MLX5_TXCMP_CODE_SINGLE, 31256fb0e3SMichael Baum MLX5_TXCMP_CODE_MULTI, 32256fb0e3SMichael Baum MLX5_TXCMP_CODE_TSO, 33256fb0e3SMichael Baum MLX5_TXCMP_CODE_EMPW, 34256fb0e3SMichael Baum }; 35256fb0e3SMichael Baum 36256fb0e3SMichael Baum /* 37256fb0e3SMichael Baum * These defines are used to configure Tx burst routine option set supported 38256fb0e3SMichael Baum * at compile time. The not specified options are optimized out due to if 39256fb0e3SMichael Baum * conditions can be explicitly calculated at compile time. 40256fb0e3SMichael Baum * The offloads with bigger runtime check (require more CPU cycles toskip) 41256fb0e3SMichael Baum * overhead should have the bigger index - this is needed to select the better 42256fb0e3SMichael Baum * matching routine function if no exact match and some offloads are not 43256fb0e3SMichael Baum * actually requested. 44256fb0e3SMichael Baum */ 45256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_MULTI (1u << 0) /* Multi-segment packets.*/ 46256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_TSO (1u << 1) /* TCP send offload supported.*/ 47256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_SWP (1u << 2) /* Tunnels/SW Parser offloads.*/ 48256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_CSUM (1u << 3) /* Check Sums offloaded. */ 49256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_INLINE (1u << 4) /* Data inlining supported. */ 50256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_VLAN (1u << 5) /* VLAN insertion supported.*/ 51256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_METADATA (1u << 6) /* Flow metadata. */ 52256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_EMPW (1u << 8) /* Enhanced MPW supported.*/ 53256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_MPW (1u << 9) /* Legacy MPW supported.*/ 54256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_TXPP (1u << 10) /* Scheduling on timestamp.*/ 55256fb0e3SMichael Baum 56256fb0e3SMichael Baum /* The most common offloads groups. */ 57256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_NONE 0 58256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG_FULL (MLX5_TXOFF_CONFIG_MULTI | \ 59256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_TSO | \ 60256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_SWP | \ 61256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_CSUM | \ 62256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_INLINE | \ 63256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_VLAN | \ 64256fb0e3SMichael Baum MLX5_TXOFF_CONFIG_METADATA) 65256fb0e3SMichael Baum 66256fb0e3SMichael Baum #define MLX5_TXOFF_CONFIG(mask) (olx & MLX5_TXOFF_CONFIG_##mask) 67256fb0e3SMichael Baum 6879a876e3SMichael Baum #define MLX5_TXOFF_PRE_DECL(func) \ 6979a876e3SMichael Baum uint16_t mlx5_tx_burst_##func(void *txq, \ 7079a876e3SMichael Baum struct rte_mbuf **pkts, \ 7179a876e3SMichael Baum uint16_t pkts_n) 7279a876e3SMichael Baum 73256fb0e3SMichael Baum #define MLX5_TXOFF_DECL(func, olx) \ 7479a876e3SMichael Baum uint16_t mlx5_tx_burst_##func(void *txq, \ 75256fb0e3SMichael Baum struct rte_mbuf **pkts, \ 76256fb0e3SMichael Baum uint16_t pkts_n) \ 77256fb0e3SMichael Baum { \ 78256fb0e3SMichael Baum return mlx5_tx_burst_tmpl((struct mlx5_txq_data *)txq, \ 79256fb0e3SMichael Baum pkts, pkts_n, (olx)); \ 80256fb0e3SMichael Baum } 81256fb0e3SMichael Baum 82377b69fbSMichael Baum /* Mbuf dynamic flag offset for inline. */ 83377b69fbSMichael Baum extern uint64_t rte_net_mlx5_dynf_inline_mask; 84daa02b5cSOlivier Matz #define RTE_MBUF_F_TX_DYNF_NOINLINE rte_net_mlx5_dynf_inline_mask 85256fb0e3SMichael Baum 8627595cd8STyler Retzlaff extern alignas(RTE_CACHE_LINE_SIZE) uint32_t mlx5_ptype_table[]; 8727595cd8STyler Retzlaff extern alignas(RTE_CACHE_LINE_SIZE) uint8_t mlx5_cksum_table[1 << 10]; 8827595cd8STyler Retzlaff extern alignas(RTE_CACHE_LINE_SIZE) uint8_t mlx5_swp_types_table[1 << 10]; 89377b69fbSMichael Baum 90377b69fbSMichael Baum struct mlx5_txq_stats { 91377b69fbSMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 92377b69fbSMichael Baum uint64_t opackets; /**< Total of successfully sent packets. */ 93377b69fbSMichael Baum uint64_t obytes; /**< Total of successfully sent bytes. */ 94377b69fbSMichael Baum #endif 95377b69fbSMichael Baum uint64_t oerrors; /**< Total number of failed transmitted packets. */ 96377b69fbSMichael Baum }; 97377b69fbSMichael Baum 98377b69fbSMichael Baum /* TX queue send local data. */ 99377b69fbSMichael Baum __extension__ 100377b69fbSMichael Baum struct mlx5_txq_local { 101377b69fbSMichael Baum struct mlx5_wqe *wqe_last; /* last sent WQE pointer. */ 102377b69fbSMichael Baum struct rte_mbuf *mbuf; /* first mbuf to process. */ 103377b69fbSMichael Baum uint16_t pkts_copy; /* packets copied to elts. */ 104377b69fbSMichael Baum uint16_t pkts_sent; /* packets sent. */ 105377b69fbSMichael Baum uint16_t pkts_loop; /* packets sent on loop entry. */ 106377b69fbSMichael Baum uint16_t elts_free; /* available elts remain. */ 107377b69fbSMichael Baum uint16_t wqe_free; /* available wqe remain. */ 108377b69fbSMichael Baum uint16_t mbuf_off; /* data offset in current mbuf. */ 109377b69fbSMichael Baum uint16_t mbuf_nseg; /* number of remaining mbuf. */ 110377b69fbSMichael Baum uint16_t mbuf_free; /* number of inline mbufs to free. */ 111377b69fbSMichael Baum }; 112377b69fbSMichael Baum 113377b69fbSMichael Baum /* TX queue descriptor. */ 114377b69fbSMichael Baum __extension__ 11527595cd8STyler Retzlaff struct __rte_cache_aligned mlx5_txq_data { 116377b69fbSMichael Baum uint16_t elts_head; /* Current counter in (*elts)[]. */ 117377b69fbSMichael Baum uint16_t elts_tail; /* Counter of first element awaiting completion. */ 118377b69fbSMichael Baum uint16_t elts_comp; /* elts index since last completion request. */ 119377b69fbSMichael Baum uint16_t elts_s; /* Number of mbuf elements. */ 120377b69fbSMichael Baum uint16_t elts_m; /* Mask for mbuf elements indices. */ 121377b69fbSMichael Baum /* Fields related to elts mbuf storage. */ 122377b69fbSMichael Baum uint16_t wqe_ci; /* Consumer index for work queue. */ 123377b69fbSMichael Baum uint16_t wqe_pi; /* Producer index for work queue. */ 124377b69fbSMichael Baum uint16_t wqe_s; /* Number of WQ elements. */ 125377b69fbSMichael Baum uint16_t wqe_m; /* Mask Number for WQ elements. */ 126377b69fbSMichael Baum uint16_t wqe_comp; /* WQE index since last completion request. */ 127377b69fbSMichael Baum uint16_t wqe_thres; /* WQE threshold to request completion in CQ. */ 128377b69fbSMichael Baum /* WQ related fields. */ 129377b69fbSMichael Baum uint16_t cq_ci; /* Consumer index for completion queue. */ 130377b69fbSMichael Baum uint16_t cq_pi; /* Production index for completion queue. */ 131377b69fbSMichael Baum uint16_t cqe_s; /* Number of CQ elements. */ 132377b69fbSMichael Baum uint16_t cqe_m; /* Mask for CQ indices. */ 133377b69fbSMichael Baum /* CQ related fields. */ 134377b69fbSMichael Baum uint16_t elts_n:4; /* elts[] length (in log2). */ 135377b69fbSMichael Baum uint16_t cqe_n:4; /* Number of CQ elements (in log2). */ 136377b69fbSMichael Baum uint16_t wqe_n:4; /* Number of WQ elements (in log2). */ 137377b69fbSMichael Baum uint16_t tso_en:1; /* When set hardware TSO is enabled. */ 138377b69fbSMichael Baum uint16_t tunnel_en:1; 139377b69fbSMichael Baum /* When set TX offload for tunneled packets are supported. */ 140377b69fbSMichael Baum uint16_t swp_en:1; /* Whether SW parser is enabled. */ 141377b69fbSMichael Baum uint16_t vlan_en:1; /* VLAN insertion in WQE is supported. */ 142377b69fbSMichael Baum uint16_t db_nc:1; /* Doorbell mapped to non-cached region. */ 143377b69fbSMichael Baum uint16_t db_heu:1; /* Doorbell heuristic write barrier. */ 1442f5122dfSViacheslav Ovsiienko uint16_t rt_timestamp:1; /* Realtime timestamp format. */ 1452f5122dfSViacheslav Ovsiienko uint16_t wait_on_time:1; /* WQE with timestamp is supported. */ 146377b69fbSMichael Baum uint16_t fast_free:1; /* mbuf fast free on Tx is enabled. */ 147377b69fbSMichael Baum uint16_t inlen_send; /* Ordinary send data inline size. */ 148377b69fbSMichael Baum uint16_t inlen_empw; /* eMPW max packet size to inline. */ 149377b69fbSMichael Baum uint16_t inlen_mode; /* Minimal data length to inline. */ 150ce306af6SJiawei Wang uint8_t tx_aggr_affinity; /* TxQ affinity configuration. */ 151377b69fbSMichael Baum uint32_t qp_num_8s; /* QP number shifted by 8. */ 152377b69fbSMichael Baum uint64_t offloads; /* Offloads for Tx Queue. */ 153377b69fbSMichael Baum struct mlx5_mr_ctrl mr_ctrl; /* MR control descriptor. */ 154377b69fbSMichael Baum struct mlx5_wqe *wqes; /* Work queue. */ 155377b69fbSMichael Baum struct mlx5_wqe *wqes_end; /* Work queue array limit. */ 156377b69fbSMichael Baum #ifdef RTE_LIBRTE_MLX5_DEBUG 157377b69fbSMichael Baum uint32_t *fcqs; /* Free completion queue (debug extended). */ 158377b69fbSMichael Baum #else 159377b69fbSMichael Baum uint16_t *fcqs; /* Free completion queue. */ 160377b69fbSMichael Baum #endif 161377b69fbSMichael Baum volatile struct mlx5_cqe *cqes; /* Completion queue. */ 162377b69fbSMichael Baum volatile uint32_t *qp_db; /* Work queue doorbell. */ 163377b69fbSMichael Baum volatile uint32_t *cq_db; /* Completion queue doorbell. */ 164377b69fbSMichael Baum uint16_t port_id; /* Port ID of device. */ 165377b69fbSMichael Baum uint16_t idx; /* Queue index. */ 1662f5122dfSViacheslav Ovsiienko uint64_t rt_timemask; /* Scheduling timestamp mask. */ 167377b69fbSMichael Baum uint64_t ts_mask; /* Timestamp flag dynamic mask. */ 168a31aa37bSViacheslav Ovsiienko uint64_t ts_last; /* Last scheduled timestamp. */ 169377b69fbSMichael Baum int32_t ts_offset; /* Timestamp field dynamic offset. */ 170377b69fbSMichael Baum struct mlx5_dev_ctx_shared *sh; /* Shared context. */ 171377b69fbSMichael Baum struct mlx5_txq_stats stats; /* TX queue counters. */ 172773a7de2SRaja Zidane struct mlx5_txq_stats stats_reset; /* stats on last reset. */ 1735dfa003dSMichael Baum struct mlx5_uar_data uar_data; 1740fc536d5SStephen Hemminger struct rte_mbuf *elts[]; 175377b69fbSMichael Baum /* Storage for queued packets, must be the last field. */ 17627595cd8STyler Retzlaff }; 177377b69fbSMichael Baum 178377b69fbSMichael Baum /* TX queue control descriptor. */ 1790fc536d5SStephen Hemminger __extension__ 180377b69fbSMichael Baum struct mlx5_txq_ctrl { 181377b69fbSMichael Baum LIST_ENTRY(mlx5_txq_ctrl) next; /* Pointer to the next element. */ 182e12a0166STyler Retzlaff RTE_ATOMIC(uint32_t) refcnt; /* Reference counter. */ 183377b69fbSMichael Baum unsigned int socket; /* CPU socket ID for allocations. */ 184c06f77aeSMichael Baum bool is_hairpin; /* Whether TxQ type is Hairpin. */ 185377b69fbSMichael Baum unsigned int max_inline_data; /* Max inline data. */ 186377b69fbSMichael Baum unsigned int max_tso_header; /* Max TSO header size. */ 187377b69fbSMichael Baum struct mlx5_txq_obj *obj; /* Verbs/DevX queue object. */ 188377b69fbSMichael Baum struct mlx5_priv *priv; /* Back pointer to private data. */ 189377b69fbSMichael Baum off_t uar_mmap_offset; /* UAR mmap offset for non-primary process. */ 190377b69fbSMichael Baum uint16_t dump_file_n; /* Number of dump files. */ 191377b69fbSMichael Baum struct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */ 192377b69fbSMichael Baum uint32_t hairpin_status; /* Hairpin binding status. */ 193377b69fbSMichael Baum struct mlx5_txq_data txq; /* Data path structure. */ 194377b69fbSMichael Baum /* Must be the last field in the structure, contains elts[]. */ 195377b69fbSMichael Baum }; 196377b69fbSMichael Baum 197377b69fbSMichael Baum /* mlx5_txq.c */ 198377b69fbSMichael Baum 199377b69fbSMichael Baum int mlx5_tx_queue_start(struct rte_eth_dev *dev, uint16_t queue_id); 200377b69fbSMichael Baum int mlx5_tx_queue_stop(struct rte_eth_dev *dev, uint16_t queue_id); 201377b69fbSMichael Baum int mlx5_tx_queue_start_primary(struct rte_eth_dev *dev, uint16_t queue_id); 202377b69fbSMichael Baum int mlx5_tx_queue_stop_primary(struct rte_eth_dev *dev, uint16_t queue_id); 203377b69fbSMichael Baum int mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, 204377b69fbSMichael Baum unsigned int socket, const struct rte_eth_txconf *conf); 205377b69fbSMichael Baum int mlx5_tx_hairpin_queue_setup 206377b69fbSMichael Baum (struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, 207377b69fbSMichael Baum const struct rte_eth_hairpin_conf *hairpin_conf); 2087483341aSXueming Li void mlx5_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid); 209377b69fbSMichael Baum int mlx5_tx_uar_init_secondary(struct rte_eth_dev *dev, int fd); 210377b69fbSMichael Baum void mlx5_tx_uar_uninit_secondary(struct rte_eth_dev *dev); 211377b69fbSMichael Baum int mlx5_txq_obj_verify(struct rte_eth_dev *dev); 212377b69fbSMichael Baum struct mlx5_txq_ctrl *mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, 213377b69fbSMichael Baum uint16_t desc, unsigned int socket, 214377b69fbSMichael Baum const struct rte_eth_txconf *conf); 215377b69fbSMichael Baum struct mlx5_txq_ctrl *mlx5_txq_hairpin_new 216377b69fbSMichael Baum (struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, 217377b69fbSMichael Baum const struct rte_eth_hairpin_conf *hairpin_conf); 218377b69fbSMichael Baum struct mlx5_txq_ctrl *mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx); 219377b69fbSMichael Baum int mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx); 220377b69fbSMichael Baum int mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx); 221377b69fbSMichael Baum int mlx5_txq_verify(struct rte_eth_dev *dev); 22226e1eaf2SDariusz Sosnowski int mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq); 223377b69fbSMichael Baum void txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl); 224377b69fbSMichael Baum void txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl); 225377b69fbSMichael Baum uint64_t mlx5_get_tx_port_offloads(struct rte_eth_dev *dev); 226377b69fbSMichael Baum void mlx5_txq_dynf_timestamp_set(struct rte_eth_dev *dev); 227ce306af6SJiawei Wang int mlx5_count_aggr_ports(struct rte_eth_dev *dev); 228ce306af6SJiawei Wang int mlx5_map_aggr_tx_affinity(struct rte_eth_dev *dev, uint16_t tx_queue_id, 229ce306af6SJiawei Wang uint8_t affinity); 2301944fbc3SSuanming Mou int mlx5_ext_txq_verify(struct rte_eth_dev *dev); 2311944fbc3SSuanming Mou struct mlx5_external_q *mlx5_ext_txq_get(struct rte_eth_dev *dev, uint16_t idx); 232377b69fbSMichael Baum 233377b69fbSMichael Baum /* mlx5_tx.c */ 234377b69fbSMichael Baum 235256fb0e3SMichael Baum void mlx5_tx_handle_completion(struct mlx5_txq_data *__rte_restrict txq, 236256fb0e3SMichael Baum unsigned int olx __rte_unused); 237377b69fbSMichael Baum int mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset); 238377b69fbSMichael Baum void mlx5_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, 239377b69fbSMichael Baum struct rte_eth_txq_info *qinfo); 240377b69fbSMichael Baum int mlx5_tx_burst_mode_get(struct rte_eth_dev *dev, uint16_t tx_queue_id, 241377b69fbSMichael Baum struct rte_eth_burst_mode *mode); 242377b69fbSMichael Baum 2434ac9ad07SMichael Baum /* mlx5_tx_empw.c */ 24479a876e3SMichael Baum 24579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full_empw); 24679a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(none_empw); 24779a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(md_empw); 24879a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mt_empw); 24979a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtsc_empw); 25079a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mti_empw); 25179a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtv_empw); 25279a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtiv_empw); 25379a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sc_empw); 25479a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sci_empw); 25579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(scv_empw); 25679a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sciv_empw); 25779a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(i_empw); 25879a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(v_empw); 25979a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(iv_empw); 26079a876e3SMichael Baum 2614ac9ad07SMichael Baum /* mlx5_tx_nompw.c */ 2624ac9ad07SMichael Baum 26379a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full); 26479a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(none); 26579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(md); 26679a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mt); 26779a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtsc); 26879a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mti); 26979a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtv); 27079a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtiv); 27179a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sc); 27279a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sci); 27379a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(scv); 27479a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(sciv); 27579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(i); 27679a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(v); 27779a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(iv); 27879a876e3SMichael Baum 2794ac9ad07SMichael Baum /* mlx5_tx_txpp.c */ 2804ac9ad07SMichael Baum 28179a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full_ts_nompw); 28279a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full_ts_nompwi); 28379a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full_ts); 28479a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(full_ts_noi); 28579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(none_ts); 28679a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mdi_ts); 28779a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mti_ts); 28879a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mtiv_ts); 28979a876e3SMichael Baum 2904ac9ad07SMichael Baum /* mlx5_tx_mpw.c */ 2914ac9ad07SMichael Baum 29279a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(none_mpw); 29379a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mci_mpw); 29479a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(mc_mpw); 29579a876e3SMichael Baum MLX5_TXOFF_PRE_DECL(i_mpw); 29679a876e3SMichael Baum 2975dfa003dSMichael Baum static __rte_always_inline struct mlx5_uar_data * 298377b69fbSMichael Baum mlx5_tx_bfreg(struct mlx5_txq_data *txq) 299377b69fbSMichael Baum { 3005dfa003dSMichael Baum return &MLX5_PROC_PRIV(txq->port_id)->uar_table[txq->idx]; 301377b69fbSMichael Baum } 302377b69fbSMichael Baum 303377b69fbSMichael Baum /** 304377b69fbSMichael Baum * Ring TX queue doorbell and flush the update by write memory barrier. 305377b69fbSMichael Baum * 306377b69fbSMichael Baum * @param txq 307377b69fbSMichael Baum * Pointer to TX queue structure. 308377b69fbSMichael Baum * @param wqe 309377b69fbSMichael Baum * Pointer to the last WQE posted in the NIC. 310377b69fbSMichael Baum */ 311377b69fbSMichael Baum static __rte_always_inline void 312377b69fbSMichael Baum mlx5_tx_dbrec(struct mlx5_txq_data *txq, volatile struct mlx5_wqe *wqe) 313377b69fbSMichael Baum { 3145dfa003dSMichael Baum mlx5_doorbell_ring(mlx5_tx_bfreg(txq), *(volatile uint64_t *)wqe, 3155dfa003dSMichael Baum txq->wqe_ci, txq->qp_db, 1); 316377b69fbSMichael Baum } 317377b69fbSMichael Baum 318377b69fbSMichael Baum /** 319377b69fbSMichael Baum * Convert timestamp from mbuf format to linear counter 320377b69fbSMichael Baum * of Clock Queue completions (24 bits). 321377b69fbSMichael Baum * 322377b69fbSMichael Baum * @param sh 323377b69fbSMichael Baum * Pointer to the device shared context to fetch Tx 324377b69fbSMichael Baum * packet pacing timestamp and parameters. 325377b69fbSMichael Baum * @param ts 326377b69fbSMichael Baum * Timestamp from mbuf to convert. 327377b69fbSMichael Baum * @return 328377b69fbSMichael Baum * positive or zero value - completion ID to wait. 329377b69fbSMichael Baum * negative value - conversion error. 330377b69fbSMichael Baum */ 331377b69fbSMichael Baum static __rte_always_inline int32_t 332377b69fbSMichael Baum mlx5_txpp_convert_tx_ts(struct mlx5_dev_ctx_shared *sh, uint64_t mts) 333377b69fbSMichael Baum { 334377b69fbSMichael Baum uint64_t ts, ci; 335377b69fbSMichael Baum uint32_t tick; 336377b69fbSMichael Baum 337377b69fbSMichael Baum do { 338377b69fbSMichael Baum /* 339377b69fbSMichael Baum * Read atomically two uint64_t fields and compare lsb bits. 340377b69fbSMichael Baum * It there is no match - the timestamp was updated in 341377b69fbSMichael Baum * the service thread, data should be re-read. 342377b69fbSMichael Baum */ 343377b69fbSMichael Baum rte_compiler_barrier(); 344e12a0166STyler Retzlaff ci = rte_atomic_load_explicit(&sh->txpp.ts.ci_ts, rte_memory_order_relaxed); 345e12a0166STyler Retzlaff ts = rte_atomic_load_explicit(&sh->txpp.ts.ts, rte_memory_order_relaxed); 346377b69fbSMichael Baum rte_compiler_barrier(); 347377b69fbSMichael Baum if (!((ts ^ ci) << (64 - MLX5_CQ_INDEX_WIDTH))) 348377b69fbSMichael Baum break; 349377b69fbSMichael Baum } while (true); 350377b69fbSMichael Baum /* Perform the skew correction, positive value to send earlier. */ 351377b69fbSMichael Baum mts -= sh->txpp.skew; 352377b69fbSMichael Baum mts -= ts; 353377b69fbSMichael Baum if (unlikely(mts >= UINT64_MAX / 2)) { 354377b69fbSMichael Baum /* We have negative integer, mts is in the past. */ 355e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&sh->txpp.err_ts_past, 356e12a0166STyler Retzlaff 1, rte_memory_order_relaxed); 357377b69fbSMichael Baum return -1; 358377b69fbSMichael Baum } 359377b69fbSMichael Baum tick = sh->txpp.tick; 360377b69fbSMichael Baum MLX5_ASSERT(tick); 361377b69fbSMichael Baum /* Convert delta to completions, round up. */ 362377b69fbSMichael Baum mts = (mts + tick - 1) / tick; 363377b69fbSMichael Baum if (unlikely(mts >= (1 << MLX5_CQ_INDEX_WIDTH) / 2 - 1)) { 364377b69fbSMichael Baum /* We have mts is too distant future. */ 365e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&sh->txpp.err_ts_future, 366e12a0166STyler Retzlaff 1, rte_memory_order_relaxed); 367377b69fbSMichael Baum return -1; 368377b69fbSMichael Baum } 369377b69fbSMichael Baum mts <<= 64 - MLX5_CQ_INDEX_WIDTH; 370377b69fbSMichael Baum ci += mts; 371377b69fbSMichael Baum ci >>= 64 - MLX5_CQ_INDEX_WIDTH; 372377b69fbSMichael Baum return ci; 373377b69fbSMichael Baum } 374377b69fbSMichael Baum 375256fb0e3SMichael Baum /** 37627918f0dSTim Martin * Read real time clock counter directly from the device PCI BAR area. 37727918f0dSTim Martin * The PCI BAR must be mapped to the process memory space at initialization. 37827918f0dSTim Martin * 37927918f0dSTim Martin * @param dev 38027918f0dSTim Martin * Device to read clock counter from 38127918f0dSTim Martin * 38227918f0dSTim Martin * @return 38327918f0dSTim Martin * 0 - if HCA BAR is not supported or not mapped. 38427918f0dSTim Martin * !=0 - read 64-bit value of real-time in UTC formatv (nanoseconds) 38527918f0dSTim Martin */ 38627918f0dSTim Martin static __rte_always_inline uint64_t mlx5_read_pcibar_clock(struct rte_eth_dev *dev) 38727918f0dSTim Martin { 38827918f0dSTim Martin struct mlx5_proc_priv *ppriv = dev->process_private; 38927918f0dSTim Martin 39027918f0dSTim Martin if (ppriv && ppriv->hca_bar) { 39127918f0dSTim Martin struct mlx5_priv *priv = dev->data->dev_private; 39227918f0dSTim Martin struct mlx5_dev_ctx_shared *sh = priv->sh; 39327918f0dSTim Martin uint64_t *hca_ptr = (uint64_t *)(ppriv->hca_bar) + 39427918f0dSTim Martin __mlx5_64_off(initial_seg, real_time); 39527918f0dSTim Martin uint64_t __rte_atomic *ts_addr; 39627918f0dSTim Martin uint64_t ts; 39727918f0dSTim Martin 39827918f0dSTim Martin ts_addr = (uint64_t __rte_atomic *)hca_ptr; 39927918f0dSTim Martin ts = rte_atomic_load_explicit(ts_addr, rte_memory_order_seq_cst); 40027918f0dSTim Martin ts = rte_be_to_cpu_64(ts); 40127918f0dSTim Martin ts = mlx5_txpp_convert_rx_ts(sh, ts); 40227918f0dSTim Martin return ts; 40327918f0dSTim Martin } 40427918f0dSTim Martin return 0; 40527918f0dSTim Martin } 40627918f0dSTim Martin 407*02932480STim Martin static __rte_always_inline uint64_t mlx5_read_pcibar_clock_from_txq(struct mlx5_txq_data *txq) 408*02932480STim Martin { 409*02932480STim Martin struct mlx5_txq_ctrl *txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq); 410*02932480STim Martin struct rte_eth_dev *dev = ETH_DEV(txq_ctrl->priv); 411*02932480STim Martin 412*02932480STim Martin return mlx5_read_pcibar_clock(dev); 413*02932480STim Martin } 414*02932480STim Martin 41527918f0dSTim Martin /** 416256fb0e3SMichael Baum * Set Software Parser flags and offsets in Ethernet Segment of WQE. 417256fb0e3SMichael Baum * Flags must be preliminary initialized to zero. 418256fb0e3SMichael Baum * 419256fb0e3SMichael Baum * @param loc 420256fb0e3SMichael Baum * Pointer to burst routine local context. 421256fb0e3SMichael Baum * @param swp_flags 422256fb0e3SMichael Baum * Pointer to store Software Parser flags. 423256fb0e3SMichael Baum * @param olx 424256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 425256fb0e3SMichael Baum * compile time and may be used for optimization. 426256fb0e3SMichael Baum * 427256fb0e3SMichael Baum * @return 428256fb0e3SMichael Baum * Software Parser offsets packed in dword. 429256fb0e3SMichael Baum * Software Parser flags are set by pointer. 430256fb0e3SMichael Baum */ 431256fb0e3SMichael Baum static __rte_always_inline uint32_t 432256fb0e3SMichael Baum txq_mbuf_to_swp(struct mlx5_txq_local *__rte_restrict loc, 433256fb0e3SMichael Baum uint8_t *swp_flags, 434256fb0e3SMichael Baum unsigned int olx) 435256fb0e3SMichael Baum { 436256fb0e3SMichael Baum uint64_t ol, tunnel; 437256fb0e3SMichael Baum unsigned int idx, off; 438256fb0e3SMichael Baum uint32_t set; 439256fb0e3SMichael Baum 440256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(SWP)) 441256fb0e3SMichael Baum return 0; 442256fb0e3SMichael Baum ol = loc->mbuf->ol_flags; 443daa02b5cSOlivier Matz tunnel = ol & RTE_MBUF_F_TX_TUNNEL_MASK; 444256fb0e3SMichael Baum /* 445256fb0e3SMichael Baum * Check whether Software Parser is required. 446256fb0e3SMichael Baum * Only customized tunnels may ask for. 447256fb0e3SMichael Baum */ 448daa02b5cSOlivier Matz if (likely(tunnel != RTE_MBUF_F_TX_TUNNEL_UDP && tunnel != RTE_MBUF_F_TX_TUNNEL_IP)) 449256fb0e3SMichael Baum return 0; 450256fb0e3SMichael Baum /* 451256fb0e3SMichael Baum * The index should have: 452daa02b5cSOlivier Matz * bit[0:1] = RTE_MBUF_F_TX_L4_MASK 453daa02b5cSOlivier Matz * bit[4] = RTE_MBUF_F_TX_IPV6 454daa02b5cSOlivier Matz * bit[8] = RTE_MBUF_F_TX_OUTER_IPV6 455daa02b5cSOlivier Matz * bit[9] = RTE_MBUF_F_TX_OUTER_UDP 456256fb0e3SMichael Baum */ 457daa02b5cSOlivier Matz idx = (ol & (RTE_MBUF_F_TX_L4_MASK | RTE_MBUF_F_TX_IPV6 | RTE_MBUF_F_TX_OUTER_IPV6)) >> 52; 458daa02b5cSOlivier Matz idx |= (tunnel == RTE_MBUF_F_TX_TUNNEL_UDP) ? (1 << 9) : 0; 459256fb0e3SMichael Baum *swp_flags = mlx5_swp_types_table[idx]; 460256fb0e3SMichael Baum /* 461256fb0e3SMichael Baum * Set offsets for SW parser. Since ConnectX-5, SW parser just 462256fb0e3SMichael Baum * complements HW parser. SW parser starts to engage only if HW parser 463256fb0e3SMichael Baum * can't reach a header. For the older devices, HW parser will not kick 464256fb0e3SMichael Baum * in if any of SWP offsets is set. Therefore, all of the L3 offsets 465256fb0e3SMichael Baum * should be set regardless of HW offload. 466256fb0e3SMichael Baum */ 467256fb0e3SMichael Baum off = loc->mbuf->outer_l2_len; 468daa02b5cSOlivier Matz if (MLX5_TXOFF_CONFIG(VLAN) && ol & RTE_MBUF_F_TX_VLAN) 469256fb0e3SMichael Baum off += sizeof(struct rte_vlan_hdr); 470256fb0e3SMichael Baum set = (off >> 1) << 8; /* Outer L3 offset. */ 471256fb0e3SMichael Baum off += loc->mbuf->outer_l3_len; 472daa02b5cSOlivier Matz if (tunnel == RTE_MBUF_F_TX_TUNNEL_UDP) 473256fb0e3SMichael Baum set |= off >> 1; /* Outer L4 offset. */ 474daa02b5cSOlivier Matz if (ol & (RTE_MBUF_F_TX_IPV4 | RTE_MBUF_F_TX_IPV6)) { /* Inner IP. */ 475daa02b5cSOlivier Matz const uint64_t csum = ol & RTE_MBUF_F_TX_L4_MASK; 476256fb0e3SMichael Baum off += loc->mbuf->l2_len; 477256fb0e3SMichael Baum set |= (off >> 1) << 24; /* Inner L3 offset. */ 478daa02b5cSOlivier Matz if (csum == RTE_MBUF_F_TX_TCP_CKSUM || 479daa02b5cSOlivier Matz csum == RTE_MBUF_F_TX_UDP_CKSUM || 480daa02b5cSOlivier Matz (MLX5_TXOFF_CONFIG(TSO) && ol & RTE_MBUF_F_TX_TCP_SEG)) { 481256fb0e3SMichael Baum off += loc->mbuf->l3_len; 482256fb0e3SMichael Baum set |= (off >> 1) << 16; /* Inner L4 offset. */ 483256fb0e3SMichael Baum } 484256fb0e3SMichael Baum } 485256fb0e3SMichael Baum set = rte_cpu_to_le_32(set); 486256fb0e3SMichael Baum return set; 487256fb0e3SMichael Baum } 488256fb0e3SMichael Baum 489256fb0e3SMichael Baum /** 490256fb0e3SMichael Baum * Convert the Checksum offloads to Verbs. 491256fb0e3SMichael Baum * 492256fb0e3SMichael Baum * @param buf 493256fb0e3SMichael Baum * Pointer to the mbuf. 494256fb0e3SMichael Baum * 495256fb0e3SMichael Baum * @return 496256fb0e3SMichael Baum * Converted checksum flags. 497256fb0e3SMichael Baum */ 498256fb0e3SMichael Baum static __rte_always_inline uint8_t 499256fb0e3SMichael Baum txq_ol_cksum_to_cs(struct rte_mbuf *buf) 500256fb0e3SMichael Baum { 501256fb0e3SMichael Baum uint32_t idx; 502daa02b5cSOlivier Matz uint8_t is_tunnel = !!(buf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK); 503daa02b5cSOlivier Matz const uint64_t ol_flags_mask = RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_L4_MASK | 504daa02b5cSOlivier Matz RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_OUTER_IP_CKSUM; 505256fb0e3SMichael Baum 506256fb0e3SMichael Baum /* 507256fb0e3SMichael Baum * The index should have: 508daa02b5cSOlivier Matz * bit[0] = RTE_MBUF_F_TX_TCP_SEG 509daa02b5cSOlivier Matz * bit[2:3] = RTE_MBUF_F_TX_UDP_CKSUM, RTE_MBUF_F_TX_TCP_CKSUM 510daa02b5cSOlivier Matz * bit[4] = RTE_MBUF_F_TX_IP_CKSUM 511daa02b5cSOlivier Matz * bit[8] = RTE_MBUF_F_TX_OUTER_IP_CKSUM 512256fb0e3SMichael Baum * bit[9] = tunnel 513256fb0e3SMichael Baum */ 514256fb0e3SMichael Baum idx = ((buf->ol_flags & ol_flags_mask) >> 50) | (!!is_tunnel << 9); 515256fb0e3SMichael Baum return mlx5_cksum_table[idx]; 516256fb0e3SMichael Baum } 517256fb0e3SMichael Baum 518256fb0e3SMichael Baum /** 519256fb0e3SMichael Baum * Free the mbufs from the linear array of pointers. 520256fb0e3SMichael Baum * 521256fb0e3SMichael Baum * @param txq 522256fb0e3SMichael Baum * Pointer to Tx queue structure. 523256fb0e3SMichael Baum * @param pkts 524256fb0e3SMichael Baum * Pointer to array of packets to be free. 525256fb0e3SMichael Baum * @param pkts_n 526256fb0e3SMichael Baum * Number of packets to be freed. 527256fb0e3SMichael Baum * @param olx 528256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 529256fb0e3SMichael Baum * compile time and may be used for optimization. 530256fb0e3SMichael Baum */ 531256fb0e3SMichael Baum static __rte_always_inline void 532256fb0e3SMichael Baum mlx5_tx_free_mbuf(struct mlx5_txq_data *__rte_restrict txq, 533256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 534256fb0e3SMichael Baum unsigned int pkts_n, 535256fb0e3SMichael Baum unsigned int olx __rte_unused) 536256fb0e3SMichael Baum { 537256fb0e3SMichael Baum struct rte_mempool *pool = NULL; 538256fb0e3SMichael Baum struct rte_mbuf **p_free = NULL; 539256fb0e3SMichael Baum struct rte_mbuf *mbuf; 540256fb0e3SMichael Baum unsigned int n_free = 0; 541256fb0e3SMichael Baum 542256fb0e3SMichael Baum /* 543256fb0e3SMichael Baum * The implemented algorithm eliminates 544256fb0e3SMichael Baum * copying pointers to temporary array 545256fb0e3SMichael Baum * for rte_mempool_put_bulk() calls. 546256fb0e3SMichael Baum */ 547256fb0e3SMichael Baum MLX5_ASSERT(pkts); 548256fb0e3SMichael Baum MLX5_ASSERT(pkts_n); 549256fb0e3SMichael Baum /* 550256fb0e3SMichael Baum * Free mbufs directly to the pool in bulk 551256fb0e3SMichael Baum * if fast free offload is engaged 552256fb0e3SMichael Baum */ 553256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MULTI) && txq->fast_free) { 554256fb0e3SMichael Baum mbuf = *pkts; 555256fb0e3SMichael Baum pool = mbuf->pool; 556256fb0e3SMichael Baum rte_mempool_put_bulk(pool, (void *)pkts, pkts_n); 557256fb0e3SMichael Baum return; 558256fb0e3SMichael Baum } 559256fb0e3SMichael Baum for (;;) { 560256fb0e3SMichael Baum for (;;) { 561256fb0e3SMichael Baum /* 562256fb0e3SMichael Baum * Decrement mbuf reference counter, detach 563256fb0e3SMichael Baum * indirect and external buffers if needed. 564256fb0e3SMichael Baum */ 565256fb0e3SMichael Baum mbuf = rte_pktmbuf_prefree_seg(*pkts); 566256fb0e3SMichael Baum if (likely(mbuf != NULL)) { 567256fb0e3SMichael Baum MLX5_ASSERT(mbuf == *pkts); 568256fb0e3SMichael Baum if (likely(n_free != 0)) { 569256fb0e3SMichael Baum if (unlikely(pool != mbuf->pool)) 570256fb0e3SMichael Baum /* From different pool. */ 571256fb0e3SMichael Baum break; 572256fb0e3SMichael Baum } else { 573256fb0e3SMichael Baum /* Start new scan array. */ 574256fb0e3SMichael Baum pool = mbuf->pool; 575256fb0e3SMichael Baum p_free = pkts; 576256fb0e3SMichael Baum } 577256fb0e3SMichael Baum ++n_free; 578256fb0e3SMichael Baum ++pkts; 579256fb0e3SMichael Baum --pkts_n; 580256fb0e3SMichael Baum if (unlikely(pkts_n == 0)) { 581256fb0e3SMichael Baum mbuf = NULL; 582256fb0e3SMichael Baum break; 583256fb0e3SMichael Baum } 584256fb0e3SMichael Baum } else { 585256fb0e3SMichael Baum /* 586256fb0e3SMichael Baum * This happens if mbuf is still referenced. 587256fb0e3SMichael Baum * We can't put it back to the pool, skip. 588256fb0e3SMichael Baum */ 589256fb0e3SMichael Baum ++pkts; 590256fb0e3SMichael Baum --pkts_n; 591256fb0e3SMichael Baum if (unlikely(n_free != 0)) 592256fb0e3SMichael Baum /* There is some array to free.*/ 593256fb0e3SMichael Baum break; 594256fb0e3SMichael Baum if (unlikely(pkts_n == 0)) 595256fb0e3SMichael Baum /* Last mbuf, nothing to free. */ 596256fb0e3SMichael Baum return; 597256fb0e3SMichael Baum } 598256fb0e3SMichael Baum } 599256fb0e3SMichael Baum for (;;) { 600256fb0e3SMichael Baum /* 601256fb0e3SMichael Baum * This loop is implemented to avoid multiple 602256fb0e3SMichael Baum * inlining of rte_mempool_put_bulk(). 603256fb0e3SMichael Baum */ 604256fb0e3SMichael Baum MLX5_ASSERT(pool); 605256fb0e3SMichael Baum MLX5_ASSERT(p_free); 606256fb0e3SMichael Baum MLX5_ASSERT(n_free); 607256fb0e3SMichael Baum /* 608256fb0e3SMichael Baum * Free the array of pre-freed mbufs 609256fb0e3SMichael Baum * belonging to the same memory pool. 610256fb0e3SMichael Baum */ 611256fb0e3SMichael Baum rte_mempool_put_bulk(pool, (void *)p_free, n_free); 612256fb0e3SMichael Baum if (unlikely(mbuf != NULL)) { 613256fb0e3SMichael Baum /* There is the request to start new scan. */ 614256fb0e3SMichael Baum pool = mbuf->pool; 615256fb0e3SMichael Baum p_free = pkts++; 616256fb0e3SMichael Baum n_free = 1; 617256fb0e3SMichael Baum --pkts_n; 618256fb0e3SMichael Baum if (likely(pkts_n != 0)) 619256fb0e3SMichael Baum break; 620256fb0e3SMichael Baum /* 621256fb0e3SMichael Baum * This is the last mbuf to be freed. 622256fb0e3SMichael Baum * Do one more loop iteration to complete. 623256fb0e3SMichael Baum * This is rare case of the last unique mbuf. 624256fb0e3SMichael Baum */ 625256fb0e3SMichael Baum mbuf = NULL; 626256fb0e3SMichael Baum continue; 627256fb0e3SMichael Baum } 628256fb0e3SMichael Baum if (likely(pkts_n == 0)) 629256fb0e3SMichael Baum return; 630256fb0e3SMichael Baum n_free = 0; 631256fb0e3SMichael Baum break; 632256fb0e3SMichael Baum } 633256fb0e3SMichael Baum } 634256fb0e3SMichael Baum } 635256fb0e3SMichael Baum 636256fb0e3SMichael Baum /** 637256fb0e3SMichael Baum * No inline version to free buffers for optimal call 638256fb0e3SMichael Baum * on the tx_burst completion. 639256fb0e3SMichael Baum */ 640256fb0e3SMichael Baum static __rte_noinline void 641256fb0e3SMichael Baum __mlx5_tx_free_mbuf(struct mlx5_txq_data *__rte_restrict txq, 642256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 643256fb0e3SMichael Baum unsigned int pkts_n, 644256fb0e3SMichael Baum unsigned int olx __rte_unused) 645256fb0e3SMichael Baum { 646256fb0e3SMichael Baum mlx5_tx_free_mbuf(txq, pkts, pkts_n, olx); 647256fb0e3SMichael Baum } 648256fb0e3SMichael Baum 649256fb0e3SMichael Baum /** 650256fb0e3SMichael Baum * Free the mbuf from the elts ring buffer till new tail. 651256fb0e3SMichael Baum * 652256fb0e3SMichael Baum * @param txq 653256fb0e3SMichael Baum * Pointer to Tx queue structure. 654256fb0e3SMichael Baum * @param tail 655256fb0e3SMichael Baum * Index in elts to free up to, becomes new elts tail. 656256fb0e3SMichael Baum * @param olx 657256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 658256fb0e3SMichael Baum * compile time and may be used for optimization. 659256fb0e3SMichael Baum */ 660256fb0e3SMichael Baum static __rte_always_inline void 661256fb0e3SMichael Baum mlx5_tx_free_elts(struct mlx5_txq_data *__rte_restrict txq, 662256fb0e3SMichael Baum uint16_t tail, 663256fb0e3SMichael Baum unsigned int olx __rte_unused) 664256fb0e3SMichael Baum { 665256fb0e3SMichael Baum uint16_t n_elts = tail - txq->elts_tail; 666256fb0e3SMichael Baum 667256fb0e3SMichael Baum MLX5_ASSERT(n_elts); 668256fb0e3SMichael Baum MLX5_ASSERT(n_elts <= txq->elts_s); 669256fb0e3SMichael Baum /* 670256fb0e3SMichael Baum * Implement a loop to support ring buffer wraparound 671256fb0e3SMichael Baum * with single inlining of mlx5_tx_free_mbuf(). 672256fb0e3SMichael Baum */ 673256fb0e3SMichael Baum do { 674256fb0e3SMichael Baum unsigned int part; 675256fb0e3SMichael Baum 676256fb0e3SMichael Baum part = txq->elts_s - (txq->elts_tail & txq->elts_m); 677256fb0e3SMichael Baum part = RTE_MIN(part, n_elts); 678256fb0e3SMichael Baum MLX5_ASSERT(part); 679256fb0e3SMichael Baum MLX5_ASSERT(part <= txq->elts_s); 680256fb0e3SMichael Baum mlx5_tx_free_mbuf(txq, 681256fb0e3SMichael Baum &txq->elts[txq->elts_tail & txq->elts_m], 682256fb0e3SMichael Baum part, olx); 683256fb0e3SMichael Baum txq->elts_tail += part; 684256fb0e3SMichael Baum n_elts -= part; 685256fb0e3SMichael Baum } while (n_elts); 686256fb0e3SMichael Baum } 687256fb0e3SMichael Baum 688256fb0e3SMichael Baum /** 689256fb0e3SMichael Baum * Store the mbuf being sent into elts ring buffer. 690256fb0e3SMichael Baum * On Tx completion these mbufs will be freed. 691256fb0e3SMichael Baum * 692256fb0e3SMichael Baum * @param txq 693256fb0e3SMichael Baum * Pointer to Tx queue structure. 694256fb0e3SMichael Baum * @param pkts 695256fb0e3SMichael Baum * Pointer to array of packets to be stored. 696256fb0e3SMichael Baum * @param pkts_n 697256fb0e3SMichael Baum * Number of packets to be stored. 698256fb0e3SMichael Baum * @param olx 699256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 700256fb0e3SMichael Baum * compile time and may be used for optimization. 701256fb0e3SMichael Baum */ 702256fb0e3SMichael Baum static __rte_always_inline void 703256fb0e3SMichael Baum mlx5_tx_copy_elts(struct mlx5_txq_data *__rte_restrict txq, 704256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 705256fb0e3SMichael Baum unsigned int pkts_n, 706256fb0e3SMichael Baum unsigned int olx __rte_unused) 707256fb0e3SMichael Baum { 708256fb0e3SMichael Baum unsigned int part; 709256fb0e3SMichael Baum struct rte_mbuf **elts = (struct rte_mbuf **)txq->elts; 710256fb0e3SMichael Baum 711256fb0e3SMichael Baum MLX5_ASSERT(pkts); 712256fb0e3SMichael Baum MLX5_ASSERT(pkts_n); 713256fb0e3SMichael Baum part = txq->elts_s - (txq->elts_head & txq->elts_m); 714256fb0e3SMichael Baum MLX5_ASSERT(part); 715256fb0e3SMichael Baum MLX5_ASSERT(part <= txq->elts_s); 716256fb0e3SMichael Baum /* This code is a good candidate for vectorizing with SIMD. */ 717256fb0e3SMichael Baum rte_memcpy((void *)(elts + (txq->elts_head & txq->elts_m)), 718256fb0e3SMichael Baum (void *)pkts, 719256fb0e3SMichael Baum RTE_MIN(part, pkts_n) * sizeof(struct rte_mbuf *)); 720256fb0e3SMichael Baum txq->elts_head += pkts_n; 721256fb0e3SMichael Baum if (unlikely(part < pkts_n)) 722256fb0e3SMichael Baum /* The copy is wrapping around the elts array. */ 723256fb0e3SMichael Baum rte_memcpy((void *)elts, (void *)(pkts + part), 724256fb0e3SMichael Baum (pkts_n - part) * sizeof(struct rte_mbuf *)); 725256fb0e3SMichael Baum } 726256fb0e3SMichael Baum 727256fb0e3SMichael Baum /** 728256fb0e3SMichael Baum * Check if the completion request flag should be set in the last WQE. 729256fb0e3SMichael Baum * Both pushed mbufs and WQEs are monitored and the completion request 730256fb0e3SMichael Baum * flag is set if any of thresholds is reached. 731256fb0e3SMichael Baum * 732256fb0e3SMichael Baum * @param txq 733256fb0e3SMichael Baum * Pointer to TX queue structure. 734256fb0e3SMichael Baum * @param loc 735256fb0e3SMichael Baum * Pointer to burst routine local context. 736256fb0e3SMichael Baum * @param olx 737256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 738256fb0e3SMichael Baum * compile time and may be used for optimization. 739256fb0e3SMichael Baum */ 740256fb0e3SMichael Baum static __rte_always_inline void 741256fb0e3SMichael Baum mlx5_tx_request_completion(struct mlx5_txq_data *__rte_restrict txq, 742256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 743256fb0e3SMichael Baum unsigned int olx) 744256fb0e3SMichael Baum { 745256fb0e3SMichael Baum uint16_t head = txq->elts_head; 746256fb0e3SMichael Baum unsigned int part; 747256fb0e3SMichael Baum 748256fb0e3SMichael Baum part = MLX5_TXOFF_CONFIG(INLINE) ? 749256fb0e3SMichael Baum 0 : loc->pkts_sent - loc->pkts_copy; 750256fb0e3SMichael Baum head += part; 751256fb0e3SMichael Baum if ((uint16_t)(head - txq->elts_comp) >= MLX5_TX_COMP_THRESH || 752256fb0e3SMichael Baum (MLX5_TXOFF_CONFIG(INLINE) && 753256fb0e3SMichael Baum (uint16_t)(txq->wqe_ci - txq->wqe_comp) >= txq->wqe_thres)) { 754256fb0e3SMichael Baum volatile struct mlx5_wqe *last = loc->wqe_last; 755256fb0e3SMichael Baum 756256fb0e3SMichael Baum MLX5_ASSERT(last); 757256fb0e3SMichael Baum txq->elts_comp = head; 758256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(INLINE)) 759256fb0e3SMichael Baum txq->wqe_comp = txq->wqe_ci; 760256fb0e3SMichael Baum /* Request unconditional completion on last WQE. */ 761256fb0e3SMichael Baum last->cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS << 762256fb0e3SMichael Baum MLX5_COMP_MODE_OFFSET); 763256fb0e3SMichael Baum /* Save elts_head in dedicated free on completion queue. */ 764256fb0e3SMichael Baum #ifdef RTE_LIBRTE_MLX5_DEBUG 765256fb0e3SMichael Baum txq->fcqs[txq->cq_pi++ & txq->cqe_m] = head | 766256fb0e3SMichael Baum (last->cseg.opcode >> 8) << 16; 767256fb0e3SMichael Baum #else 768256fb0e3SMichael Baum txq->fcqs[txq->cq_pi++ & txq->cqe_m] = head; 769256fb0e3SMichael Baum #endif 770256fb0e3SMichael Baum /* A CQE slot must always be available. */ 771256fb0e3SMichael Baum MLX5_ASSERT((txq->cq_pi - txq->cq_ci) <= txq->cqe_s); 772256fb0e3SMichael Baum } 773256fb0e3SMichael Baum } 774256fb0e3SMichael Baum 775256fb0e3SMichael Baum /** 7768fa8d147SViacheslav Ovsiienko * Set completion request flag for all issued WQEs. 7778fa8d147SViacheslav Ovsiienko * This routine is intended to be used with enabled fast path tracing 7788fa8d147SViacheslav Ovsiienko * and send scheduling on time to provide the detailed report in trace 7798fa8d147SViacheslav Ovsiienko * for send completions on every WQE. 7808fa8d147SViacheslav Ovsiienko * 7818fa8d147SViacheslav Ovsiienko * @param txq 7828fa8d147SViacheslav Ovsiienko * Pointer to TX queue structure. 7838fa8d147SViacheslav Ovsiienko * @param loc 7848fa8d147SViacheslav Ovsiienko * Pointer to burst routine local context. 7858fa8d147SViacheslav Ovsiienko * @param olx 7868fa8d147SViacheslav Ovsiienko * Configured Tx offloads mask. It is fully defined at 7878fa8d147SViacheslav Ovsiienko * compile time and may be used for optimization. 7888fa8d147SViacheslav Ovsiienko */ 7898fa8d147SViacheslav Ovsiienko static __rte_always_inline void 7908fa8d147SViacheslav Ovsiienko mlx5_tx_request_completion_trace(struct mlx5_txq_data *__rte_restrict txq, 7918fa8d147SViacheslav Ovsiienko struct mlx5_txq_local *__rte_restrict loc, 7928fa8d147SViacheslav Ovsiienko unsigned int olx) 7938fa8d147SViacheslav Ovsiienko { 7948fa8d147SViacheslav Ovsiienko uint16_t head = txq->elts_comp; 7958fa8d147SViacheslav Ovsiienko 7968fa8d147SViacheslav Ovsiienko while (txq->wqe_comp != txq->wqe_ci) { 7978fa8d147SViacheslav Ovsiienko volatile struct mlx5_wqe *wqe; 7988fa8d147SViacheslav Ovsiienko uint32_t wqe_n; 7998fa8d147SViacheslav Ovsiienko 8008fa8d147SViacheslav Ovsiienko MLX5_ASSERT(loc->wqe_last); 8018fa8d147SViacheslav Ovsiienko wqe = txq->wqes + (txq->wqe_comp & txq->wqe_m); 8028fa8d147SViacheslav Ovsiienko if (wqe == loc->wqe_last) { 8038fa8d147SViacheslav Ovsiienko head = txq->elts_head; 8048fa8d147SViacheslav Ovsiienko head += MLX5_TXOFF_CONFIG(INLINE) ? 8058fa8d147SViacheslav Ovsiienko 0 : loc->pkts_sent - loc->pkts_copy; 8068fa8d147SViacheslav Ovsiienko txq->elts_comp = head; 8078fa8d147SViacheslav Ovsiienko } 8088fa8d147SViacheslav Ovsiienko /* Completion request flag was set on cseg constructing. */ 8098fa8d147SViacheslav Ovsiienko #ifdef RTE_LIBRTE_MLX5_DEBUG 8108fa8d147SViacheslav Ovsiienko txq->fcqs[txq->cq_pi++ & txq->cqe_m] = head | 8118fa8d147SViacheslav Ovsiienko (wqe->cseg.opcode >> 8) << 16; 8128fa8d147SViacheslav Ovsiienko #else 8138fa8d147SViacheslav Ovsiienko txq->fcqs[txq->cq_pi++ & txq->cqe_m] = head; 8148fa8d147SViacheslav Ovsiienko #endif 8158fa8d147SViacheslav Ovsiienko /* A CQE slot must always be available. */ 8168fa8d147SViacheslav Ovsiienko MLX5_ASSERT((txq->cq_pi - txq->cq_ci) <= txq->cqe_s); 8178fa8d147SViacheslav Ovsiienko /* Advance to the next WQE in the queue. */ 8188fa8d147SViacheslav Ovsiienko wqe_n = rte_be_to_cpu_32(wqe->cseg.sq_ds) & 0x3F; 8198fa8d147SViacheslav Ovsiienko txq->wqe_comp += RTE_ALIGN(wqe_n, 4) / 4; 8208fa8d147SViacheslav Ovsiienko } 8218fa8d147SViacheslav Ovsiienko } 8228fa8d147SViacheslav Ovsiienko 8238fa8d147SViacheslav Ovsiienko /** 824256fb0e3SMichael Baum * Build the Control Segment with specified opcode: 825256fb0e3SMichael Baum * - MLX5_OPCODE_SEND 826256fb0e3SMichael Baum * - MLX5_OPCODE_ENHANCED_MPSW 827256fb0e3SMichael Baum * - MLX5_OPCODE_TSO 828256fb0e3SMichael Baum * 829256fb0e3SMichael Baum * @param txq 830256fb0e3SMichael Baum * Pointer to TX queue structure. 831256fb0e3SMichael Baum * @param loc 832256fb0e3SMichael Baum * Pointer to burst routine local context. 833256fb0e3SMichael Baum * @param wqe 834256fb0e3SMichael Baum * Pointer to WQE to fill with built Control Segment. 835256fb0e3SMichael Baum * @param ds 836256fb0e3SMichael Baum * Supposed length of WQE in segments. 837256fb0e3SMichael Baum * @param opcode 838256fb0e3SMichael Baum * SQ WQE opcode to put into Control Segment. 839256fb0e3SMichael Baum * @param olx 840256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 841256fb0e3SMichael Baum * compile time and may be used for optimization. 842256fb0e3SMichael Baum */ 843256fb0e3SMichael Baum static __rte_always_inline void 844256fb0e3SMichael Baum mlx5_tx_cseg_init(struct mlx5_txq_data *__rte_restrict txq, 845256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc __rte_unused, 846256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 847256fb0e3SMichael Baum unsigned int ds, 848256fb0e3SMichael Baum unsigned int opcode, 8498fa8d147SViacheslav Ovsiienko unsigned int olx) 850256fb0e3SMichael Baum { 851256fb0e3SMichael Baum struct mlx5_wqe_cseg *__rte_restrict cs = &wqe->cseg; 852*02932480STim Martin uint64_t real_time; 853256fb0e3SMichael Baum 854256fb0e3SMichael Baum /* For legacy MPW replace the EMPW by TSO with modifier. */ 855256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW) && opcode == MLX5_OPCODE_ENHANCED_MPSW) 856256fb0e3SMichael Baum opcode = MLX5_OPCODE_TSO | MLX5_OPC_MOD_MPW << 24; 857256fb0e3SMichael Baum cs->opcode = rte_cpu_to_be_32((txq->wqe_ci << 8) | opcode); 858256fb0e3SMichael Baum cs->sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds); 8598fa8d147SViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(TXPP) && __rte_trace_point_fp_is_enabled()) 8608fa8d147SViacheslav Ovsiienko cs->flags = RTE_BE32(MLX5_COMP_ALWAYS << 8618fa8d147SViacheslav Ovsiienko MLX5_COMP_MODE_OFFSET); 8628fa8d147SViacheslav Ovsiienko else 863256fb0e3SMichael Baum cs->flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR << 864256fb0e3SMichael Baum MLX5_COMP_MODE_OFFSET); 865256fb0e3SMichael Baum cs->misc = RTE_BE32(0); 866*02932480STim Martin if (__rte_trace_point_fp_is_enabled()) { 867*02932480STim Martin real_time = mlx5_read_pcibar_clock_from_txq(txq); 868*02932480STim Martin if (!loc->pkts_sent) 869*02932480STim Martin rte_pmd_mlx5_trace_tx_entry(real_time, txq->port_id, txq->idx); 870*02932480STim Martin rte_pmd_mlx5_trace_tx_wqe(real_time, (txq->wqe_ci << 8) | opcode); 871*02932480STim Martin } 872256fb0e3SMichael Baum } 873256fb0e3SMichael Baum 874256fb0e3SMichael Baum /** 875256fb0e3SMichael Baum * Build the Synchronize Queue Segment with specified completion index. 876256fb0e3SMichael Baum * 877256fb0e3SMichael Baum * @param txq 878256fb0e3SMichael Baum * Pointer to TX queue structure. 879256fb0e3SMichael Baum * @param loc 880256fb0e3SMichael Baum * Pointer to burst routine local context. 881256fb0e3SMichael Baum * @param wqe 882256fb0e3SMichael Baum * Pointer to WQE to fill with built Control Segment. 883256fb0e3SMichael Baum * @param wci 884256fb0e3SMichael Baum * Completion index in Clock Queue to wait. 885256fb0e3SMichael Baum * @param olx 886256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 887256fb0e3SMichael Baum * compile time and may be used for optimization. 888256fb0e3SMichael Baum */ 889256fb0e3SMichael Baum static __rte_always_inline void 89049e87976SViacheslav Ovsiienko mlx5_tx_qseg_init(struct mlx5_txq_data *restrict txq, 891256fb0e3SMichael Baum struct mlx5_txq_local *restrict loc __rte_unused, 892256fb0e3SMichael Baum struct mlx5_wqe *restrict wqe, 893256fb0e3SMichael Baum unsigned int wci, 894256fb0e3SMichael Baum unsigned int olx __rte_unused) 895256fb0e3SMichael Baum { 896256fb0e3SMichael Baum struct mlx5_wqe_qseg *qs; 897256fb0e3SMichael Baum 898256fb0e3SMichael Baum qs = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE); 899256fb0e3SMichael Baum qs->max_index = rte_cpu_to_be_32(wci); 900256fb0e3SMichael Baum qs->qpn_cqn = rte_cpu_to_be_32(txq->sh->txpp.clock_queue.cq_obj.cq->id); 901256fb0e3SMichael Baum qs->reserved0 = RTE_BE32(0); 902256fb0e3SMichael Baum qs->reserved1 = RTE_BE32(0); 903256fb0e3SMichael Baum } 904256fb0e3SMichael Baum 905256fb0e3SMichael Baum /** 90649e87976SViacheslav Ovsiienko * Build the Wait on Time Segment with specified timestamp value. 90749e87976SViacheslav Ovsiienko * 90849e87976SViacheslav Ovsiienko * @param txq 90949e87976SViacheslav Ovsiienko * Pointer to TX queue structure. 91049e87976SViacheslav Ovsiienko * @param loc 91149e87976SViacheslav Ovsiienko * Pointer to burst routine local context. 91249e87976SViacheslav Ovsiienko * @param wqe 91349e87976SViacheslav Ovsiienko * Pointer to WQE to fill with built Control Segment. 91449e87976SViacheslav Ovsiienko * @param ts 91549e87976SViacheslav Ovsiienko * Timesatmp value to wait. 91649e87976SViacheslav Ovsiienko * @param olx 91749e87976SViacheslav Ovsiienko * Configured Tx offloads mask. It is fully defined at 91849e87976SViacheslav Ovsiienko * compile time and may be used for optimization. 91949e87976SViacheslav Ovsiienko */ 92049e87976SViacheslav Ovsiienko static __rte_always_inline void 92149e87976SViacheslav Ovsiienko mlx5_tx_wseg_init(struct mlx5_txq_data *restrict txq, 92249e87976SViacheslav Ovsiienko struct mlx5_txq_local *restrict loc __rte_unused, 92349e87976SViacheslav Ovsiienko struct mlx5_wqe *restrict wqe, 92449e87976SViacheslav Ovsiienko uint64_t ts, 92549e87976SViacheslav Ovsiienko unsigned int olx __rte_unused) 92649e87976SViacheslav Ovsiienko { 92749e87976SViacheslav Ovsiienko struct mlx5_wqe_wseg *ws; 92849e87976SViacheslav Ovsiienko 92949e87976SViacheslav Ovsiienko ws = RTE_PTR_ADD(wqe, MLX5_WSEG_SIZE); 9302c7cb21aSViacheslav Ovsiienko ws->operation = rte_cpu_to_be_32(MLX5_WAIT_COND_CYCLIC_SMALLER); 93149e87976SViacheslav Ovsiienko ws->lkey = RTE_BE32(0); 93249e87976SViacheslav Ovsiienko ws->va_high = RTE_BE32(0); 93349e87976SViacheslav Ovsiienko ws->va_low = RTE_BE32(0); 93449e87976SViacheslav Ovsiienko if (txq->rt_timestamp) { 93549e87976SViacheslav Ovsiienko ts = ts % (uint64_t)NS_PER_S 93649e87976SViacheslav Ovsiienko | (ts / (uint64_t)NS_PER_S) << 32; 93749e87976SViacheslav Ovsiienko } 93849e87976SViacheslav Ovsiienko ws->value = rte_cpu_to_be_64(ts); 93949e87976SViacheslav Ovsiienko ws->mask = txq->rt_timemask; 94049e87976SViacheslav Ovsiienko } 94149e87976SViacheslav Ovsiienko 94249e87976SViacheslav Ovsiienko /** 943256fb0e3SMichael Baum * Build the Ethernet Segment without inlined data. 944256fb0e3SMichael Baum * Supports Software Parser, Checksums and VLAN insertion Tx offload features. 945256fb0e3SMichael Baum * 946256fb0e3SMichael Baum * @param txq 947256fb0e3SMichael Baum * Pointer to TX queue structure. 948256fb0e3SMichael Baum * @param loc 949256fb0e3SMichael Baum * Pointer to burst routine local context. 950256fb0e3SMichael Baum * @param wqe 951256fb0e3SMichael Baum * Pointer to WQE to fill with built Ethernet Segment. 952256fb0e3SMichael Baum * @param olx 953256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 954256fb0e3SMichael Baum * compile time and may be used for optimization. 955256fb0e3SMichael Baum */ 956256fb0e3SMichael Baum static __rte_always_inline void 957256fb0e3SMichael Baum mlx5_tx_eseg_none(struct mlx5_txq_data *__rte_restrict txq __rte_unused, 958256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 959256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 960256fb0e3SMichael Baum unsigned int olx) 961256fb0e3SMichael Baum { 962256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict es = &wqe->eseg; 963256fb0e3SMichael Baum uint32_t csum; 964256fb0e3SMichael Baum 965256fb0e3SMichael Baum /* 966256fb0e3SMichael Baum * Calculate and set check sum flags first, dword field 967256fb0e3SMichael Baum * in segment may be shared with Software Parser flags. 968256fb0e3SMichael Baum */ 969256fb0e3SMichael Baum csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0; 970256fb0e3SMichael Baum es->flags = rte_cpu_to_le_32(csum); 971256fb0e3SMichael Baum /* 972256fb0e3SMichael Baum * Calculate and set Software Parser offsets and flags. 973256fb0e3SMichael Baum * These flags a set for custom UDP and IP tunnel packets. 974256fb0e3SMichael Baum */ 975256fb0e3SMichael Baum es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx); 976256fb0e3SMichael Baum /* Fill metadata field if needed. */ 977256fb0e3SMichael Baum es->metadata = MLX5_TXOFF_CONFIG(METADATA) ? 978daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_DYNFLAG_TX_METADATA ? 9796728fe93SBing Zhao rte_cpu_to_be_32(*RTE_FLOW_DYNF_METADATA(loc->mbuf)) : 9806728fe93SBing Zhao 0 : 0; 981256fb0e3SMichael Baum /* Engage VLAN tag insertion feature if requested. */ 982256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 983daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) { 984256fb0e3SMichael Baum /* 985256fb0e3SMichael Baum * We should get here only if device support 986256fb0e3SMichael Baum * this feature correctly. 987256fb0e3SMichael Baum */ 988256fb0e3SMichael Baum MLX5_ASSERT(txq->vlan_en); 989256fb0e3SMichael Baum es->inline_hdr = rte_cpu_to_be_32(MLX5_ETH_WQE_VLAN_INSERT | 990256fb0e3SMichael Baum loc->mbuf->vlan_tci); 991256fb0e3SMichael Baum } else { 992256fb0e3SMichael Baum es->inline_hdr = RTE_BE32(0); 993256fb0e3SMichael Baum } 994256fb0e3SMichael Baum } 995256fb0e3SMichael Baum 996256fb0e3SMichael Baum /** 997256fb0e3SMichael Baum * Build the Ethernet Segment with minimal inlined data 998256fb0e3SMichael Baum * of MLX5_ESEG_MIN_INLINE_SIZE bytes length. This is 999256fb0e3SMichael Baum * used to fill the gap in single WQEBB WQEs. 1000256fb0e3SMichael Baum * Supports Software Parser, Checksums and VLAN 1001256fb0e3SMichael Baum * insertion Tx offload features. 1002256fb0e3SMichael Baum * 1003256fb0e3SMichael Baum * @param txq 1004256fb0e3SMichael Baum * Pointer to TX queue structure. 1005256fb0e3SMichael Baum * @param loc 1006256fb0e3SMichael Baum * Pointer to burst routine local context. 1007256fb0e3SMichael Baum * @param wqe 1008256fb0e3SMichael Baum * Pointer to WQE to fill with built Ethernet Segment. 1009256fb0e3SMichael Baum * @param vlan 1010256fb0e3SMichael Baum * Length of VLAN tag insertion if any. 1011256fb0e3SMichael Baum * @param olx 1012256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1013256fb0e3SMichael Baum * compile time and may be used for optimization. 1014256fb0e3SMichael Baum */ 1015256fb0e3SMichael Baum static __rte_always_inline void 1016256fb0e3SMichael Baum mlx5_tx_eseg_dmin(struct mlx5_txq_data *__rte_restrict txq __rte_unused, 1017256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1018256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 1019256fb0e3SMichael Baum unsigned int vlan, 1020256fb0e3SMichael Baum unsigned int olx) 1021256fb0e3SMichael Baum { 1022256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict es = &wqe->eseg; 1023256fb0e3SMichael Baum uint32_t csum; 1024256fb0e3SMichael Baum uint8_t *psrc, *pdst; 1025256fb0e3SMichael Baum 1026256fb0e3SMichael Baum /* 1027256fb0e3SMichael Baum * Calculate and set check sum flags first, dword field 1028256fb0e3SMichael Baum * in segment may be shared with Software Parser flags. 1029256fb0e3SMichael Baum */ 1030256fb0e3SMichael Baum csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0; 1031256fb0e3SMichael Baum es->flags = rte_cpu_to_le_32(csum); 1032256fb0e3SMichael Baum /* 1033256fb0e3SMichael Baum * Calculate and set Software Parser offsets and flags. 1034256fb0e3SMichael Baum * These flags a set for custom UDP and IP tunnel packets. 1035256fb0e3SMichael Baum */ 1036256fb0e3SMichael Baum es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx); 1037256fb0e3SMichael Baum /* Fill metadata field if needed. */ 1038256fb0e3SMichael Baum es->metadata = MLX5_TXOFF_CONFIG(METADATA) ? 1039daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_DYNFLAG_TX_METADATA ? 10406728fe93SBing Zhao rte_cpu_to_be_32(*RTE_FLOW_DYNF_METADATA(loc->mbuf)) : 10416728fe93SBing Zhao 0 : 0; 1042256fb0e3SMichael Baum psrc = rte_pktmbuf_mtod(loc->mbuf, uint8_t *); 1043256fb0e3SMichael Baum es->inline_hdr_sz = RTE_BE16(MLX5_ESEG_MIN_INLINE_SIZE); 1044256fb0e3SMichael Baum es->inline_data = *(unaligned_uint16_t *)psrc; 1045256fb0e3SMichael Baum psrc += sizeof(uint16_t); 1046256fb0e3SMichael Baum pdst = (uint8_t *)(es + 1); 1047256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && vlan) { 1048256fb0e3SMichael Baum /* Implement VLAN tag insertion as part inline data. */ 1049256fb0e3SMichael Baum memcpy(pdst, psrc, 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t)); 1050256fb0e3SMichael Baum pdst += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t); 1051256fb0e3SMichael Baum psrc += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t); 1052256fb0e3SMichael Baum /* Insert VLAN ethertype + VLAN tag. */ 1053256fb0e3SMichael Baum *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32 1054256fb0e3SMichael Baum ((RTE_ETHER_TYPE_VLAN << 16) | 1055256fb0e3SMichael Baum loc->mbuf->vlan_tci); 1056256fb0e3SMichael Baum pdst += sizeof(struct rte_vlan_hdr); 1057256fb0e3SMichael Baum /* Copy the rest two bytes from packet data. */ 1058256fb0e3SMichael Baum MLX5_ASSERT(pdst == RTE_PTR_ALIGN(pdst, sizeof(uint16_t))); 1059256fb0e3SMichael Baum *(uint16_t *)pdst = *(unaligned_uint16_t *)psrc; 1060256fb0e3SMichael Baum } else { 1061256fb0e3SMichael Baum /* Fill the gap in the title WQEBB with inline data. */ 1062256fb0e3SMichael Baum rte_mov16(pdst, psrc); 1063256fb0e3SMichael Baum } 1064256fb0e3SMichael Baum } 1065256fb0e3SMichael Baum 1066256fb0e3SMichael Baum /** 1067256fb0e3SMichael Baum * Build the Ethernet Segment with entire packet data inlining. Checks the 1068256fb0e3SMichael Baum * boundary of WQEBB and ring buffer wrapping, supports Software Parser, 1069256fb0e3SMichael Baum * Checksums and VLAN insertion Tx offload features. 1070256fb0e3SMichael Baum * 1071256fb0e3SMichael Baum * @param txq 1072256fb0e3SMichael Baum * Pointer to TX queue structure. 1073256fb0e3SMichael Baum * @param loc 1074256fb0e3SMichael Baum * Pointer to burst routine local context. 1075256fb0e3SMichael Baum * @param wqe 1076256fb0e3SMichael Baum * Pointer to WQE to fill with built Ethernet Segment. 1077256fb0e3SMichael Baum * @param vlan 1078256fb0e3SMichael Baum * Length of VLAN tag insertion if any. 1079256fb0e3SMichael Baum * @param inlen 1080256fb0e3SMichael Baum * Length of data to inline (VLAN included, if any). 1081256fb0e3SMichael Baum * @param tso 1082256fb0e3SMichael Baum * TSO flag, set mss field from the packet. 1083256fb0e3SMichael Baum * @param olx 1084256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1085256fb0e3SMichael Baum * compile time and may be used for optimization. 1086256fb0e3SMichael Baum * 1087256fb0e3SMichael Baum * @return 1088256fb0e3SMichael Baum * Pointer to the next Data Segment (aligned and wrapped around). 1089256fb0e3SMichael Baum */ 1090256fb0e3SMichael Baum static __rte_always_inline struct mlx5_wqe_dseg * 1091256fb0e3SMichael Baum mlx5_tx_eseg_data(struct mlx5_txq_data *__rte_restrict txq, 1092256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1093256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 1094256fb0e3SMichael Baum unsigned int vlan, 1095256fb0e3SMichael Baum unsigned int inlen, 1096256fb0e3SMichael Baum unsigned int tso, 1097256fb0e3SMichael Baum unsigned int olx) 1098256fb0e3SMichael Baum { 1099256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict es = &wqe->eseg; 1100256fb0e3SMichael Baum uint32_t csum; 1101256fb0e3SMichael Baum uint8_t *psrc, *pdst; 1102256fb0e3SMichael Baum unsigned int part; 1103256fb0e3SMichael Baum 1104256fb0e3SMichael Baum /* 1105256fb0e3SMichael Baum * Calculate and set check sum flags first, dword field 1106256fb0e3SMichael Baum * in segment may be shared with Software Parser flags. 1107256fb0e3SMichael Baum */ 1108256fb0e3SMichael Baum csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0; 1109256fb0e3SMichael Baum if (tso) { 1110256fb0e3SMichael Baum csum <<= 24; 1111256fb0e3SMichael Baum csum |= loc->mbuf->tso_segsz; 1112256fb0e3SMichael Baum es->flags = rte_cpu_to_be_32(csum); 1113256fb0e3SMichael Baum } else { 1114256fb0e3SMichael Baum es->flags = rte_cpu_to_le_32(csum); 1115256fb0e3SMichael Baum } 1116256fb0e3SMichael Baum /* 1117256fb0e3SMichael Baum * Calculate and set Software Parser offsets and flags. 1118256fb0e3SMichael Baum * These flags a set for custom UDP and IP tunnel packets. 1119256fb0e3SMichael Baum */ 1120256fb0e3SMichael Baum es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx); 1121256fb0e3SMichael Baum /* Fill metadata field if needed. */ 1122256fb0e3SMichael Baum es->metadata = MLX5_TXOFF_CONFIG(METADATA) ? 1123daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_DYNFLAG_TX_METADATA ? 11246728fe93SBing Zhao rte_cpu_to_be_32(*RTE_FLOW_DYNF_METADATA(loc->mbuf)) : 11256728fe93SBing Zhao 0 : 0; 1126256fb0e3SMichael Baum psrc = rte_pktmbuf_mtod(loc->mbuf, uint8_t *); 1127256fb0e3SMichael Baum es->inline_hdr_sz = rte_cpu_to_be_16(inlen); 1128256fb0e3SMichael Baum es->inline_data = *(unaligned_uint16_t *)psrc; 1129256fb0e3SMichael Baum psrc += sizeof(uint16_t); 1130256fb0e3SMichael Baum pdst = (uint8_t *)(es + 1); 1131256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && vlan) { 1132256fb0e3SMichael Baum /* Implement VLAN tag insertion as part inline data. */ 1133256fb0e3SMichael Baum memcpy(pdst, psrc, 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t)); 1134256fb0e3SMichael Baum pdst += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t); 1135256fb0e3SMichael Baum psrc += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t); 1136256fb0e3SMichael Baum /* Insert VLAN ethertype + VLAN tag. */ 1137256fb0e3SMichael Baum *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32 1138256fb0e3SMichael Baum ((RTE_ETHER_TYPE_VLAN << 16) | 1139256fb0e3SMichael Baum loc->mbuf->vlan_tci); 1140256fb0e3SMichael Baum pdst += sizeof(struct rte_vlan_hdr); 1141256fb0e3SMichael Baum /* Copy the rest two bytes from packet data. */ 1142256fb0e3SMichael Baum MLX5_ASSERT(pdst == RTE_PTR_ALIGN(pdst, sizeof(uint16_t))); 1143256fb0e3SMichael Baum *(uint16_t *)pdst = *(unaligned_uint16_t *)psrc; 1144256fb0e3SMichael Baum psrc += sizeof(uint16_t); 1145256fb0e3SMichael Baum } else { 1146256fb0e3SMichael Baum /* Fill the gap in the title WQEBB with inline data. */ 1147256fb0e3SMichael Baum rte_mov16(pdst, psrc); 1148256fb0e3SMichael Baum psrc += sizeof(rte_v128u32_t); 1149256fb0e3SMichael Baum } 1150256fb0e3SMichael Baum pdst = (uint8_t *)(es + 2); 1151256fb0e3SMichael Baum MLX5_ASSERT(inlen >= MLX5_ESEG_MIN_INLINE_SIZE); 1152256fb0e3SMichael Baum MLX5_ASSERT(pdst < (uint8_t *)txq->wqes_end); 1153256fb0e3SMichael Baum inlen -= MLX5_ESEG_MIN_INLINE_SIZE; 1154256fb0e3SMichael Baum if (!inlen) { 1155256fb0e3SMichael Baum MLX5_ASSERT(pdst == RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE)); 1156256fb0e3SMichael Baum return (struct mlx5_wqe_dseg *)pdst; 1157256fb0e3SMichael Baum } 1158256fb0e3SMichael Baum /* 1159256fb0e3SMichael Baum * The WQEBB space availability is checked by caller. 1160256fb0e3SMichael Baum * Here we should be aware of WQE ring buffer wraparound only. 1161256fb0e3SMichael Baum */ 1162256fb0e3SMichael Baum part = (uint8_t *)txq->wqes_end - pdst; 1163256fb0e3SMichael Baum part = RTE_MIN(part, inlen); 1164256fb0e3SMichael Baum do { 1165256fb0e3SMichael Baum rte_memcpy(pdst, psrc, part); 1166256fb0e3SMichael Baum inlen -= part; 1167256fb0e3SMichael Baum if (likely(!inlen)) { 1168256fb0e3SMichael Baum /* 1169256fb0e3SMichael Baum * If return value is not used by the caller 1170256fb0e3SMichael Baum * the code below will be optimized out. 1171256fb0e3SMichael Baum */ 1172256fb0e3SMichael Baum pdst += part; 1173256fb0e3SMichael Baum pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE); 1174256fb0e3SMichael Baum if (unlikely(pdst >= (uint8_t *)txq->wqes_end)) 1175256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1176256fb0e3SMichael Baum return (struct mlx5_wqe_dseg *)pdst; 1177256fb0e3SMichael Baum } 1178256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1179256fb0e3SMichael Baum psrc += part; 1180256fb0e3SMichael Baum part = inlen; 1181256fb0e3SMichael Baum } while (true); 1182256fb0e3SMichael Baum } 1183256fb0e3SMichael Baum 1184256fb0e3SMichael Baum /** 1185256fb0e3SMichael Baum * Copy data from chain of mbuf to the specified linear buffer. 1186256fb0e3SMichael Baum * Checksums and VLAN insertion Tx offload features. If data 1187256fb0e3SMichael Baum * from some mbuf copied completely this mbuf is freed. Local 1188256fb0e3SMichael Baum * structure is used to keep the byte stream state. 1189256fb0e3SMichael Baum * 1190256fb0e3SMichael Baum * @param pdst 1191256fb0e3SMichael Baum * Pointer to the destination linear buffer. 1192256fb0e3SMichael Baum * @param loc 1193256fb0e3SMichael Baum * Pointer to burst routine local context. 1194256fb0e3SMichael Baum * @param len 1195256fb0e3SMichael Baum * Length of data to be copied. 1196256fb0e3SMichael Baum * @param must 1197256fb0e3SMichael Baum * Length of data to be copied ignoring no inline hint. 1198256fb0e3SMichael Baum * @param olx 1199256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1200256fb0e3SMichael Baum * compile time and may be used for optimization. 1201256fb0e3SMichael Baum * 1202256fb0e3SMichael Baum * @return 1203256fb0e3SMichael Baum * Number of actual copied data bytes. This is always greater than or 1204256fb0e3SMichael Baum * equal to must parameter and might be lesser than len in no inline 1205256fb0e3SMichael Baum * hint flag is encountered. 1206256fb0e3SMichael Baum */ 1207256fb0e3SMichael Baum static __rte_always_inline unsigned int 1208256fb0e3SMichael Baum mlx5_tx_mseg_memcpy(uint8_t *pdst, 1209256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1210256fb0e3SMichael Baum unsigned int len, 1211256fb0e3SMichael Baum unsigned int must, 1212256fb0e3SMichael Baum unsigned int olx __rte_unused) 1213256fb0e3SMichael Baum { 1214256fb0e3SMichael Baum struct rte_mbuf *mbuf; 1215256fb0e3SMichael Baum unsigned int part, dlen, copy = 0; 1216256fb0e3SMichael Baum uint8_t *psrc; 1217256fb0e3SMichael Baum 1218256fb0e3SMichael Baum MLX5_ASSERT(len); 1219256fb0e3SMichael Baum do { 1220256fb0e3SMichael Baum /* Allow zero length packets, must check first. */ 1221256fb0e3SMichael Baum dlen = rte_pktmbuf_data_len(loc->mbuf); 1222256fb0e3SMichael Baum if (dlen <= loc->mbuf_off) { 1223256fb0e3SMichael Baum /* Exhausted packet, just free. */ 1224256fb0e3SMichael Baum mbuf = loc->mbuf; 1225256fb0e3SMichael Baum loc->mbuf = mbuf->next; 1226256fb0e3SMichael Baum rte_pktmbuf_free_seg(mbuf); 1227256fb0e3SMichael Baum loc->mbuf_off = 0; 1228256fb0e3SMichael Baum MLX5_ASSERT(loc->mbuf_nseg > 1); 1229256fb0e3SMichael Baum MLX5_ASSERT(loc->mbuf); 1230256fb0e3SMichael Baum --loc->mbuf_nseg; 1231daa02b5cSOlivier Matz if (loc->mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE) { 1232256fb0e3SMichael Baum unsigned int diff; 1233256fb0e3SMichael Baum 1234256fb0e3SMichael Baum if (copy >= must) { 1235256fb0e3SMichael Baum /* 1236256fb0e3SMichael Baum * We already copied the minimal 1237256fb0e3SMichael Baum * requested amount of data. 1238256fb0e3SMichael Baum */ 1239256fb0e3SMichael Baum return copy; 1240256fb0e3SMichael Baum } 1241256fb0e3SMichael Baum diff = must - copy; 1242256fb0e3SMichael Baum if (diff <= rte_pktmbuf_data_len(loc->mbuf)) { 1243256fb0e3SMichael Baum /* 1244256fb0e3SMichael Baum * Copy only the minimal required 1245fa488345SDariusz Sosnowski * part of the data buffer. Limit amount 1246fa488345SDariusz Sosnowski * of data to be copied to the length of 1247fa488345SDariusz Sosnowski * available space. 1248256fb0e3SMichael Baum */ 1249fa488345SDariusz Sosnowski len = RTE_MIN(len, diff); 1250256fb0e3SMichael Baum } 1251256fb0e3SMichael Baum } 1252256fb0e3SMichael Baum continue; 1253256fb0e3SMichael Baum } 1254256fb0e3SMichael Baum dlen -= loc->mbuf_off; 1255256fb0e3SMichael Baum psrc = rte_pktmbuf_mtod_offset(loc->mbuf, uint8_t *, 1256256fb0e3SMichael Baum loc->mbuf_off); 1257256fb0e3SMichael Baum part = RTE_MIN(len, dlen); 1258256fb0e3SMichael Baum rte_memcpy(pdst, psrc, part); 1259256fb0e3SMichael Baum copy += part; 1260256fb0e3SMichael Baum loc->mbuf_off += part; 1261256fb0e3SMichael Baum len -= part; 1262256fb0e3SMichael Baum if (!len) { 1263256fb0e3SMichael Baum if (loc->mbuf_off >= rte_pktmbuf_data_len(loc->mbuf)) { 1264256fb0e3SMichael Baum loc->mbuf_off = 0; 1265256fb0e3SMichael Baum /* Exhausted packet, just free. */ 1266256fb0e3SMichael Baum mbuf = loc->mbuf; 1267256fb0e3SMichael Baum loc->mbuf = mbuf->next; 1268256fb0e3SMichael Baum rte_pktmbuf_free_seg(mbuf); 1269256fb0e3SMichael Baum loc->mbuf_off = 0; 1270256fb0e3SMichael Baum MLX5_ASSERT(loc->mbuf_nseg >= 1); 1271256fb0e3SMichael Baum --loc->mbuf_nseg; 1272256fb0e3SMichael Baum } 1273256fb0e3SMichael Baum return copy; 1274256fb0e3SMichael Baum } 1275256fb0e3SMichael Baum pdst += part; 1276256fb0e3SMichael Baum } while (true); 1277256fb0e3SMichael Baum } 1278256fb0e3SMichael Baum 1279256fb0e3SMichael Baum /** 1280256fb0e3SMichael Baum * Build the Ethernet Segment with inlined data from multi-segment packet. 1281256fb0e3SMichael Baum * Checks the boundary of WQEBB and ring buffer wrapping, supports Software 1282256fb0e3SMichael Baum * Parser, Checksums and VLAN insertion Tx offload features. 1283256fb0e3SMichael Baum * 1284256fb0e3SMichael Baum * @param txq 1285256fb0e3SMichael Baum * Pointer to TX queue structure. 1286256fb0e3SMichael Baum * @param loc 1287256fb0e3SMichael Baum * Pointer to burst routine local context. 1288256fb0e3SMichael Baum * @param wqe 1289256fb0e3SMichael Baum * Pointer to WQE to fill with built Ethernet Segment. 1290256fb0e3SMichael Baum * @param vlan 1291256fb0e3SMichael Baum * Length of VLAN tag insertion if any. 1292256fb0e3SMichael Baum * @param inlen 1293256fb0e3SMichael Baum * Length of data to inline (VLAN included, if any). 1294256fb0e3SMichael Baum * @param tso 1295256fb0e3SMichael Baum * TSO flag, set mss field from the packet. 1296256fb0e3SMichael Baum * @param olx 1297256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1298256fb0e3SMichael Baum * compile time and may be used for optimization. 1299256fb0e3SMichael Baum * 1300256fb0e3SMichael Baum * @return 1301256fb0e3SMichael Baum * Pointer to the next Data Segment (aligned and possible NOT wrapped 1302256fb0e3SMichael Baum * around - caller should do wrapping check on its own). 1303256fb0e3SMichael Baum */ 1304256fb0e3SMichael Baum static __rte_always_inline struct mlx5_wqe_dseg * 1305256fb0e3SMichael Baum mlx5_tx_eseg_mdat(struct mlx5_txq_data *__rte_restrict txq, 1306256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1307256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 1308256fb0e3SMichael Baum unsigned int vlan, 1309256fb0e3SMichael Baum unsigned int inlen, 1310256fb0e3SMichael Baum unsigned int tso, 1311256fb0e3SMichael Baum unsigned int olx) 1312256fb0e3SMichael Baum { 1313256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict es = &wqe->eseg; 1314256fb0e3SMichael Baum uint32_t csum; 1315256fb0e3SMichael Baum uint8_t *pdst; 1316256fb0e3SMichael Baum unsigned int part, tlen = 0; 1317256fb0e3SMichael Baum 1318256fb0e3SMichael Baum /* 1319256fb0e3SMichael Baum * Calculate and set check sum flags first, uint32_t field 1320256fb0e3SMichael Baum * in segment may be shared with Software Parser flags. 1321256fb0e3SMichael Baum */ 1322256fb0e3SMichael Baum csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0; 1323256fb0e3SMichael Baum if (tso) { 1324256fb0e3SMichael Baum csum <<= 24; 1325256fb0e3SMichael Baum csum |= loc->mbuf->tso_segsz; 1326256fb0e3SMichael Baum es->flags = rte_cpu_to_be_32(csum); 1327256fb0e3SMichael Baum } else { 1328256fb0e3SMichael Baum es->flags = rte_cpu_to_le_32(csum); 1329256fb0e3SMichael Baum } 1330256fb0e3SMichael Baum /* 1331256fb0e3SMichael Baum * Calculate and set Software Parser offsets and flags. 1332256fb0e3SMichael Baum * These flags a set for custom UDP and IP tunnel packets. 1333256fb0e3SMichael Baum */ 1334256fb0e3SMichael Baum es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx); 1335256fb0e3SMichael Baum /* Fill metadata field if needed. */ 1336256fb0e3SMichael Baum es->metadata = MLX5_TXOFF_CONFIG(METADATA) ? 1337daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_DYNFLAG_TX_METADATA ? 13386728fe93SBing Zhao rte_cpu_to_be_32(*RTE_FLOW_DYNF_METADATA(loc->mbuf)) : 13396728fe93SBing Zhao 0 : 0; 1340256fb0e3SMichael Baum MLX5_ASSERT(inlen >= MLX5_ESEG_MIN_INLINE_SIZE); 1341256fb0e3SMichael Baum pdst = (uint8_t *)&es->inline_data; 1342256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && vlan) { 1343256fb0e3SMichael Baum /* Implement VLAN tag insertion as part inline data. */ 1344256fb0e3SMichael Baum mlx5_tx_mseg_memcpy(pdst, loc, 1345256fb0e3SMichael Baum 2 * RTE_ETHER_ADDR_LEN, 1346256fb0e3SMichael Baum 2 * RTE_ETHER_ADDR_LEN, olx); 1347256fb0e3SMichael Baum pdst += 2 * RTE_ETHER_ADDR_LEN; 1348256fb0e3SMichael Baum *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32 1349256fb0e3SMichael Baum ((RTE_ETHER_TYPE_VLAN << 16) | 1350256fb0e3SMichael Baum loc->mbuf->vlan_tci); 1351256fb0e3SMichael Baum pdst += sizeof(struct rte_vlan_hdr); 1352256fb0e3SMichael Baum tlen += 2 * RTE_ETHER_ADDR_LEN + sizeof(struct rte_vlan_hdr); 1353256fb0e3SMichael Baum } 1354256fb0e3SMichael Baum MLX5_ASSERT(pdst < (uint8_t *)txq->wqes_end); 1355256fb0e3SMichael Baum /* 1356256fb0e3SMichael Baum * The WQEBB space availability is checked by caller. 1357256fb0e3SMichael Baum * Here we should be aware of WQE ring buffer wraparound only. 1358256fb0e3SMichael Baum */ 1359256fb0e3SMichael Baum part = (uint8_t *)txq->wqes_end - pdst; 1360256fb0e3SMichael Baum part = RTE_MIN(part, inlen - tlen); 1361256fb0e3SMichael Baum MLX5_ASSERT(part); 1362256fb0e3SMichael Baum do { 1363256fb0e3SMichael Baum unsigned int copy; 1364256fb0e3SMichael Baum 1365256fb0e3SMichael Baum /* 1366256fb0e3SMichael Baum * Copying may be interrupted inside the routine 1367256fb0e3SMichael Baum * if run into no inline hint flag. 1368256fb0e3SMichael Baum */ 136952e1ece5SViacheslav Ovsiienko copy = tso ? inlen : txq->inlen_mode; 137052e1ece5SViacheslav Ovsiienko copy = tlen >= copy ? 0 : (copy - tlen); 1371256fb0e3SMichael Baum copy = mlx5_tx_mseg_memcpy(pdst, loc, part, copy, olx); 1372256fb0e3SMichael Baum tlen += copy; 1373256fb0e3SMichael Baum if (likely(inlen <= tlen) || copy < part) { 1374256fb0e3SMichael Baum es->inline_hdr_sz = rte_cpu_to_be_16(tlen); 1375256fb0e3SMichael Baum pdst += copy; 1376256fb0e3SMichael Baum pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE); 1377256fb0e3SMichael Baum return (struct mlx5_wqe_dseg *)pdst; 1378256fb0e3SMichael Baum } 1379256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1380256fb0e3SMichael Baum part = inlen - tlen; 1381256fb0e3SMichael Baum } while (true); 1382256fb0e3SMichael Baum } 1383256fb0e3SMichael Baum 1384256fb0e3SMichael Baum /** 1385256fb0e3SMichael Baum * Build the Data Segment of pointer type. 1386256fb0e3SMichael Baum * 1387256fb0e3SMichael Baum * @param txq 1388256fb0e3SMichael Baum * Pointer to TX queue structure. 1389256fb0e3SMichael Baum * @param loc 1390256fb0e3SMichael Baum * Pointer to burst routine local context. 1391256fb0e3SMichael Baum * @param dseg 1392256fb0e3SMichael Baum * Pointer to WQE to fill with built Data Segment. 1393256fb0e3SMichael Baum * @param buf 1394256fb0e3SMichael Baum * Data buffer to point. 1395256fb0e3SMichael Baum * @param len 1396256fb0e3SMichael Baum * Data buffer length. 1397256fb0e3SMichael Baum * @param olx 1398256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1399256fb0e3SMichael Baum * compile time and may be used for optimization. 1400256fb0e3SMichael Baum */ 1401256fb0e3SMichael Baum static __rte_always_inline void 1402256fb0e3SMichael Baum mlx5_tx_dseg_ptr(struct mlx5_txq_data *__rte_restrict txq, 1403256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1404256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg, 1405256fb0e3SMichael Baum uint8_t *buf, 1406256fb0e3SMichael Baum unsigned int len, 1407256fb0e3SMichael Baum unsigned int olx __rte_unused) 1408256fb0e3SMichael Baum 1409256fb0e3SMichael Baum { 1410256fb0e3SMichael Baum MLX5_ASSERT(len); 1411256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32(len); 141220489176SMichael Baum dseg->lkey = mlx5_mr_mb2mr(&txq->mr_ctrl, loc->mbuf); 1413256fb0e3SMichael Baum dseg->pbuf = rte_cpu_to_be_64((uintptr_t)buf); 1414256fb0e3SMichael Baum } 1415256fb0e3SMichael Baum 1416256fb0e3SMichael Baum /** 1417256fb0e3SMichael Baum * Build the Data Segment of pointer type or inline if data length is less than 1418256fb0e3SMichael Baum * buffer in minimal Data Segment size. 1419256fb0e3SMichael Baum * 1420256fb0e3SMichael Baum * @param txq 1421256fb0e3SMichael Baum * Pointer to TX queue structure. 1422256fb0e3SMichael Baum * @param loc 1423256fb0e3SMichael Baum * Pointer to burst routine local context. 1424256fb0e3SMichael Baum * @param dseg 1425256fb0e3SMichael Baum * Pointer to WQE to fill with built Data Segment. 1426256fb0e3SMichael Baum * @param buf 1427256fb0e3SMichael Baum * Data buffer to point. 1428256fb0e3SMichael Baum * @param len 1429256fb0e3SMichael Baum * Data buffer length. 1430256fb0e3SMichael Baum * @param olx 1431256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1432256fb0e3SMichael Baum * compile time and may be used for optimization. 1433256fb0e3SMichael Baum */ 1434256fb0e3SMichael Baum static __rte_always_inline void 1435256fb0e3SMichael Baum mlx5_tx_dseg_iptr(struct mlx5_txq_data *__rte_restrict txq, 1436256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1437256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg, 1438256fb0e3SMichael Baum uint8_t *buf, 1439256fb0e3SMichael Baum unsigned int len, 1440256fb0e3SMichael Baum unsigned int olx __rte_unused) 1441256fb0e3SMichael Baum 1442256fb0e3SMichael Baum { 1443256fb0e3SMichael Baum uintptr_t dst, src; 1444256fb0e3SMichael Baum 1445256fb0e3SMichael Baum MLX5_ASSERT(len); 1446256fb0e3SMichael Baum if (len > MLX5_DSEG_MIN_INLINE_SIZE) { 1447256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32(len); 144820489176SMichael Baum dseg->lkey = mlx5_mr_mb2mr(&txq->mr_ctrl, loc->mbuf); 1449256fb0e3SMichael Baum dseg->pbuf = rte_cpu_to_be_64((uintptr_t)buf); 1450256fb0e3SMichael Baum 1451256fb0e3SMichael Baum return; 1452256fb0e3SMichael Baum } 1453256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32(len | MLX5_ETH_WQE_DATA_INLINE); 1454256fb0e3SMichael Baum /* Unrolled implementation of generic rte_memcpy. */ 1455256fb0e3SMichael Baum dst = (uintptr_t)&dseg->inline_data[0]; 1456256fb0e3SMichael Baum src = (uintptr_t)buf; 1457256fb0e3SMichael Baum if (len & 0x08) { 1458256fb0e3SMichael Baum #ifdef RTE_ARCH_STRICT_ALIGN 1459256fb0e3SMichael Baum MLX5_ASSERT(dst == RTE_PTR_ALIGN(dst, sizeof(uint32_t))); 1460256fb0e3SMichael Baum *(uint32_t *)dst = *(unaligned_uint32_t *)src; 1461256fb0e3SMichael Baum dst += sizeof(uint32_t); 1462256fb0e3SMichael Baum src += sizeof(uint32_t); 1463256fb0e3SMichael Baum *(uint32_t *)dst = *(unaligned_uint32_t *)src; 1464256fb0e3SMichael Baum dst += sizeof(uint32_t); 1465256fb0e3SMichael Baum src += sizeof(uint32_t); 1466256fb0e3SMichael Baum #else 1467256fb0e3SMichael Baum *(uint64_t *)dst = *(unaligned_uint64_t *)src; 1468256fb0e3SMichael Baum dst += sizeof(uint64_t); 1469256fb0e3SMichael Baum src += sizeof(uint64_t); 1470256fb0e3SMichael Baum #endif 1471256fb0e3SMichael Baum } 1472256fb0e3SMichael Baum if (len & 0x04) { 1473256fb0e3SMichael Baum *(uint32_t *)dst = *(unaligned_uint32_t *)src; 1474256fb0e3SMichael Baum dst += sizeof(uint32_t); 1475256fb0e3SMichael Baum src += sizeof(uint32_t); 1476256fb0e3SMichael Baum } 1477256fb0e3SMichael Baum if (len & 0x02) { 1478256fb0e3SMichael Baum *(uint16_t *)dst = *(unaligned_uint16_t *)src; 1479256fb0e3SMichael Baum dst += sizeof(uint16_t); 1480256fb0e3SMichael Baum src += sizeof(uint16_t); 1481256fb0e3SMichael Baum } 1482256fb0e3SMichael Baum if (len & 0x01) 1483256fb0e3SMichael Baum *(uint8_t *)dst = *(uint8_t *)src; 1484256fb0e3SMichael Baum } 1485256fb0e3SMichael Baum 1486256fb0e3SMichael Baum /** 1487256fb0e3SMichael Baum * Build the Data Segment of inlined data from single 1488256fb0e3SMichael Baum * segment packet, no VLAN insertion. 1489256fb0e3SMichael Baum * 1490256fb0e3SMichael Baum * @param txq 1491256fb0e3SMichael Baum * Pointer to TX queue structure. 1492256fb0e3SMichael Baum * @param loc 1493256fb0e3SMichael Baum * Pointer to burst routine local context. 1494256fb0e3SMichael Baum * @param dseg 1495256fb0e3SMichael Baum * Pointer to WQE to fill with built Data Segment. 1496256fb0e3SMichael Baum * @param buf 1497256fb0e3SMichael Baum * Data buffer to point. 1498256fb0e3SMichael Baum * @param len 1499256fb0e3SMichael Baum * Data buffer length. 1500256fb0e3SMichael Baum * @param olx 1501256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1502256fb0e3SMichael Baum * compile time and may be used for optimization. 1503256fb0e3SMichael Baum * 1504256fb0e3SMichael Baum * @return 1505256fb0e3SMichael Baum * Pointer to the next Data Segment after inlined data. 1506256fb0e3SMichael Baum * Ring buffer wraparound check is needed. We do not do it here because it 1507256fb0e3SMichael Baum * may not be needed for the last packet in the eMPW session. 1508256fb0e3SMichael Baum */ 1509256fb0e3SMichael Baum static __rte_always_inline struct mlx5_wqe_dseg * 1510256fb0e3SMichael Baum mlx5_tx_dseg_empw(struct mlx5_txq_data *__rte_restrict txq, 1511256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc __rte_unused, 1512256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg, 1513256fb0e3SMichael Baum uint8_t *buf, 1514256fb0e3SMichael Baum unsigned int len, 1515256fb0e3SMichael Baum unsigned int olx __rte_unused) 1516256fb0e3SMichael Baum { 1517256fb0e3SMichael Baum unsigned int part; 1518256fb0e3SMichael Baum uint8_t *pdst; 1519256fb0e3SMichael Baum 1520256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MPW)) { 1521256fb0e3SMichael Baum /* Store the descriptor byte counter for eMPW sessions. */ 1522256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32(len | MLX5_ETH_WQE_DATA_INLINE); 1523256fb0e3SMichael Baum pdst = &dseg->inline_data[0]; 1524256fb0e3SMichael Baum } else { 1525256fb0e3SMichael Baum /* The entire legacy MPW session counter is stored on close. */ 1526256fb0e3SMichael Baum pdst = (uint8_t *)dseg; 1527256fb0e3SMichael Baum } 1528256fb0e3SMichael Baum /* 1529256fb0e3SMichael Baum * The WQEBB space availability is checked by caller. 1530256fb0e3SMichael Baum * Here we should be aware of WQE ring buffer wraparound only. 1531256fb0e3SMichael Baum */ 1532256fb0e3SMichael Baum part = (uint8_t *)txq->wqes_end - pdst; 1533256fb0e3SMichael Baum part = RTE_MIN(part, len); 1534256fb0e3SMichael Baum do { 1535256fb0e3SMichael Baum rte_memcpy(pdst, buf, part); 1536256fb0e3SMichael Baum len -= part; 1537256fb0e3SMichael Baum if (likely(!len)) { 1538256fb0e3SMichael Baum pdst += part; 1539256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MPW)) 1540256fb0e3SMichael Baum pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE); 1541256fb0e3SMichael Baum /* Note: no final wraparound check here. */ 1542256fb0e3SMichael Baum return (struct mlx5_wqe_dseg *)pdst; 1543256fb0e3SMichael Baum } 1544256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1545256fb0e3SMichael Baum buf += part; 1546256fb0e3SMichael Baum part = len; 1547256fb0e3SMichael Baum } while (true); 1548256fb0e3SMichael Baum } 1549256fb0e3SMichael Baum 1550256fb0e3SMichael Baum /** 1551256fb0e3SMichael Baum * Build the Data Segment of inlined data from single 1552256fb0e3SMichael Baum * segment packet with VLAN insertion. 1553256fb0e3SMichael Baum * 1554256fb0e3SMichael Baum * @param txq 1555256fb0e3SMichael Baum * Pointer to TX queue structure. 1556256fb0e3SMichael Baum * @param loc 1557256fb0e3SMichael Baum * Pointer to burst routine local context. 1558256fb0e3SMichael Baum * @param dseg 1559256fb0e3SMichael Baum * Pointer to the dseg fill with built Data Segment. 1560256fb0e3SMichael Baum * @param buf 1561256fb0e3SMichael Baum * Data buffer to point. 1562256fb0e3SMichael Baum * @param len 1563256fb0e3SMichael Baum * Data buffer length. 1564256fb0e3SMichael Baum * @param olx 1565256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1566256fb0e3SMichael Baum * compile time and may be used for optimization. 1567256fb0e3SMichael Baum * 1568256fb0e3SMichael Baum * @return 1569256fb0e3SMichael Baum * Pointer to the next Data Segment after inlined data. 1570256fb0e3SMichael Baum * Ring buffer wraparound check is needed. 1571256fb0e3SMichael Baum */ 1572256fb0e3SMichael Baum static __rte_always_inline struct mlx5_wqe_dseg * 1573256fb0e3SMichael Baum mlx5_tx_dseg_vlan(struct mlx5_txq_data *__rte_restrict txq, 1574256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc __rte_unused, 1575256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg, 1576256fb0e3SMichael Baum uint8_t *buf, 1577256fb0e3SMichael Baum unsigned int len, 1578256fb0e3SMichael Baum unsigned int olx __rte_unused) 1579256fb0e3SMichael Baum 1580256fb0e3SMichael Baum { 1581256fb0e3SMichael Baum unsigned int part; 1582256fb0e3SMichael Baum uint8_t *pdst; 1583256fb0e3SMichael Baum 1584256fb0e3SMichael Baum MLX5_ASSERT(len > MLX5_ESEG_MIN_INLINE_SIZE); 1585256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MPW)) { 1586256fb0e3SMichael Baum /* Store the descriptor byte counter for eMPW sessions. */ 1587256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32 1588256fb0e3SMichael Baum ((len + sizeof(struct rte_vlan_hdr)) | 1589256fb0e3SMichael Baum MLX5_ETH_WQE_DATA_INLINE); 1590256fb0e3SMichael Baum pdst = &dseg->inline_data[0]; 1591256fb0e3SMichael Baum } else { 1592256fb0e3SMichael Baum /* The entire legacy MPW session counter is stored on close. */ 1593256fb0e3SMichael Baum pdst = (uint8_t *)dseg; 1594256fb0e3SMichael Baum } 1595256fb0e3SMichael Baum memcpy(pdst, buf, MLX5_DSEG_MIN_INLINE_SIZE); 1596256fb0e3SMichael Baum buf += MLX5_DSEG_MIN_INLINE_SIZE; 1597256fb0e3SMichael Baum pdst += MLX5_DSEG_MIN_INLINE_SIZE; 1598256fb0e3SMichael Baum len -= MLX5_DSEG_MIN_INLINE_SIZE; 1599256fb0e3SMichael Baum /* Insert VLAN ethertype + VLAN tag. Pointer is aligned. */ 1600256fb0e3SMichael Baum MLX5_ASSERT(pdst == RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE)); 1601256fb0e3SMichael Baum if (unlikely(pdst >= (uint8_t *)txq->wqes_end)) 1602256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1603256fb0e3SMichael Baum *(uint32_t *)pdst = rte_cpu_to_be_32((RTE_ETHER_TYPE_VLAN << 16) | 1604256fb0e3SMichael Baum loc->mbuf->vlan_tci); 1605256fb0e3SMichael Baum pdst += sizeof(struct rte_vlan_hdr); 1606256fb0e3SMichael Baum /* 1607256fb0e3SMichael Baum * The WQEBB space availability is checked by caller. 1608256fb0e3SMichael Baum * Here we should be aware of WQE ring buffer wraparound only. 1609256fb0e3SMichael Baum */ 1610256fb0e3SMichael Baum part = (uint8_t *)txq->wqes_end - pdst; 1611256fb0e3SMichael Baum part = RTE_MIN(part, len); 1612256fb0e3SMichael Baum do { 1613256fb0e3SMichael Baum rte_memcpy(pdst, buf, part); 1614256fb0e3SMichael Baum len -= part; 1615256fb0e3SMichael Baum if (likely(!len)) { 1616256fb0e3SMichael Baum pdst += part; 1617256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MPW)) 1618256fb0e3SMichael Baum pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE); 1619256fb0e3SMichael Baum /* Note: no final wraparound check here. */ 1620256fb0e3SMichael Baum return (struct mlx5_wqe_dseg *)pdst; 1621256fb0e3SMichael Baum } 1622256fb0e3SMichael Baum pdst = (uint8_t *)txq->wqes; 1623256fb0e3SMichael Baum buf += part; 1624256fb0e3SMichael Baum part = len; 1625256fb0e3SMichael Baum } while (true); 1626256fb0e3SMichael Baum } 1627256fb0e3SMichael Baum 1628256fb0e3SMichael Baum /** 1629256fb0e3SMichael Baum * Build the Ethernet Segment with optionally inlined data with 1630256fb0e3SMichael Baum * VLAN insertion and following Data Segments (if any) from 1631256fb0e3SMichael Baum * multi-segment packet. Used by ordinary send and TSO. 1632256fb0e3SMichael Baum * 1633256fb0e3SMichael Baum * @param txq 1634256fb0e3SMichael Baum * Pointer to TX queue structure. 1635256fb0e3SMichael Baum * @param loc 1636256fb0e3SMichael Baum * Pointer to burst routine local context. 1637256fb0e3SMichael Baum * @param wqe 1638256fb0e3SMichael Baum * Pointer to WQE to fill with built Ethernet/Data Segments. 1639256fb0e3SMichael Baum * @param vlan 1640256fb0e3SMichael Baum * Length of VLAN header to insert, 0 means no VLAN insertion. 1641256fb0e3SMichael Baum * @param inlen 1642256fb0e3SMichael Baum * Data length to inline. For TSO this parameter specifies exact value, 1643256fb0e3SMichael Baum * for ordinary send routine can be aligned by caller to provide better WQE 1644256fb0e3SMichael Baum * space saving and data buffer start address alignment. 1645256fb0e3SMichael Baum * This length includes VLAN header being inserted. 1646256fb0e3SMichael Baum * @param tso 1647256fb0e3SMichael Baum * Zero means ordinary send, inlined data can be extended, 1648256fb0e3SMichael Baum * otherwise this is TSO, inlined data length is fixed. 1649256fb0e3SMichael Baum * @param olx 1650256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1651256fb0e3SMichael Baum * compile time and may be used for optimization. 1652256fb0e3SMichael Baum * 1653256fb0e3SMichael Baum * @return 1654256fb0e3SMichael Baum * Actual size of built WQE in segments. 1655256fb0e3SMichael Baum */ 1656256fb0e3SMichael Baum static __rte_always_inline unsigned int 1657256fb0e3SMichael Baum mlx5_tx_mseg_build(struct mlx5_txq_data *__rte_restrict txq, 1658256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1659256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe, 1660256fb0e3SMichael Baum unsigned int vlan, 1661256fb0e3SMichael Baum unsigned int inlen, 1662256fb0e3SMichael Baum unsigned int tso, 1663256fb0e3SMichael Baum unsigned int olx __rte_unused) 1664256fb0e3SMichael Baum { 1665256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 1666256fb0e3SMichael Baum unsigned int ds; 1667256fb0e3SMichael Baum 1668256fb0e3SMichael Baum MLX5_ASSERT((rte_pktmbuf_pkt_len(loc->mbuf) + vlan) >= inlen); 1669256fb0e3SMichael Baum loc->mbuf_nseg = NB_SEGS(loc->mbuf); 1670256fb0e3SMichael Baum loc->mbuf_off = 0; 1671256fb0e3SMichael Baum 1672256fb0e3SMichael Baum dseg = mlx5_tx_eseg_mdat(txq, loc, wqe, vlan, inlen, tso, olx); 1673256fb0e3SMichael Baum if (!loc->mbuf_nseg) 1674256fb0e3SMichael Baum goto dseg_done; 1675256fb0e3SMichael Baum /* 1676256fb0e3SMichael Baum * There are still some mbuf remaining, not inlined. 1677256fb0e3SMichael Baum * The first mbuf may be partially inlined and we 1678256fb0e3SMichael Baum * must process the possible non-zero data offset. 1679256fb0e3SMichael Baum */ 1680256fb0e3SMichael Baum if (loc->mbuf_off) { 1681256fb0e3SMichael Baum unsigned int dlen; 1682256fb0e3SMichael Baum uint8_t *dptr; 1683256fb0e3SMichael Baum 1684256fb0e3SMichael Baum /* 1685256fb0e3SMichael Baum * Exhausted packets must be dropped before. 1686256fb0e3SMichael Baum * Non-zero offset means there are some data 1687256fb0e3SMichael Baum * remained in the packet. 1688256fb0e3SMichael Baum */ 1689256fb0e3SMichael Baum MLX5_ASSERT(loc->mbuf_off < rte_pktmbuf_data_len(loc->mbuf)); 1690256fb0e3SMichael Baum MLX5_ASSERT(rte_pktmbuf_data_len(loc->mbuf)); 1691256fb0e3SMichael Baum dptr = rte_pktmbuf_mtod_offset(loc->mbuf, uint8_t *, 1692256fb0e3SMichael Baum loc->mbuf_off); 1693256fb0e3SMichael Baum dlen = rte_pktmbuf_data_len(loc->mbuf) - loc->mbuf_off; 1694256fb0e3SMichael Baum /* 1695256fb0e3SMichael Baum * Build the pointer/minimal Data Segment. 1696256fb0e3SMichael Baum * Do ring buffer wrapping check in advance. 1697256fb0e3SMichael Baum */ 1698256fb0e3SMichael Baum if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end) 1699256fb0e3SMichael Baum dseg = (struct mlx5_wqe_dseg *)txq->wqes; 1700256fb0e3SMichael Baum mlx5_tx_dseg_iptr(txq, loc, dseg, dptr, dlen, olx); 1701256fb0e3SMichael Baum /* Store the mbuf to be freed on completion. */ 1702256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free); 1703256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 1704256fb0e3SMichael Baum --loc->elts_free; 1705256fb0e3SMichael Baum ++dseg; 1706256fb0e3SMichael Baum if (--loc->mbuf_nseg == 0) 1707256fb0e3SMichael Baum goto dseg_done; 1708256fb0e3SMichael Baum loc->mbuf = loc->mbuf->next; 1709256fb0e3SMichael Baum loc->mbuf_off = 0; 1710256fb0e3SMichael Baum } 1711256fb0e3SMichael Baum do { 1712256fb0e3SMichael Baum if (unlikely(!rte_pktmbuf_data_len(loc->mbuf))) { 1713256fb0e3SMichael Baum struct rte_mbuf *mbuf; 1714256fb0e3SMichael Baum 1715256fb0e3SMichael Baum /* Zero length segment found, just skip. */ 1716256fb0e3SMichael Baum mbuf = loc->mbuf; 1717256fb0e3SMichael Baum loc->mbuf = loc->mbuf->next; 1718256fb0e3SMichael Baum rte_pktmbuf_free_seg(mbuf); 1719256fb0e3SMichael Baum if (--loc->mbuf_nseg == 0) 1720256fb0e3SMichael Baum break; 1721256fb0e3SMichael Baum } else { 1722256fb0e3SMichael Baum if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end) 1723256fb0e3SMichael Baum dseg = (struct mlx5_wqe_dseg *)txq->wqes; 1724256fb0e3SMichael Baum mlx5_tx_dseg_iptr 1725256fb0e3SMichael Baum (txq, loc, dseg, 1726256fb0e3SMichael Baum rte_pktmbuf_mtod(loc->mbuf, uint8_t *), 1727256fb0e3SMichael Baum rte_pktmbuf_data_len(loc->mbuf), olx); 1728256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free); 1729256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 1730256fb0e3SMichael Baum --loc->elts_free; 1731256fb0e3SMichael Baum ++dseg; 1732256fb0e3SMichael Baum if (--loc->mbuf_nseg == 0) 1733256fb0e3SMichael Baum break; 1734256fb0e3SMichael Baum loc->mbuf = loc->mbuf->next; 1735256fb0e3SMichael Baum } 1736256fb0e3SMichael Baum } while (true); 1737256fb0e3SMichael Baum 1738256fb0e3SMichael Baum dseg_done: 1739256fb0e3SMichael Baum /* Calculate actual segments used from the dseg pointer. */ 1740256fb0e3SMichael Baum if ((uintptr_t)wqe < (uintptr_t)dseg) 1741256fb0e3SMichael Baum ds = ((uintptr_t)dseg - (uintptr_t)wqe) / MLX5_WSEG_SIZE; 1742256fb0e3SMichael Baum else 1743256fb0e3SMichael Baum ds = (((uintptr_t)dseg - (uintptr_t)wqe) + 1744256fb0e3SMichael Baum txq->wqe_s * MLX5_WQE_SIZE) / MLX5_WSEG_SIZE; 1745256fb0e3SMichael Baum return ds; 1746256fb0e3SMichael Baum } 1747256fb0e3SMichael Baum 1748256fb0e3SMichael Baum /** 1749256fb0e3SMichael Baum * The routine checks timestamp flag in the current packet, 1750256fb0e3SMichael Baum * and push WAIT WQE into the queue if scheduling is required. 1751256fb0e3SMichael Baum * 1752256fb0e3SMichael Baum * @param txq 1753256fb0e3SMichael Baum * Pointer to TX queue structure. 1754256fb0e3SMichael Baum * @param loc 1755256fb0e3SMichael Baum * Pointer to burst routine local context. 175637d6fc30SViacheslav Ovsiienko * @param elts 175737d6fc30SViacheslav Ovsiienko * Number of free elements in elts buffer to be checked, for zero 175837d6fc30SViacheslav Ovsiienko * value the check is optimized out by compiler. 1759256fb0e3SMichael Baum * @param olx 1760256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1761256fb0e3SMichael Baum * compile time and may be used for optimization. 1762256fb0e3SMichael Baum * 1763256fb0e3SMichael Baum * @return 1764256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 1765256fb0e3SMichael Baum * MLX5_TXCMP_CODE_SINGLE - continue processing with the packet. 1766256fb0e3SMichael Baum * MLX5_TXCMP_CODE_MULTI - the WAIT inserted, continue processing. 1767256fb0e3SMichael Baum * Local context variables partially updated. 1768256fb0e3SMichael Baum */ 1769256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 1770256fb0e3SMichael Baum mlx5_tx_schedule_send(struct mlx5_txq_data *restrict txq, 1771256fb0e3SMichael Baum struct mlx5_txq_local *restrict loc, 177237d6fc30SViacheslav Ovsiienko uint16_t elts, 1773256fb0e3SMichael Baum unsigned int olx) 1774256fb0e3SMichael Baum { 1775256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP) && 1776256fb0e3SMichael Baum loc->mbuf->ol_flags & txq->ts_mask) { 177749e87976SViacheslav Ovsiienko struct mlx5_dev_ctx_shared *sh; 1778256fb0e3SMichael Baum struct mlx5_wqe *wqe; 1779256fb0e3SMichael Baum uint64_t ts; 1780256fb0e3SMichael Baum 1781256fb0e3SMichael Baum /* 1782256fb0e3SMichael Baum * Estimate the required space quickly and roughly. 1783256fb0e3SMichael Baum * We would like to ensure the packet can be pushed 1784256fb0e3SMichael Baum * to the queue and we won't get the orphan WAIT WQE. 1785256fb0e3SMichael Baum */ 1786256fb0e3SMichael Baum if (loc->wqe_free <= MLX5_WQE_SIZE_MAX / MLX5_WQE_SIZE || 178737d6fc30SViacheslav Ovsiienko loc->elts_free < elts) 1788256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 1789256fb0e3SMichael Baum /* Convert the timestamp into completion to wait. */ 1790256fb0e3SMichael Baum ts = *RTE_MBUF_DYNFIELD(loc->mbuf, txq->ts_offset, uint64_t *); 1791a31aa37bSViacheslav Ovsiienko if (txq->ts_last && ts < txq->ts_last) 1792e12a0166STyler Retzlaff rte_atomic_fetch_add_explicit(&txq->sh->txpp.err_ts_order, 1793e12a0166STyler Retzlaff 1, rte_memory_order_relaxed); 1794a31aa37bSViacheslav Ovsiienko txq->ts_last = ts; 179549e87976SViacheslav Ovsiienko wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 179649e87976SViacheslav Ovsiienko sh = txq->sh; 179749e87976SViacheslav Ovsiienko if (txq->wait_on_time) { 179849e87976SViacheslav Ovsiienko /* The wait on time capability should be used. */ 179949e87976SViacheslav Ovsiienko ts -= sh->txpp.skew; 1800a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_wait(ts); 180149e87976SViacheslav Ovsiienko mlx5_tx_cseg_init(txq, loc, wqe, 180249e87976SViacheslav Ovsiienko 1 + sizeof(struct mlx5_wqe_wseg) / 180349e87976SViacheslav Ovsiienko MLX5_WSEG_SIZE, 180449e87976SViacheslav Ovsiienko MLX5_OPCODE_WAIT | 180549e87976SViacheslav Ovsiienko MLX5_OPC_MOD_WAIT_TIME << 24, olx); 180649e87976SViacheslav Ovsiienko mlx5_tx_wseg_init(txq, loc, wqe, ts, olx); 180749e87976SViacheslav Ovsiienko } else { 180849e87976SViacheslav Ovsiienko /* Legacy cross-channel operation should be used. */ 180949e87976SViacheslav Ovsiienko int32_t wci; 181049e87976SViacheslav Ovsiienko 181149e87976SViacheslav Ovsiienko wci = mlx5_txpp_convert_tx_ts(sh, ts); 1812256fb0e3SMichael Baum if (unlikely(wci < 0)) 1813256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 1814256fb0e3SMichael Baum /* Build the WAIT WQE with specified completion. */ 1815a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_wait(ts - sh->txpp.skew); 181649e87976SViacheslav Ovsiienko mlx5_tx_cseg_init(txq, loc, wqe, 181749e87976SViacheslav Ovsiienko 1 + sizeof(struct mlx5_wqe_qseg) / 181849e87976SViacheslav Ovsiienko MLX5_WSEG_SIZE, 181949e87976SViacheslav Ovsiienko MLX5_OPCODE_WAIT | 182049e87976SViacheslav Ovsiienko MLX5_OPC_MOD_WAIT_CQ_PI << 24, olx); 182149e87976SViacheslav Ovsiienko mlx5_tx_qseg_init(txq, loc, wqe, wci, olx); 182249e87976SViacheslav Ovsiienko } 1823256fb0e3SMichael Baum ++txq->wqe_ci; 1824256fb0e3SMichael Baum --loc->wqe_free; 1825256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 1826256fb0e3SMichael Baum } 1827256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 1828256fb0e3SMichael Baum } 1829256fb0e3SMichael Baum 1830256fb0e3SMichael Baum /** 1831256fb0e3SMichael Baum * Tx one packet function for multi-segment TSO. Supports all 1832256fb0e3SMichael Baum * types of Tx offloads, uses MLX5_OPCODE_TSO to build WQEs, 1833256fb0e3SMichael Baum * sends one packet per WQE. 1834256fb0e3SMichael Baum * 1835256fb0e3SMichael Baum * This routine is responsible for storing processed mbuf 1836256fb0e3SMichael Baum * into elts ring buffer and update elts_head. 1837256fb0e3SMichael Baum * 1838256fb0e3SMichael Baum * @param txq 1839256fb0e3SMichael Baum * Pointer to TX queue structure. 1840256fb0e3SMichael Baum * @param loc 1841256fb0e3SMichael Baum * Pointer to burst routine local context. 1842256fb0e3SMichael Baum * @param olx 1843256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1844256fb0e3SMichael Baum * compile time and may be used for optimization. 1845256fb0e3SMichael Baum * 1846256fb0e3SMichael Baum * @return 1847256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 1848256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 1849256fb0e3SMichael Baum * Local context variables partially updated. 1850256fb0e3SMichael Baum */ 1851256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 1852256fb0e3SMichael Baum mlx5_tx_packet_multi_tso(struct mlx5_txq_data *__rte_restrict txq, 1853256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1854256fb0e3SMichael Baum unsigned int olx) 1855256fb0e3SMichael Baum { 1856256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe; 1857256fb0e3SMichael Baum unsigned int ds, dlen, inlen, ntcp, vlan = 0; 1858256fb0e3SMichael Baum 185937d6fc30SViacheslav Ovsiienko MLX5_ASSERT(loc->elts_free >= NB_SEGS(loc->mbuf)); 1860256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP)) { 1861256fb0e3SMichael Baum enum mlx5_txcmp_code wret; 1862256fb0e3SMichael Baum 1863256fb0e3SMichael Baum /* Generate WAIT for scheduling if requested. */ 186437d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 0, olx); 1865256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_EXIT) 1866256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 1867256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_ERROR) 1868256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1869256fb0e3SMichael Baum } 1870256fb0e3SMichael Baum /* 1871256fb0e3SMichael Baum * Calculate data length to be inlined to estimate 1872256fb0e3SMichael Baum * the required space in WQE ring buffer. 1873256fb0e3SMichael Baum */ 1874256fb0e3SMichael Baum dlen = rte_pktmbuf_pkt_len(loc->mbuf); 1875daa02b5cSOlivier Matz if (MLX5_TXOFF_CONFIG(VLAN) && loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) 1876256fb0e3SMichael Baum vlan = sizeof(struct rte_vlan_hdr); 1877256fb0e3SMichael Baum inlen = loc->mbuf->l2_len + vlan + 1878256fb0e3SMichael Baum loc->mbuf->l3_len + loc->mbuf->l4_len; 1879256fb0e3SMichael Baum if (unlikely((!inlen || !loc->mbuf->tso_segsz))) 1880256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1881daa02b5cSOlivier Matz if (loc->mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) 1882256fb0e3SMichael Baum inlen += loc->mbuf->outer_l2_len + loc->mbuf->outer_l3_len; 1883256fb0e3SMichael Baum /* Packet must contain all TSO headers. */ 1884256fb0e3SMichael Baum if (unlikely(inlen > MLX5_MAX_TSO_HEADER || 1885256fb0e3SMichael Baum inlen <= MLX5_ESEG_MIN_INLINE_SIZE || 1886256fb0e3SMichael Baum inlen > (dlen + vlan))) 1887256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1888256fb0e3SMichael Baum /* 1889256fb0e3SMichael Baum * Check whether there are enough free WQEBBs: 1890256fb0e3SMichael Baum * - Control Segment 1891256fb0e3SMichael Baum * - Ethernet Segment 1892256fb0e3SMichael Baum * - First Segment of inlined Ethernet data 1893256fb0e3SMichael Baum * - ... data continued ... 1894256fb0e3SMichael Baum * - Data Segments of pointer/min inline type 1895256fb0e3SMichael Baum */ 1896256fb0e3SMichael Baum ds = NB_SEGS(loc->mbuf) + 2 + (inlen - 1897256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE + 1898256fb0e3SMichael Baum MLX5_WSEG_SIZE + 1899256fb0e3SMichael Baum MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 1900256fb0e3SMichael Baum if (unlikely(loc->wqe_free < ((ds + 3) / 4))) 1901256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 1902256fb0e3SMichael Baum /* Check for maximal WQE size. */ 1903130bb7daSRaja Zidane if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ds)) 1904256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1905256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1906256fb0e3SMichael Baum /* Update sent data bytes/packets counters. */ 1907256fb0e3SMichael Baum ntcp = (dlen - (inlen - vlan) + loc->mbuf->tso_segsz - 1) / 1908256fb0e3SMichael Baum loc->mbuf->tso_segsz; 1909256fb0e3SMichael Baum /* 1910256fb0e3SMichael Baum * One will be added for mbuf itself at the end of the mlx5_tx_burst 1911256fb0e3SMichael Baum * from loc->pkts_sent field. 1912256fb0e3SMichael Baum */ 1913256fb0e3SMichael Baum --ntcp; 1914256fb0e3SMichael Baum txq->stats.opackets += ntcp; 1915256fb0e3SMichael Baum txq->stats.obytes += dlen + vlan + ntcp * inlen; 1916256fb0e3SMichael Baum #endif 1917256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 1918256fb0e3SMichael Baum loc->wqe_last = wqe; 1919256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, 0, MLX5_OPCODE_TSO, olx); 1920a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 1921256fb0e3SMichael Baum ds = mlx5_tx_mseg_build(txq, loc, wqe, vlan, inlen, 1, olx); 1922256fb0e3SMichael Baum wqe->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds); 1923256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 1924256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 1925256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 1926256fb0e3SMichael Baum } 1927256fb0e3SMichael Baum 1928256fb0e3SMichael Baum /** 1929256fb0e3SMichael Baum * Tx one packet function for multi-segment SEND. Supports all types of Tx 1930256fb0e3SMichael Baum * offloads, uses MLX5_OPCODE_SEND to build WQEs, sends one packet per WQE, 1931256fb0e3SMichael Baum * without any data inlining in Ethernet Segment. 1932256fb0e3SMichael Baum * 1933256fb0e3SMichael Baum * This routine is responsible for storing processed mbuf 1934256fb0e3SMichael Baum * into elts ring buffer and update elts_head. 1935256fb0e3SMichael Baum * 1936256fb0e3SMichael Baum * @param txq 1937256fb0e3SMichael Baum * Pointer to TX queue structure. 1938256fb0e3SMichael Baum * @param loc 1939256fb0e3SMichael Baum * Pointer to burst routine local context. 1940256fb0e3SMichael Baum * @param olx 1941256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 1942256fb0e3SMichael Baum * compile time and may be used for optimization. 1943256fb0e3SMichael Baum * 1944256fb0e3SMichael Baum * @return 1945256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 1946256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 1947256fb0e3SMichael Baum * Local context variables partially updated. 1948256fb0e3SMichael Baum */ 1949256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 1950256fb0e3SMichael Baum mlx5_tx_packet_multi_send(struct mlx5_txq_data *__rte_restrict txq, 1951256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 1952256fb0e3SMichael Baum unsigned int olx) 1953256fb0e3SMichael Baum { 1954256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 1955256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe; 1956256fb0e3SMichael Baum unsigned int ds, nseg; 1957256fb0e3SMichael Baum 1958256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) > 1); 195937d6fc30SViacheslav Ovsiienko MLX5_ASSERT(loc->elts_free >= NB_SEGS(loc->mbuf)); 1960256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP)) { 1961256fb0e3SMichael Baum enum mlx5_txcmp_code wret; 1962256fb0e3SMichael Baum 1963256fb0e3SMichael Baum /* Generate WAIT for scheduling if requested. */ 196437d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 0, olx); 1965256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_EXIT) 1966256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 1967256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_ERROR) 1968256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1969256fb0e3SMichael Baum } 1970256fb0e3SMichael Baum /* 1971256fb0e3SMichael Baum * No inline at all, it means the CPU cycles saving is prioritized at 1972256fb0e3SMichael Baum * configuration, we should not copy any packet data to WQE. 1973256fb0e3SMichael Baum */ 1974256fb0e3SMichael Baum nseg = NB_SEGS(loc->mbuf); 1975256fb0e3SMichael Baum ds = 2 + nseg; 1976256fb0e3SMichael Baum if (unlikely(loc->wqe_free < ((ds + 3) / 4))) 1977256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 1978256fb0e3SMichael Baum /* Check for maximal WQE size. */ 1979130bb7daSRaja Zidane if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ds)) 1980256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1981256fb0e3SMichael Baum /* 1982256fb0e3SMichael Baum * Some Tx offloads may cause an error if packet is not long enough, 1983256fb0e3SMichael Baum * check against assumed minimal length. 1984256fb0e3SMichael Baum */ 1985256fb0e3SMichael Baum if (rte_pktmbuf_pkt_len(loc->mbuf) <= MLX5_ESEG_MIN_INLINE_SIZE) 1986256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 1987256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1988256fb0e3SMichael Baum /* Update sent data bytes counter. */ 1989256fb0e3SMichael Baum txq->stats.obytes += rte_pktmbuf_pkt_len(loc->mbuf); 1990256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 1991daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) 1992256fb0e3SMichael Baum txq->stats.obytes += sizeof(struct rte_vlan_hdr); 1993256fb0e3SMichael Baum #endif 1994256fb0e3SMichael Baum /* 1995256fb0e3SMichael Baum * SEND WQE, one WQEBB: 1996256fb0e3SMichael Baum * - Control Segment, SEND opcode 1997256fb0e3SMichael Baum * - Ethernet Segment, optional VLAN, no inline 1998256fb0e3SMichael Baum * - Data Segments, pointer only type 1999256fb0e3SMichael Baum */ 2000256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 2001256fb0e3SMichael Baum loc->wqe_last = wqe; 2002256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, ds, MLX5_OPCODE_SEND, olx); 2003a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 2004256fb0e3SMichael Baum mlx5_tx_eseg_none(txq, loc, wqe, olx); 2005256fb0e3SMichael Baum dseg = &wqe->dseg[0]; 2006256fb0e3SMichael Baum do { 2007256fb0e3SMichael Baum if (unlikely(!rte_pktmbuf_data_len(loc->mbuf))) { 2008256fb0e3SMichael Baum struct rte_mbuf *mbuf; 2009256fb0e3SMichael Baum 2010256fb0e3SMichael Baum /* 2011256fb0e3SMichael Baum * Zero length segment found, have to correct total 2012256fb0e3SMichael Baum * size of WQE in segments. 2013256fb0e3SMichael Baum * It is supposed to be rare occasion, so in normal 2014256fb0e3SMichael Baum * case (no zero length segments) we avoid extra 2015256fb0e3SMichael Baum * writing to the Control Segment. 2016256fb0e3SMichael Baum */ 2017256fb0e3SMichael Baum --ds; 2018256fb0e3SMichael Baum wqe->cseg.sq_ds -= RTE_BE32(1); 2019256fb0e3SMichael Baum mbuf = loc->mbuf; 2020256fb0e3SMichael Baum loc->mbuf = mbuf->next; 2021256fb0e3SMichael Baum rte_pktmbuf_free_seg(mbuf); 2022256fb0e3SMichael Baum if (--nseg == 0) 2023256fb0e3SMichael Baum break; 2024256fb0e3SMichael Baum } else { 2025256fb0e3SMichael Baum mlx5_tx_dseg_ptr 2026256fb0e3SMichael Baum (txq, loc, dseg, 2027256fb0e3SMichael Baum rte_pktmbuf_mtod(loc->mbuf, uint8_t *), 2028256fb0e3SMichael Baum rte_pktmbuf_data_len(loc->mbuf), olx); 2029256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 2030256fb0e3SMichael Baum --loc->elts_free; 2031256fb0e3SMichael Baum if (--nseg == 0) 2032256fb0e3SMichael Baum break; 2033256fb0e3SMichael Baum ++dseg; 2034256fb0e3SMichael Baum if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end) 2035256fb0e3SMichael Baum dseg = (struct mlx5_wqe_dseg *)txq->wqes; 2036256fb0e3SMichael Baum loc->mbuf = loc->mbuf->next; 2037256fb0e3SMichael Baum } 2038256fb0e3SMichael Baum } while (true); 2039256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 2040256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 2041256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 2042256fb0e3SMichael Baum } 2043256fb0e3SMichael Baum 2044256fb0e3SMichael Baum /** 2045256fb0e3SMichael Baum * Tx one packet function for multi-segment SEND. Supports all 2046256fb0e3SMichael Baum * types of Tx offloads, uses MLX5_OPCODE_SEND to build WQEs, 2047256fb0e3SMichael Baum * sends one packet per WQE, with data inlining in 2048256fb0e3SMichael Baum * Ethernet Segment and minimal Data Segments. 2049256fb0e3SMichael Baum * 2050256fb0e3SMichael Baum * This routine is responsible for storing processed mbuf 2051256fb0e3SMichael Baum * into elts ring buffer and update elts_head. 2052256fb0e3SMichael Baum * 2053256fb0e3SMichael Baum * @param txq 2054256fb0e3SMichael Baum * Pointer to TX queue structure. 2055256fb0e3SMichael Baum * @param loc 2056256fb0e3SMichael Baum * Pointer to burst routine local context. 2057256fb0e3SMichael Baum * @param olx 2058256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2059256fb0e3SMichael Baum * compile time and may be used for optimization. 2060256fb0e3SMichael Baum * 2061256fb0e3SMichael Baum * @return 2062256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 2063256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 2064256fb0e3SMichael Baum * Local context variables partially updated. 2065256fb0e3SMichael Baum */ 2066256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2067256fb0e3SMichael Baum mlx5_tx_packet_multi_inline(struct mlx5_txq_data *__rte_restrict txq, 2068256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2069256fb0e3SMichael Baum unsigned int olx) 2070256fb0e3SMichael Baum { 2071256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe; 2072256fb0e3SMichael Baum unsigned int ds, inlen, dlen, vlan = 0; 2073256fb0e3SMichael Baum 2074256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE)); 2075256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) > 1); 207637d6fc30SViacheslav Ovsiienko MLX5_ASSERT(loc->elts_free >= NB_SEGS(loc->mbuf)); 2077256fb0e3SMichael Baum /* 2078256fb0e3SMichael Baum * First calculate data length to be inlined 2079256fb0e3SMichael Baum * to estimate the required space for WQE. 2080256fb0e3SMichael Baum */ 2081256fb0e3SMichael Baum dlen = rte_pktmbuf_pkt_len(loc->mbuf); 2082daa02b5cSOlivier Matz if (MLX5_TXOFF_CONFIG(VLAN) && loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) 2083256fb0e3SMichael Baum vlan = sizeof(struct rte_vlan_hdr); 2084256fb0e3SMichael Baum inlen = dlen + vlan; 2085256fb0e3SMichael Baum /* Check against minimal length. */ 2086256fb0e3SMichael Baum if (inlen <= MLX5_ESEG_MIN_INLINE_SIZE) 2087256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2088256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE); 2089256fb0e3SMichael Baum if (inlen > txq->inlen_send || 2090daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE) { 2091256fb0e3SMichael Baum struct rte_mbuf *mbuf; 2092256fb0e3SMichael Baum unsigned int nxlen; 2093256fb0e3SMichael Baum uintptr_t start; 2094256fb0e3SMichael Baum 2095ec837ad0SViacheslav Ovsiienko mbuf = loc->mbuf; 2096e3c7bb56SViacheslav Ovsiienko nxlen = rte_pktmbuf_data_len(mbuf) + vlan; 2097256fb0e3SMichael Baum /* 2098256fb0e3SMichael Baum * Packet length exceeds the allowed inline data length, 2099256fb0e3SMichael Baum * check whether the minimal inlining is required. 2100256fb0e3SMichael Baum */ 2101256fb0e3SMichael Baum if (txq->inlen_mode) { 2102256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_mode >= 2103256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE); 2104256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_mode <= txq->inlen_send); 21057775172cSDariusz Sosnowski inlen = RTE_MIN(txq->inlen_mode, inlen); 2106ec837ad0SViacheslav Ovsiienko } else if (vlan && !txq->vlan_en) { 2107256fb0e3SMichael Baum /* 2108ec837ad0SViacheslav Ovsiienko * VLAN insertion is requested and hardware does not 2109ec837ad0SViacheslav Ovsiienko * support the offload, will do with software inline. 2110256fb0e3SMichael Baum */ 2111256fb0e3SMichael Baum inlen = MLX5_ESEG_MIN_INLINE_SIZE; 2112daa02b5cSOlivier Matz } else if (mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE || 2113ec837ad0SViacheslav Ovsiienko nxlen > txq->inlen_send) { 2114ec837ad0SViacheslav Ovsiienko return mlx5_tx_packet_multi_send(txq, loc, olx); 2115da4470cbSAlexander Kozyrev } else if (nxlen <= MLX5_ESEG_MIN_INLINE_SIZE) { 2116da4470cbSAlexander Kozyrev inlen = MLX5_ESEG_MIN_INLINE_SIZE; 2117ec837ad0SViacheslav Ovsiienko } else { 2118ec837ad0SViacheslav Ovsiienko goto do_first; 2119256fb0e3SMichael Baum } 21207775172cSDariusz Sosnowski if (mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE) 21217775172cSDariusz Sosnowski goto do_build; 2122256fb0e3SMichael Baum /* 2123256fb0e3SMichael Baum * Now we know the minimal amount of data is requested 2124256fb0e3SMichael Baum * to inline. Check whether we should inline the buffers 2125256fb0e3SMichael Baum * from the chain beginning to eliminate some mbufs. 2126256fb0e3SMichael Baum */ 2127256fb0e3SMichael Baum if (unlikely(nxlen <= txq->inlen_send)) { 2128256fb0e3SMichael Baum /* We can inline first mbuf at least. */ 2129256fb0e3SMichael Baum if (nxlen < inlen) { 2130256fb0e3SMichael Baum unsigned int smlen; 2131256fb0e3SMichael Baum 2132256fb0e3SMichael Baum /* Scan mbufs till inlen filled. */ 2133256fb0e3SMichael Baum do { 2134256fb0e3SMichael Baum smlen = nxlen; 2135256fb0e3SMichael Baum mbuf = NEXT(mbuf); 2136256fb0e3SMichael Baum MLX5_ASSERT(mbuf); 2137256fb0e3SMichael Baum nxlen = rte_pktmbuf_data_len(mbuf); 2138256fb0e3SMichael Baum nxlen += smlen; 2139256fb0e3SMichael Baum } while (unlikely(nxlen < inlen)); 2140256fb0e3SMichael Baum if (unlikely(nxlen > txq->inlen_send)) { 2141256fb0e3SMichael Baum /* We cannot inline entire mbuf. */ 2142256fb0e3SMichael Baum smlen = inlen - smlen; 2143256fb0e3SMichael Baum start = rte_pktmbuf_mtod_offset 2144256fb0e3SMichael Baum (mbuf, uintptr_t, smlen); 2145256fb0e3SMichael Baum goto do_align; 2146256fb0e3SMichael Baum } 2147256fb0e3SMichael Baum } 2148ec837ad0SViacheslav Ovsiienko do_first: 2149256fb0e3SMichael Baum do { 2150256fb0e3SMichael Baum inlen = nxlen; 2151256fb0e3SMichael Baum mbuf = NEXT(mbuf); 2152256fb0e3SMichael Baum /* There should be not end of packet. */ 2153256fb0e3SMichael Baum MLX5_ASSERT(mbuf); 21547775172cSDariusz Sosnowski if (mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE) 21557775172cSDariusz Sosnowski break; 2156256fb0e3SMichael Baum nxlen = inlen + rte_pktmbuf_data_len(mbuf); 2157256fb0e3SMichael Baum } while (unlikely(nxlen < txq->inlen_send)); 2158256fb0e3SMichael Baum } 2159256fb0e3SMichael Baum start = rte_pktmbuf_mtod(mbuf, uintptr_t); 2160256fb0e3SMichael Baum /* 2161256fb0e3SMichael Baum * Check whether we can do inline to align start 2162256fb0e3SMichael Baum * address of data buffer to cacheline. 2163256fb0e3SMichael Baum */ 2164256fb0e3SMichael Baum do_align: 2165256fb0e3SMichael Baum start = (~start + 1) & (RTE_CACHE_LINE_SIZE - 1); 2166256fb0e3SMichael Baum if (unlikely(start)) { 2167256fb0e3SMichael Baum start += inlen; 2168256fb0e3SMichael Baum if (start <= txq->inlen_send) 2169256fb0e3SMichael Baum inlen = start; 2170256fb0e3SMichael Baum } 2171256fb0e3SMichael Baum } 2172256fb0e3SMichael Baum /* 2173256fb0e3SMichael Baum * Check whether there are enough free WQEBBs: 2174256fb0e3SMichael Baum * - Control Segment 2175256fb0e3SMichael Baum * - Ethernet Segment 2176256fb0e3SMichael Baum * - First Segment of inlined Ethernet data 2177256fb0e3SMichael Baum * - ... data continued ... 2178256fb0e3SMichael Baum * - Data Segments of pointer/min inline type 2179256fb0e3SMichael Baum * 2180256fb0e3SMichael Baum * Estimate the number of Data Segments conservatively, 2181256fb0e3SMichael Baum * supposing no any mbufs is being freed during inlining. 2182256fb0e3SMichael Baum */ 21837775172cSDariusz Sosnowski do_build: 218437d6fc30SViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(TXPP)) { 218537d6fc30SViacheslav Ovsiienko enum mlx5_txcmp_code wret; 218637d6fc30SViacheslav Ovsiienko 218737d6fc30SViacheslav Ovsiienko /* Generate WAIT for scheduling if requested. */ 218837d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 0, olx); 218937d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_EXIT) 219037d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_EXIT; 219137d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_ERROR) 219237d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_ERROR; 219337d6fc30SViacheslav Ovsiienko } 2194256fb0e3SMichael Baum MLX5_ASSERT(inlen <= txq->inlen_send); 2195256fb0e3SMichael Baum ds = NB_SEGS(loc->mbuf) + 2 + (inlen - 2196256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE + 2197256fb0e3SMichael Baum MLX5_WSEG_SIZE + 2198256fb0e3SMichael Baum MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 2199256fb0e3SMichael Baum if (unlikely(loc->wqe_free < ((ds + 3) / 4))) 2200256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2201256fb0e3SMichael Baum /* Check for maximal WQE size. */ 2202d15bfd29SViacheslav Ovsiienko if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ds)) { 2203d15bfd29SViacheslav Ovsiienko /* Check if we can adjust the inline length. */ 2204d15bfd29SViacheslav Ovsiienko if (unlikely(txq->inlen_mode)) { 2205d15bfd29SViacheslav Ovsiienko ds = NB_SEGS(loc->mbuf) + 2 + 2206d15bfd29SViacheslav Ovsiienko (txq->inlen_mode - 2207d15bfd29SViacheslav Ovsiienko MLX5_ESEG_MIN_INLINE_SIZE + 2208d15bfd29SViacheslav Ovsiienko MLX5_WSEG_SIZE + 2209d15bfd29SViacheslav Ovsiienko MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 2210e2259f93SDmitry Kozlyuk if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ds)) 2211256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2212d15bfd29SViacheslav Ovsiienko } 2213d15bfd29SViacheslav Ovsiienko /* We have lucky opportunity to adjust. */ 2214d15bfd29SViacheslav Ovsiienko inlen = RTE_MIN(inlen, MLX5_WQE_SIZE_MAX - 2215d15bfd29SViacheslav Ovsiienko MLX5_WSEG_SIZE * 2 - 2216d15bfd29SViacheslav Ovsiienko MLX5_WSEG_SIZE * NB_SEGS(loc->mbuf) - 2217d15bfd29SViacheslav Ovsiienko MLX5_WSEG_SIZE + 2218d15bfd29SViacheslav Ovsiienko MLX5_ESEG_MIN_INLINE_SIZE); 2219d15bfd29SViacheslav Ovsiienko } 2220256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2221256fb0e3SMichael Baum /* Update sent data bytes/packets counters. */ 2222256fb0e3SMichael Baum txq->stats.obytes += dlen + vlan; 2223256fb0e3SMichael Baum #endif 2224256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 2225256fb0e3SMichael Baum loc->wqe_last = wqe; 2226256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, 0, MLX5_OPCODE_SEND, olx); 2227a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 2228256fb0e3SMichael Baum ds = mlx5_tx_mseg_build(txq, loc, wqe, vlan, inlen, 0, olx); 2229256fb0e3SMichael Baum wqe->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds); 2230256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 2231256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 2232256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 2233256fb0e3SMichael Baum } 2234256fb0e3SMichael Baum 2235256fb0e3SMichael Baum /** 2236256fb0e3SMichael Baum * Tx burst function for multi-segment packets. Supports all 2237256fb0e3SMichael Baum * types of Tx offloads, uses MLX5_OPCODE_SEND/TSO to build WQEs, 2238256fb0e3SMichael Baum * sends one packet per WQE. Function stops sending if it 2239256fb0e3SMichael Baum * encounters the single-segment packet. 2240256fb0e3SMichael Baum * 2241256fb0e3SMichael Baum * This routine is responsible for storing processed mbuf 2242256fb0e3SMichael Baum * into elts ring buffer and update elts_head. 2243256fb0e3SMichael Baum * 2244256fb0e3SMichael Baum * @param txq 2245256fb0e3SMichael Baum * Pointer to TX queue structure. 2246256fb0e3SMichael Baum * @param[in] pkts 2247256fb0e3SMichael Baum * Packets to transmit. 2248256fb0e3SMichael Baum * @param pkts_n 2249256fb0e3SMichael Baum * Number of packets in array. 2250256fb0e3SMichael Baum * @param loc 2251256fb0e3SMichael Baum * Pointer to burst routine local context. 2252256fb0e3SMichael Baum * @param olx 2253256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2254256fb0e3SMichael Baum * compile time and may be used for optimization. 2255256fb0e3SMichael Baum * 2256256fb0e3SMichael Baum * @return 2257256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 2258256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 2259256fb0e3SMichael Baum * MLX5_TXCMP_CODE_SINGLE - single-segment packet encountered. 2260256fb0e3SMichael Baum * MLX5_TXCMP_CODE_TSO - TSO single-segment packet encountered. 2261256fb0e3SMichael Baum * Local context variables updated. 2262256fb0e3SMichael Baum */ 2263256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2264256fb0e3SMichael Baum mlx5_tx_burst_mseg(struct mlx5_txq_data *__rte_restrict txq, 2265256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 2266256fb0e3SMichael Baum unsigned int pkts_n, 2267256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2268256fb0e3SMichael Baum unsigned int olx) 2269256fb0e3SMichael Baum { 2270256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 2271256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc->pkts_sent); 2272256fb0e3SMichael Baum pkts += loc->pkts_sent + 1; 2273256fb0e3SMichael Baum pkts_n -= loc->pkts_sent; 2274256fb0e3SMichael Baum for (;;) { 2275256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 2276256fb0e3SMichael Baum 2277256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) > 1); 2278256fb0e3SMichael Baum /* 2279256fb0e3SMichael Baum * Estimate the number of free elts quickly but conservatively. 2280256fb0e3SMichael Baum * Some segment may be fully inlined and freed, 2281256fb0e3SMichael Baum * ignore this here - precise estimation is costly. 2282256fb0e3SMichael Baum */ 2283256fb0e3SMichael Baum if (loc->elts_free < NB_SEGS(loc->mbuf)) 2284256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2285256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TSO) && 2286daa02b5cSOlivier Matz unlikely(loc->mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { 2287256fb0e3SMichael Baum /* Proceed with multi-segment TSO. */ 2288256fb0e3SMichael Baum ret = mlx5_tx_packet_multi_tso(txq, loc, olx); 2289256fb0e3SMichael Baum } else if (MLX5_TXOFF_CONFIG(INLINE)) { 2290256fb0e3SMichael Baum /* Proceed with multi-segment SEND with inlining. */ 2291256fb0e3SMichael Baum ret = mlx5_tx_packet_multi_inline(txq, loc, olx); 2292256fb0e3SMichael Baum } else { 2293256fb0e3SMichael Baum /* Proceed with multi-segment SEND w/o inlining. */ 2294256fb0e3SMichael Baum ret = mlx5_tx_packet_multi_send(txq, loc, olx); 2295256fb0e3SMichael Baum } 2296256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_EXIT) 2297256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2298256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_ERROR) 2299256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2300256fb0e3SMichael Baum /* WQE is built, go to the next packet. */ 2301256fb0e3SMichael Baum ++loc->pkts_sent; 2302256fb0e3SMichael Baum --pkts_n; 2303256fb0e3SMichael Baum if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free)) 2304256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2305256fb0e3SMichael Baum loc->mbuf = *pkts++; 2306256fb0e3SMichael Baum if (pkts_n > 1) 2307256fb0e3SMichael Baum rte_prefetch0(*pkts); 2308256fb0e3SMichael Baum if (likely(NB_SEGS(loc->mbuf) > 1)) 2309256fb0e3SMichael Baum continue; 2310256fb0e3SMichael Baum /* Here ends the series of multi-segment packets. */ 2311256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TSO) && 2312daa02b5cSOlivier Matz unlikely(loc->mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) 2313256fb0e3SMichael Baum return MLX5_TXCMP_CODE_TSO; 2314256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 2315256fb0e3SMichael Baum } 2316256fb0e3SMichael Baum MLX5_ASSERT(false); 2317256fb0e3SMichael Baum } 2318256fb0e3SMichael Baum 2319256fb0e3SMichael Baum /** 2320256fb0e3SMichael Baum * Tx burst function for single-segment packets with TSO. 2321256fb0e3SMichael Baum * Supports all types of Tx offloads, except multi-packets. 2322256fb0e3SMichael Baum * Uses MLX5_OPCODE_TSO to build WQEs, sends one packet per WQE. 2323256fb0e3SMichael Baum * Function stops sending if it encounters the multi-segment 2324256fb0e3SMichael Baum * packet or packet without TSO requested. 2325256fb0e3SMichael Baum * 2326256fb0e3SMichael Baum * The routine is responsible for storing processed mbuf into elts ring buffer 2327256fb0e3SMichael Baum * and update elts_head if inline offloads is requested due to possible early 2328256fb0e3SMichael Baum * freeing of the inlined mbufs (can not store pkts array in elts as a batch). 2329256fb0e3SMichael Baum * 2330256fb0e3SMichael Baum * @param txq 2331256fb0e3SMichael Baum * Pointer to TX queue structure. 2332256fb0e3SMichael Baum * @param[in] pkts 2333256fb0e3SMichael Baum * Packets to transmit. 2334256fb0e3SMichael Baum * @param pkts_n 2335256fb0e3SMichael Baum * Number of packets in array. 2336256fb0e3SMichael Baum * @param loc 2337256fb0e3SMichael Baum * Pointer to burst routine local context. 2338256fb0e3SMichael Baum * @param olx 2339256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2340256fb0e3SMichael Baum * compile time and may be used for optimization. 2341256fb0e3SMichael Baum * 2342256fb0e3SMichael Baum * @return 2343256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 2344256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 2345256fb0e3SMichael Baum * MLX5_TXCMP_CODE_SINGLE - single-segment packet encountered. 2346256fb0e3SMichael Baum * MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered. 2347256fb0e3SMichael Baum * Local context variables updated. 2348256fb0e3SMichael Baum */ 2349256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2350256fb0e3SMichael Baum mlx5_tx_burst_tso(struct mlx5_txq_data *__rte_restrict txq, 2351256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 2352256fb0e3SMichael Baum unsigned int pkts_n, 2353256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2354256fb0e3SMichael Baum unsigned int olx) 2355256fb0e3SMichael Baum { 2356256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 2357256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc->pkts_sent); 2358256fb0e3SMichael Baum pkts += loc->pkts_sent + 1; 2359256fb0e3SMichael Baum pkts_n -= loc->pkts_sent; 2360256fb0e3SMichael Baum for (;;) { 2361256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 2362256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe; 2363256fb0e3SMichael Baum unsigned int ds, dlen, hlen, ntcp, vlan = 0; 2364256fb0e3SMichael Baum uint8_t *dptr; 2365256fb0e3SMichael Baum 2366256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 2367256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP)) { 2368256fb0e3SMichael Baum enum mlx5_txcmp_code wret; 2369256fb0e3SMichael Baum 2370256fb0e3SMichael Baum /* Generate WAIT for scheduling if requested. */ 237137d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 1, olx); 2372256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_EXIT) 2373256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2374256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_ERROR) 2375256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2376256fb0e3SMichael Baum } 2377256fb0e3SMichael Baum dlen = rte_pktmbuf_data_len(loc->mbuf); 2378256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 2379daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) { 2380256fb0e3SMichael Baum vlan = sizeof(struct rte_vlan_hdr); 2381256fb0e3SMichael Baum } 2382256fb0e3SMichael Baum /* 2383256fb0e3SMichael Baum * First calculate the WQE size to check 2384256fb0e3SMichael Baum * whether we have enough space in ring buffer. 2385256fb0e3SMichael Baum */ 2386256fb0e3SMichael Baum hlen = loc->mbuf->l2_len + vlan + 2387256fb0e3SMichael Baum loc->mbuf->l3_len + loc->mbuf->l4_len; 2388256fb0e3SMichael Baum if (unlikely((!hlen || !loc->mbuf->tso_segsz))) 2389256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2390daa02b5cSOlivier Matz if (loc->mbuf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) 2391256fb0e3SMichael Baum hlen += loc->mbuf->outer_l2_len + 2392256fb0e3SMichael Baum loc->mbuf->outer_l3_len; 2393256fb0e3SMichael Baum /* Segment must contain all TSO headers. */ 2394256fb0e3SMichael Baum if (unlikely(hlen > MLX5_MAX_TSO_HEADER || 2395256fb0e3SMichael Baum hlen <= MLX5_ESEG_MIN_INLINE_SIZE || 2396256fb0e3SMichael Baum hlen > (dlen + vlan))) 2397256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2398256fb0e3SMichael Baum /* 2399256fb0e3SMichael Baum * Check whether there are enough free WQEBBs: 2400256fb0e3SMichael Baum * - Control Segment 2401256fb0e3SMichael Baum * - Ethernet Segment 2402256fb0e3SMichael Baum * - First Segment of inlined Ethernet data 2403256fb0e3SMichael Baum * - ... data continued ... 2404256fb0e3SMichael Baum * - Finishing Data Segment of pointer type 2405256fb0e3SMichael Baum */ 2406256fb0e3SMichael Baum ds = 4 + (hlen - MLX5_ESEG_MIN_INLINE_SIZE + 2407256fb0e3SMichael Baum MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 2408256fb0e3SMichael Baum if (loc->wqe_free < ((ds + 3) / 4)) 2409256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2410256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2411256fb0e3SMichael Baum /* Update sent data bytes/packets counters. */ 2412256fb0e3SMichael Baum ntcp = (dlen + vlan - hlen + 2413256fb0e3SMichael Baum loc->mbuf->tso_segsz - 1) / 2414256fb0e3SMichael Baum loc->mbuf->tso_segsz; 2415256fb0e3SMichael Baum /* 2416256fb0e3SMichael Baum * One will be added for mbuf itself at the end 2417256fb0e3SMichael Baum * of the mlx5_tx_burst from loc->pkts_sent field. 2418256fb0e3SMichael Baum */ 2419256fb0e3SMichael Baum --ntcp; 2420256fb0e3SMichael Baum txq->stats.opackets += ntcp; 2421256fb0e3SMichael Baum txq->stats.obytes += dlen + vlan + ntcp * hlen; 2422256fb0e3SMichael Baum #endif 2423256fb0e3SMichael Baum /* 2424256fb0e3SMichael Baum * Build the TSO WQE: 2425256fb0e3SMichael Baum * - Control Segment 2426256fb0e3SMichael Baum * - Ethernet Segment with hlen bytes inlined 2427256fb0e3SMichael Baum * - Data Segment of pointer type 2428256fb0e3SMichael Baum */ 2429256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 2430256fb0e3SMichael Baum loc->wqe_last = wqe; 2431a1e910f5SViacheslav Ovsiienko mlx5_tx_cseg_init(txq, loc, wqe, ds, MLX5_OPCODE_TSO, olx); 2432a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 2433256fb0e3SMichael Baum dseg = mlx5_tx_eseg_data(txq, loc, wqe, vlan, hlen, 1, olx); 2434256fb0e3SMichael Baum dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) + hlen - vlan; 2435256fb0e3SMichael Baum dlen -= hlen - vlan; 2436256fb0e3SMichael Baum mlx5_tx_dseg_ptr(txq, loc, dseg, dptr, dlen, olx); 2437256fb0e3SMichael Baum /* 2438256fb0e3SMichael Baum * WQE is built, update the loop parameters 2439256fb0e3SMichael Baum * and go to the next packet. 2440256fb0e3SMichael Baum */ 2441256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 2442256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 2443256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(INLINE)) 2444256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 2445256fb0e3SMichael Baum --loc->elts_free; 2446256fb0e3SMichael Baum ++loc->pkts_sent; 2447256fb0e3SMichael Baum --pkts_n; 2448256fb0e3SMichael Baum if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free)) 2449256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2450256fb0e3SMichael Baum loc->mbuf = *pkts++; 2451256fb0e3SMichael Baum if (pkts_n > 1) 2452256fb0e3SMichael Baum rte_prefetch0(*pkts); 2453256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MULTI) && 2454256fb0e3SMichael Baum unlikely(NB_SEGS(loc->mbuf) > 1)) 2455256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 2456daa02b5cSOlivier Matz if (likely(!(loc->mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG))) 2457256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 2458256fb0e3SMichael Baum /* Continue with the next TSO packet. */ 2459256fb0e3SMichael Baum } 2460256fb0e3SMichael Baum MLX5_ASSERT(false); 2461256fb0e3SMichael Baum } 2462256fb0e3SMichael Baum 2463256fb0e3SMichael Baum /** 2464256fb0e3SMichael Baum * Analyze the packet and select the best method to send. 2465256fb0e3SMichael Baum * 2466256fb0e3SMichael Baum * @param txq 2467256fb0e3SMichael Baum * Pointer to TX queue structure. 2468256fb0e3SMichael Baum * @param loc 2469256fb0e3SMichael Baum * Pointer to burst routine local context. 2470256fb0e3SMichael Baum * @param olx 2471256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2472256fb0e3SMichael Baum * compile time and may be used for optimization. 2473256fb0e3SMichael Baum * @param newp 2474256fb0e3SMichael Baum * The predefined flag whether do complete check for 2475256fb0e3SMichael Baum * multi-segment packets and TSO. 2476256fb0e3SMichael Baum * 2477256fb0e3SMichael Baum * @return 2478256fb0e3SMichael Baum * MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered. 2479256fb0e3SMichael Baum * MLX5_TXCMP_CODE_TSO - TSO required, use TSO/LSO. 2480256fb0e3SMichael Baum * MLX5_TXCMP_CODE_SINGLE - single-segment packet, use SEND. 2481256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EMPW - single-segment packet, use MPW. 2482256fb0e3SMichael Baum */ 2483256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2484256fb0e3SMichael Baum mlx5_tx_able_to_empw(struct mlx5_txq_data *__rte_restrict txq, 2485256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2486256fb0e3SMichael Baum unsigned int olx, 2487256fb0e3SMichael Baum bool newp) 2488256fb0e3SMichael Baum { 2489256fb0e3SMichael Baum /* Check for multi-segment packet. */ 2490256fb0e3SMichael Baum if (newp && 2491256fb0e3SMichael Baum MLX5_TXOFF_CONFIG(MULTI) && 2492256fb0e3SMichael Baum unlikely(NB_SEGS(loc->mbuf) > 1)) 2493256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 2494256fb0e3SMichael Baum /* Check for TSO packet. */ 2495256fb0e3SMichael Baum if (newp && 2496256fb0e3SMichael Baum MLX5_TXOFF_CONFIG(TSO) && 2497daa02b5cSOlivier Matz unlikely(loc->mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) 2498256fb0e3SMichael Baum return MLX5_TXCMP_CODE_TSO; 2499256fb0e3SMichael Baum /* Check if eMPW is enabled at all. */ 2500256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(EMPW)) 2501256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 2502256fb0e3SMichael Baum /* Check if eMPW can be engaged. */ 2503256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 2504daa02b5cSOlivier Matz unlikely(loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) && 2505256fb0e3SMichael Baum (!MLX5_TXOFF_CONFIG(INLINE) || 2506256fb0e3SMichael Baum unlikely((rte_pktmbuf_data_len(loc->mbuf) + 2507256fb0e3SMichael Baum sizeof(struct rte_vlan_hdr)) > txq->inlen_empw))) { 2508256fb0e3SMichael Baum /* 2509256fb0e3SMichael Baum * eMPW does not support VLAN insertion offload, we have to 2510256fb0e3SMichael Baum * inline the entire packet but packet is too long for inlining. 2511256fb0e3SMichael Baum */ 2512256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 2513256fb0e3SMichael Baum } 2514256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EMPW; 2515256fb0e3SMichael Baum } 2516256fb0e3SMichael Baum 2517256fb0e3SMichael Baum /** 2518256fb0e3SMichael Baum * Check the next packet attributes to match with the eMPW batch ones. 2519256fb0e3SMichael Baum * In addition, for legacy MPW the packet length is checked either. 2520256fb0e3SMichael Baum * 2521256fb0e3SMichael Baum * @param txq 2522256fb0e3SMichael Baum * Pointer to TX queue structure. 2523256fb0e3SMichael Baum * @param es 2524256fb0e3SMichael Baum * Pointer to Ethernet Segment of eMPW batch. 2525256fb0e3SMichael Baum * @param loc 2526256fb0e3SMichael Baum * Pointer to burst routine local context. 2527256fb0e3SMichael Baum * @param dlen 2528256fb0e3SMichael Baum * Length of previous packet in MPW descriptor. 2529256fb0e3SMichael Baum * @param olx 2530256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2531256fb0e3SMichael Baum * compile time and may be used for optimization. 2532256fb0e3SMichael Baum * 2533256fb0e3SMichael Baum * @return 2534256fb0e3SMichael Baum * true - packet match with eMPW batch attributes. 2535256fb0e3SMichael Baum * false - no match, eMPW should be restarted. 2536256fb0e3SMichael Baum */ 2537256fb0e3SMichael Baum static __rte_always_inline bool 2538256fb0e3SMichael Baum mlx5_tx_match_empw(struct mlx5_txq_data *__rte_restrict txq, 2539256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict es, 2540256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2541256fb0e3SMichael Baum uint32_t dlen, 2542256fb0e3SMichael Baum unsigned int olx) 2543256fb0e3SMichael Baum { 2544256fb0e3SMichael Baum uint8_t swp_flags = 0; 2545256fb0e3SMichael Baum 2546256fb0e3SMichael Baum /* Compare the checksum flags, if any. */ 2547256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(CSUM) && 2548256fb0e3SMichael Baum txq_ol_cksum_to_cs(loc->mbuf) != es->cs_flags) 2549256fb0e3SMichael Baum return false; 2550256fb0e3SMichael Baum /* Compare the Software Parser offsets and flags. */ 2551256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(SWP) && 2552256fb0e3SMichael Baum (es->swp_offs != txq_mbuf_to_swp(loc, &swp_flags, olx) || 2553256fb0e3SMichael Baum es->swp_flags != swp_flags)) 2554256fb0e3SMichael Baum return false; 2555256fb0e3SMichael Baum /* Fill metadata field if needed. */ 2556256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(METADATA) && 2557daa02b5cSOlivier Matz es->metadata != (loc->mbuf->ol_flags & RTE_MBUF_DYNFLAG_TX_METADATA ? 25586728fe93SBing Zhao rte_cpu_to_be_32(*RTE_FLOW_DYNF_METADATA(loc->mbuf)) : 0)) 2559256fb0e3SMichael Baum return false; 2560256fb0e3SMichael Baum /* Legacy MPW can send packets with the same length only. */ 2561256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW) && 2562256fb0e3SMichael Baum dlen != rte_pktmbuf_data_len(loc->mbuf)) 2563256fb0e3SMichael Baum return false; 2564256fb0e3SMichael Baum /* There must be no VLAN packets in eMPW loop. */ 2565256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN)) 2566daa02b5cSOlivier Matz MLX5_ASSERT(!(loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN)); 2567256fb0e3SMichael Baum /* Check if the scheduling is requested. */ 2568256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP) && 2569256fb0e3SMichael Baum loc->mbuf->ol_flags & txq->ts_mask) 2570256fb0e3SMichael Baum return false; 2571256fb0e3SMichael Baum return true; 2572256fb0e3SMichael Baum } 2573256fb0e3SMichael Baum 2574256fb0e3SMichael Baum /** 2575256fb0e3SMichael Baum * Update send loop variables and WQE for eMPW loop without data inlining. 2576256fb0e3SMichael Baum * Number of Data Segments is equal to the number of sent packets. 2577256fb0e3SMichael Baum * 2578256fb0e3SMichael Baum * @param txq 2579256fb0e3SMichael Baum * Pointer to TX queue structure. 2580256fb0e3SMichael Baum * @param loc 2581256fb0e3SMichael Baum * Pointer to burst routine local context. 2582256fb0e3SMichael Baum * @param ds 2583256fb0e3SMichael Baum * Number of packets/Data Segments/Packets. 2584256fb0e3SMichael Baum * @param slen 2585256fb0e3SMichael Baum * Accumulated statistics, bytes sent. 2586256fb0e3SMichael Baum * @param olx 2587256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2588256fb0e3SMichael Baum * compile time and may be used for optimization. 2589256fb0e3SMichael Baum * 2590256fb0e3SMichael Baum * @return 2591256fb0e3SMichael Baum * true - packet match with eMPW batch attributes. 2592256fb0e3SMichael Baum * false - no match, eMPW should be restarted. 2593256fb0e3SMichael Baum */ 2594256fb0e3SMichael Baum static __rte_always_inline void 2595256fb0e3SMichael Baum mlx5_tx_sdone_empw(struct mlx5_txq_data *__rte_restrict txq, 2596256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2597256fb0e3SMichael Baum unsigned int ds, 2598256fb0e3SMichael Baum unsigned int slen, 2599256fb0e3SMichael Baum unsigned int olx __rte_unused) 2600256fb0e3SMichael Baum { 2601256fb0e3SMichael Baum MLX5_ASSERT(!MLX5_TXOFF_CONFIG(INLINE)); 2602256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2603256fb0e3SMichael Baum /* Update sent data bytes counter. */ 2604256fb0e3SMichael Baum txq->stats.obytes += slen; 2605256fb0e3SMichael Baum #else 2606256fb0e3SMichael Baum (void)slen; 2607256fb0e3SMichael Baum #endif 2608256fb0e3SMichael Baum loc->elts_free -= ds; 2609256fb0e3SMichael Baum loc->pkts_sent += ds; 2610256fb0e3SMichael Baum ds += 2; 2611256fb0e3SMichael Baum loc->wqe_last->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds); 2612256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 2613256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 2614256fb0e3SMichael Baum } 2615256fb0e3SMichael Baum 2616256fb0e3SMichael Baum /** 2617256fb0e3SMichael Baum * Update send loop variables and WQE for eMPW loop with data inlining. 2618256fb0e3SMichael Baum * Gets the size of pushed descriptors and data to the WQE. 2619256fb0e3SMichael Baum * 2620256fb0e3SMichael Baum * @param txq 2621256fb0e3SMichael Baum * Pointer to TX queue structure. 2622256fb0e3SMichael Baum * @param loc 2623256fb0e3SMichael Baum * Pointer to burst routine local context. 2624256fb0e3SMichael Baum * @param len 2625256fb0e3SMichael Baum * Total size of descriptor/data in bytes. 2626256fb0e3SMichael Baum * @param slen 2627256fb0e3SMichael Baum * Accumulated statistics, data bytes sent. 2628256fb0e3SMichael Baum * @param wqem 2629256fb0e3SMichael Baum * The base WQE for the eMPW/MPW descriptor. 2630256fb0e3SMichael Baum * @param olx 2631256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2632256fb0e3SMichael Baum * compile time and may be used for optimization. 2633256fb0e3SMichael Baum * 2634256fb0e3SMichael Baum * @return 2635256fb0e3SMichael Baum * true - packet match with eMPW batch attributes. 2636256fb0e3SMichael Baum * false - no match, eMPW should be restarted. 2637256fb0e3SMichael Baum */ 2638256fb0e3SMichael Baum static __rte_always_inline void 2639256fb0e3SMichael Baum mlx5_tx_idone_empw(struct mlx5_txq_data *__rte_restrict txq, 2640256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2641256fb0e3SMichael Baum unsigned int len, 2642256fb0e3SMichael Baum unsigned int slen, 2643256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqem, 2644256fb0e3SMichael Baum unsigned int olx __rte_unused) 2645256fb0e3SMichael Baum { 2646256fb0e3SMichael Baum struct mlx5_wqe_dseg *dseg = &wqem->dseg[0]; 2647256fb0e3SMichael Baum 2648256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE)); 2649256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2650256fb0e3SMichael Baum /* Update sent data bytes counter. */ 2651256fb0e3SMichael Baum txq->stats.obytes += slen; 2652256fb0e3SMichael Baum #else 2653256fb0e3SMichael Baum (void)slen; 2654256fb0e3SMichael Baum #endif 2655256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW) && dseg->bcount == RTE_BE32(0)) { 2656256fb0e3SMichael Baum /* 2657256fb0e3SMichael Baum * If the legacy MPW session contains the inline packets 2658256fb0e3SMichael Baum * we should set the only inline data segment length 2659256fb0e3SMichael Baum * and align the total length to the segment size. 2660256fb0e3SMichael Baum */ 2661256fb0e3SMichael Baum MLX5_ASSERT(len > sizeof(dseg->bcount)); 2662256fb0e3SMichael Baum dseg->bcount = rte_cpu_to_be_32((len - sizeof(dseg->bcount)) | 2663256fb0e3SMichael Baum MLX5_ETH_WQE_DATA_INLINE); 2664256fb0e3SMichael Baum len = (len + MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE + 2; 2665256fb0e3SMichael Baum } else { 2666256fb0e3SMichael Baum /* 2667256fb0e3SMichael Baum * The session is not legacy MPW or contains the 2668256fb0e3SMichael Baum * data buffer pointer segments. 2669256fb0e3SMichael Baum */ 2670256fb0e3SMichael Baum MLX5_ASSERT((len % MLX5_WSEG_SIZE) == 0); 2671256fb0e3SMichael Baum len = len / MLX5_WSEG_SIZE + 2; 2672256fb0e3SMichael Baum } 2673256fb0e3SMichael Baum wqem->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | len); 2674256fb0e3SMichael Baum txq->wqe_ci += (len + 3) / 4; 2675256fb0e3SMichael Baum loc->wqe_free -= (len + 3) / 4; 2676256fb0e3SMichael Baum loc->wqe_last = wqem; 2677256fb0e3SMichael Baum } 2678256fb0e3SMichael Baum 2679256fb0e3SMichael Baum /** 2680256fb0e3SMichael Baum * The set of Tx burst functions for single-segment packets without TSO 2681256fb0e3SMichael Baum * and with Multi-Packet Writing feature support. 2682256fb0e3SMichael Baum * Supports all types of Tx offloads, except multi-packets and TSO. 2683256fb0e3SMichael Baum * 2684256fb0e3SMichael Baum * Uses MLX5_OPCODE_EMPW to build WQEs if possible and sends as many packet 2685256fb0e3SMichael Baum * per WQE as it can. If eMPW is not configured or packet can not be sent with 2686256fb0e3SMichael Baum * eMPW (VLAN insertion) the ordinary SEND opcode is used and only one packet 2687256fb0e3SMichael Baum * placed in WQE. 2688256fb0e3SMichael Baum * 2689256fb0e3SMichael Baum * Functions stop sending if it encounters the multi-segment packet or packet 2690256fb0e3SMichael Baum * with TSO requested. 2691256fb0e3SMichael Baum * 2692256fb0e3SMichael Baum * The routines are responsible for storing processed mbuf into elts ring buffer 2693256fb0e3SMichael Baum * and update elts_head if inlining offload is requested. Otherwise the copying 2694256fb0e3SMichael Baum * mbufs to elts can be postponed and completed at the end of burst routine. 2695256fb0e3SMichael Baum * 2696256fb0e3SMichael Baum * @param txq 2697256fb0e3SMichael Baum * Pointer to TX queue structure. 2698256fb0e3SMichael Baum * @param[in] pkts 2699256fb0e3SMichael Baum * Packets to transmit. 2700256fb0e3SMichael Baum * @param pkts_n 2701256fb0e3SMichael Baum * Number of packets in array. 2702256fb0e3SMichael Baum * @param loc 2703256fb0e3SMichael Baum * Pointer to burst routine local context. 2704256fb0e3SMichael Baum * @param olx 2705256fb0e3SMichael Baum * Configured Tx offloads mask. It is fully defined at 2706256fb0e3SMichael Baum * compile time and may be used for optimization. 2707256fb0e3SMichael Baum * 2708256fb0e3SMichael Baum * @return 2709256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EXIT - sending is done or impossible. 2710256fb0e3SMichael Baum * MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred. 2711256fb0e3SMichael Baum * MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered. 2712256fb0e3SMichael Baum * MLX5_TXCMP_CODE_TSO - TSO packet encountered. 2713256fb0e3SMichael Baum * MLX5_TXCMP_CODE_SINGLE - used inside functions set. 2714256fb0e3SMichael Baum * MLX5_TXCMP_CODE_EMPW - used inside functions set. 2715256fb0e3SMichael Baum * 2716256fb0e3SMichael Baum * Local context variables updated. 2717256fb0e3SMichael Baum * 2718256fb0e3SMichael Baum * 2719256fb0e3SMichael Baum * The routine sends packets with MLX5_OPCODE_EMPW 2720256fb0e3SMichael Baum * without inlining, this is dedicated optimized branch. 2721256fb0e3SMichael Baum * No VLAN insertion is supported. 2722256fb0e3SMichael Baum */ 2723256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2724256fb0e3SMichael Baum mlx5_tx_burst_empw_simple(struct mlx5_txq_data *__rte_restrict txq, 2725256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 2726256fb0e3SMichael Baum unsigned int pkts_n, 2727256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2728256fb0e3SMichael Baum unsigned int olx) 2729256fb0e3SMichael Baum { 2730256fb0e3SMichael Baum /* 2731256fb0e3SMichael Baum * Subroutine is the part of mlx5_tx_burst_single() and sends 2732256fb0e3SMichael Baum * single-segment packet with eMPW opcode without data inlining. 2733256fb0e3SMichael Baum */ 2734256fb0e3SMichael Baum MLX5_ASSERT(!MLX5_TXOFF_CONFIG(INLINE)); 2735256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(EMPW)); 2736256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 2737256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc->pkts_sent); 2738256fb0e3SMichael Baum pkts += loc->pkts_sent + 1; 2739256fb0e3SMichael Baum pkts_n -= loc->pkts_sent; 2740256fb0e3SMichael Baum for (;;) { 2741256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 2742256fb0e3SMichael Baum struct mlx5_wqe_eseg *__rte_restrict eseg; 2743256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 2744256fb0e3SMichael Baum unsigned int part, loop; 2745256fb0e3SMichael Baum unsigned int slen = 0; 2746256fb0e3SMichael Baum 2747256fb0e3SMichael Baum next_empw: 2748256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 2749256fb0e3SMichael Baum part = RTE_MIN(pkts_n, MLX5_TXOFF_CONFIG(MPW) ? 2750256fb0e3SMichael Baum MLX5_MPW_MAX_PACKETS : 2751256fb0e3SMichael Baum MLX5_EMPW_MAX_PACKETS); 2752256fb0e3SMichael Baum if (unlikely(loc->elts_free < part)) { 2753256fb0e3SMichael Baum /* We have no enough elts to save all mbufs. */ 2754256fb0e3SMichael Baum if (unlikely(loc->elts_free < MLX5_EMPW_MIN_PACKETS)) 2755256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2756256fb0e3SMichael Baum /* But we still able to send at least minimal eMPW. */ 2757256fb0e3SMichael Baum part = loc->elts_free; 2758256fb0e3SMichael Baum } 275937d6fc30SViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(TXPP)) { 276037d6fc30SViacheslav Ovsiienko enum mlx5_txcmp_code wret; 276137d6fc30SViacheslav Ovsiienko 276237d6fc30SViacheslav Ovsiienko /* Generate WAIT for scheduling if requested. */ 276337d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 0, olx); 276437d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_EXIT) 276537d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_EXIT; 276637d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_ERROR) 276737d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_ERROR; 276837d6fc30SViacheslav Ovsiienko } 2769256fb0e3SMichael Baum /* Check whether we have enough WQEs */ 2770256fb0e3SMichael Baum if (unlikely(loc->wqe_free < ((2 + part + 3) / 4))) { 2771256fb0e3SMichael Baum if (unlikely(loc->wqe_free < 2772256fb0e3SMichael Baum ((2 + MLX5_EMPW_MIN_PACKETS + 3) / 4))) 2773256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2774256fb0e3SMichael Baum part = (loc->wqe_free * 4) - 2; 2775256fb0e3SMichael Baum } 2776256fb0e3SMichael Baum if (likely(part > 1)) 2777256fb0e3SMichael Baum rte_prefetch0(*pkts); 2778256fb0e3SMichael Baum loc->wqe_last = txq->wqes + (txq->wqe_ci & txq->wqe_m); 2779256fb0e3SMichael Baum /* 2780256fb0e3SMichael Baum * Build eMPW title WQEBB: 2781256fb0e3SMichael Baum * - Control Segment, eMPW opcode 2782256fb0e3SMichael Baum * - Ethernet Segment, no inline 2783256fb0e3SMichael Baum */ 2784256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, loc->wqe_last, part + 2, 2785256fb0e3SMichael Baum MLX5_OPCODE_ENHANCED_MPSW, olx); 2786256fb0e3SMichael Baum mlx5_tx_eseg_none(txq, loc, loc->wqe_last, 2787256fb0e3SMichael Baum olx & ~MLX5_TXOFF_CONFIG_VLAN); 2788256fb0e3SMichael Baum eseg = &loc->wqe_last->eseg; 2789256fb0e3SMichael Baum dseg = &loc->wqe_last->dseg[0]; 2790256fb0e3SMichael Baum loop = part; 2791256fb0e3SMichael Baum /* Store the packet length for legacy MPW. */ 2792256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW)) 2793256fb0e3SMichael Baum eseg->mss = rte_cpu_to_be_16 2794256fb0e3SMichael Baum (rte_pktmbuf_data_len(loc->mbuf)); 2795256fb0e3SMichael Baum for (;;) { 2796256fb0e3SMichael Baum uint32_t dlen = rte_pktmbuf_data_len(loc->mbuf); 2797256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2798256fb0e3SMichael Baum /* Update sent data bytes counter. */ 2799256fb0e3SMichael Baum slen += dlen; 2800256fb0e3SMichael Baum #endif 2801a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 2802256fb0e3SMichael Baum mlx5_tx_dseg_ptr 2803256fb0e3SMichael Baum (txq, loc, dseg, 2804256fb0e3SMichael Baum rte_pktmbuf_mtod(loc->mbuf, uint8_t *), 2805256fb0e3SMichael Baum dlen, olx); 2806256fb0e3SMichael Baum if (unlikely(--loop == 0)) 2807256fb0e3SMichael Baum break; 2808256fb0e3SMichael Baum loc->mbuf = *pkts++; 2809256fb0e3SMichael Baum if (likely(loop > 1)) 2810256fb0e3SMichael Baum rte_prefetch0(*pkts); 2811256fb0e3SMichael Baum ret = mlx5_tx_able_to_empw(txq, loc, olx, true); 2812256fb0e3SMichael Baum /* 2813256fb0e3SMichael Baum * Unroll the completion code to avoid 2814256fb0e3SMichael Baum * returning variable value - it results in 2815256fb0e3SMichael Baum * unoptimized sequent checking in caller. 2816256fb0e3SMichael Baum */ 2817256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_MULTI) { 2818256fb0e3SMichael Baum part -= loop; 2819256fb0e3SMichael Baum mlx5_tx_sdone_empw(txq, loc, part, slen, olx); 2820256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 2821256fb0e3SMichael Baum !loc->wqe_free)) 2822256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2823256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 2824256fb0e3SMichael Baum } 2825256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 2826256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_TSO) { 2827256fb0e3SMichael Baum part -= loop; 2828256fb0e3SMichael Baum mlx5_tx_sdone_empw(txq, loc, part, slen, olx); 2829256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 2830256fb0e3SMichael Baum !loc->wqe_free)) 2831256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2832256fb0e3SMichael Baum return MLX5_TXCMP_CODE_TSO; 2833256fb0e3SMichael Baum } 2834256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_SINGLE) { 2835256fb0e3SMichael Baum part -= loop; 2836256fb0e3SMichael Baum mlx5_tx_sdone_empw(txq, loc, part, slen, olx); 2837256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 2838256fb0e3SMichael Baum !loc->wqe_free)) 2839256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2840256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 2841256fb0e3SMichael Baum } 2842256fb0e3SMichael Baum if (ret != MLX5_TXCMP_CODE_EMPW) { 2843256fb0e3SMichael Baum MLX5_ASSERT(false); 2844256fb0e3SMichael Baum part -= loop; 2845256fb0e3SMichael Baum mlx5_tx_sdone_empw(txq, loc, part, slen, olx); 2846256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2847256fb0e3SMichael Baum } 2848256fb0e3SMichael Baum /* 2849256fb0e3SMichael Baum * Check whether packet parameters coincide 2850256fb0e3SMichael Baum * within assumed eMPW batch: 2851256fb0e3SMichael Baum * - check sum settings 2852256fb0e3SMichael Baum * - metadata value 2853256fb0e3SMichael Baum * - software parser settings 2854256fb0e3SMichael Baum * - packets length (legacy MPW only) 2855256fb0e3SMichael Baum * - scheduling is not required 2856256fb0e3SMichael Baum */ 2857256fb0e3SMichael Baum if (!mlx5_tx_match_empw(txq, eseg, loc, dlen, olx)) { 2858256fb0e3SMichael Baum MLX5_ASSERT(loop); 2859256fb0e3SMichael Baum part -= loop; 2860256fb0e3SMichael Baum mlx5_tx_sdone_empw(txq, loc, part, slen, olx); 2861256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 2862256fb0e3SMichael Baum !loc->wqe_free)) 2863256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2864256fb0e3SMichael Baum pkts_n -= part; 2865256fb0e3SMichael Baum goto next_empw; 2866256fb0e3SMichael Baum } 2867256fb0e3SMichael Baum /* Packet attributes match, continue the same eMPW. */ 2868256fb0e3SMichael Baum ++dseg; 2869256fb0e3SMichael Baum if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end) 2870256fb0e3SMichael Baum dseg = (struct mlx5_wqe_dseg *)txq->wqes; 2871256fb0e3SMichael Baum } 2872256fb0e3SMichael Baum /* eMPW is built successfully, update loop parameters. */ 2873256fb0e3SMichael Baum MLX5_ASSERT(!loop); 2874256fb0e3SMichael Baum MLX5_ASSERT(pkts_n >= part); 2875256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 2876256fb0e3SMichael Baum /* Update sent data bytes counter. */ 2877256fb0e3SMichael Baum txq->stats.obytes += slen; 2878256fb0e3SMichael Baum #endif 2879256fb0e3SMichael Baum loc->elts_free -= part; 2880256fb0e3SMichael Baum loc->pkts_sent += part; 2881256fb0e3SMichael Baum txq->wqe_ci += (2 + part + 3) / 4; 2882256fb0e3SMichael Baum loc->wqe_free -= (2 + part + 3) / 4; 2883256fb0e3SMichael Baum pkts_n -= part; 2884256fb0e3SMichael Baum if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free)) 2885256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2886256fb0e3SMichael Baum loc->mbuf = *pkts++; 2887256fb0e3SMichael Baum ret = mlx5_tx_able_to_empw(txq, loc, olx, true); 2888256fb0e3SMichael Baum if (unlikely(ret != MLX5_TXCMP_CODE_EMPW)) 2889256fb0e3SMichael Baum return ret; 2890256fb0e3SMichael Baum /* Continue sending eMPW batches. */ 2891256fb0e3SMichael Baum } 2892256fb0e3SMichael Baum MLX5_ASSERT(false); 2893256fb0e3SMichael Baum } 2894256fb0e3SMichael Baum 2895256fb0e3SMichael Baum /** 2896256fb0e3SMichael Baum * The routine sends packets with MLX5_OPCODE_EMPW 2897256fb0e3SMichael Baum * with inlining, optionally supports VLAN insertion. 2898256fb0e3SMichael Baum */ 2899256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 2900256fb0e3SMichael Baum mlx5_tx_burst_empw_inline(struct mlx5_txq_data *__rte_restrict txq, 2901256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 2902256fb0e3SMichael Baum unsigned int pkts_n, 2903256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 2904256fb0e3SMichael Baum unsigned int olx) 2905256fb0e3SMichael Baum { 2906256fb0e3SMichael Baum /* 2907256fb0e3SMichael Baum * Subroutine is the part of mlx5_tx_burst_single() and sends 2908256fb0e3SMichael Baum * single-segment packet with eMPW opcode with data inlining. 2909256fb0e3SMichael Baum */ 2910256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE)); 2911256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(EMPW)); 2912256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 2913256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc->pkts_sent); 2914256fb0e3SMichael Baum pkts += loc->pkts_sent + 1; 2915256fb0e3SMichael Baum pkts_n -= loc->pkts_sent; 2916256fb0e3SMichael Baum for (;;) { 2917256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 2918256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqem; 2919256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 2920256fb0e3SMichael Baum unsigned int room, part, nlim; 2921256fb0e3SMichael Baum unsigned int slen = 0; 2922256fb0e3SMichael Baum 2923256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 2924256fb0e3SMichael Baum /* 2925256fb0e3SMichael Baum * Limits the amount of packets in one WQE 2926256fb0e3SMichael Baum * to improve CQE latency generation. 2927256fb0e3SMichael Baum */ 2928256fb0e3SMichael Baum nlim = RTE_MIN(pkts_n, MLX5_TXOFF_CONFIG(MPW) ? 2929256fb0e3SMichael Baum MLX5_MPW_INLINE_MAX_PACKETS : 2930256fb0e3SMichael Baum MLX5_EMPW_MAX_PACKETS); 293137d6fc30SViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(TXPP)) { 293237d6fc30SViacheslav Ovsiienko enum mlx5_txcmp_code wret; 293337d6fc30SViacheslav Ovsiienko 293437d6fc30SViacheslav Ovsiienko /* Generate WAIT for scheduling if requested. */ 293537d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, nlim, olx); 293637d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_EXIT) 293737d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_EXIT; 293837d6fc30SViacheslav Ovsiienko if (wret == MLX5_TXCMP_CODE_ERROR) 293937d6fc30SViacheslav Ovsiienko return MLX5_TXCMP_CODE_ERROR; 294037d6fc30SViacheslav Ovsiienko } 2941256fb0e3SMichael Baum /* Check whether we have minimal amount WQEs */ 2942256fb0e3SMichael Baum if (unlikely(loc->wqe_free < 2943256fb0e3SMichael Baum ((2 + MLX5_EMPW_MIN_PACKETS + 3) / 4))) 2944256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 2945256fb0e3SMichael Baum if (likely(pkts_n > 1)) 2946256fb0e3SMichael Baum rte_prefetch0(*pkts); 2947256fb0e3SMichael Baum wqem = txq->wqes + (txq->wqe_ci & txq->wqe_m); 2948256fb0e3SMichael Baum /* 2949256fb0e3SMichael Baum * Build eMPW title WQEBB: 2950256fb0e3SMichael Baum * - Control Segment, eMPW opcode, zero DS 2951256fb0e3SMichael Baum * - Ethernet Segment, no inline 2952256fb0e3SMichael Baum */ 2953256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqem, 0, 2954256fb0e3SMichael Baum MLX5_OPCODE_ENHANCED_MPSW, olx); 2955256fb0e3SMichael Baum mlx5_tx_eseg_none(txq, loc, wqem, 2956256fb0e3SMichael Baum olx & ~MLX5_TXOFF_CONFIG_VLAN); 2957256fb0e3SMichael Baum dseg = &wqem->dseg[0]; 2958256fb0e3SMichael Baum /* Store the packet length for legacy MPW. */ 2959256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW)) 2960256fb0e3SMichael Baum wqem->eseg.mss = rte_cpu_to_be_16 2961256fb0e3SMichael Baum (rte_pktmbuf_data_len(loc->mbuf)); 2962256fb0e3SMichael Baum room = RTE_MIN(MLX5_WQE_SIZE_MAX / MLX5_WQE_SIZE, 2963256fb0e3SMichael Baum loc->wqe_free) * MLX5_WQE_SIZE - 2964256fb0e3SMichael Baum MLX5_WQE_CSEG_SIZE - 2965256fb0e3SMichael Baum MLX5_WQE_ESEG_SIZE; 2966256fb0e3SMichael Baum /* Limit the room for legacy MPW sessions for performance. */ 2967256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW)) 2968256fb0e3SMichael Baum room = RTE_MIN(room, 2969256fb0e3SMichael Baum RTE_MAX(txq->inlen_empw + 2970256fb0e3SMichael Baum sizeof(dseg->bcount) + 2971256fb0e3SMichael Baum (MLX5_TXOFF_CONFIG(VLAN) ? 2972256fb0e3SMichael Baum sizeof(struct rte_vlan_hdr) : 0), 2973256fb0e3SMichael Baum MLX5_MPW_INLINE_MAX_PACKETS * 2974256fb0e3SMichael Baum MLX5_WQE_DSEG_SIZE)); 2975256fb0e3SMichael Baum /* Build WQE till we have space, packets and resources. */ 2976256fb0e3SMichael Baum part = room; 2977256fb0e3SMichael Baum for (;;) { 2978256fb0e3SMichael Baum uint32_t dlen = rte_pktmbuf_data_len(loc->mbuf); 2979256fb0e3SMichael Baum uint8_t *dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *); 2980256fb0e3SMichael Baum unsigned int tlen; 2981256fb0e3SMichael Baum 2982256fb0e3SMichael Baum MLX5_ASSERT(room >= MLX5_WQE_DSEG_SIZE); 2983256fb0e3SMichael Baum MLX5_ASSERT((room % MLX5_WQE_DSEG_SIZE) == 0); 2984256fb0e3SMichael Baum MLX5_ASSERT((uintptr_t)dseg < (uintptr_t)txq->wqes_end); 2985256fb0e3SMichael Baum /* 2986256fb0e3SMichael Baum * Some Tx offloads may cause an error if packet is not 2987256fb0e3SMichael Baum * long enough, check against assumed minimal length. 2988256fb0e3SMichael Baum */ 2989256fb0e3SMichael Baum if (unlikely(dlen <= MLX5_ESEG_MIN_INLINE_SIZE)) { 2990256fb0e3SMichael Baum part -= room; 2991256fb0e3SMichael Baum if (unlikely(!part)) 2992256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 2993256fb0e3SMichael Baum /* 2994256fb0e3SMichael Baum * We have some successfully built 2995256fb0e3SMichael Baum * packet Data Segments to send. 2996256fb0e3SMichael Baum */ 2997256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 2998256fb0e3SMichael Baum slen, wqem, olx); 2999256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 3000256fb0e3SMichael Baum } 3001256fb0e3SMichael Baum /* Inline or not inline - that's the Question. */ 3002256fb0e3SMichael Baum if (dlen > txq->inlen_empw || 3003daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_DYNF_NOINLINE) 3004256fb0e3SMichael Baum goto pointer_empw; 3005256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW)) { 3006256fb0e3SMichael Baum if (dlen > txq->inlen_send) 3007256fb0e3SMichael Baum goto pointer_empw; 3008256fb0e3SMichael Baum tlen = dlen; 3009256fb0e3SMichael Baum if (part == room) { 3010256fb0e3SMichael Baum /* Open new inline MPW session. */ 3011256fb0e3SMichael Baum tlen += sizeof(dseg->bcount); 3012256fb0e3SMichael Baum dseg->bcount = RTE_BE32(0); 3013256fb0e3SMichael Baum dseg = RTE_PTR_ADD 3014256fb0e3SMichael Baum (dseg, sizeof(dseg->bcount)); 3015256fb0e3SMichael Baum } else { 3016256fb0e3SMichael Baum /* 3017256fb0e3SMichael Baum * No pointer and inline descriptor 3018256fb0e3SMichael Baum * intermix for legacy MPW sessions. 3019256fb0e3SMichael Baum */ 3020256fb0e3SMichael Baum if (wqem->dseg[0].bcount) 3021256fb0e3SMichael Baum break; 3022256fb0e3SMichael Baum } 3023256fb0e3SMichael Baum } else { 3024256fb0e3SMichael Baum tlen = sizeof(dseg->bcount) + dlen; 3025256fb0e3SMichael Baum } 3026256fb0e3SMichael Baum /* Inline entire packet, optional VLAN insertion. */ 3027256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 3028daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) { 3029256fb0e3SMichael Baum /* 3030256fb0e3SMichael Baum * The packet length must be checked in 3031256fb0e3SMichael Baum * mlx5_tx_able_to_empw() and packet 3032256fb0e3SMichael Baum * fits into inline length guaranteed. 3033256fb0e3SMichael Baum */ 3034256fb0e3SMichael Baum MLX5_ASSERT((dlen + 3035256fb0e3SMichael Baum sizeof(struct rte_vlan_hdr)) <= 3036256fb0e3SMichael Baum txq->inlen_empw); 3037256fb0e3SMichael Baum tlen += sizeof(struct rte_vlan_hdr); 3038256fb0e3SMichael Baum if (room < tlen) 3039256fb0e3SMichael Baum break; 3040a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3041256fb0e3SMichael Baum dseg = mlx5_tx_dseg_vlan(txq, loc, dseg, 3042256fb0e3SMichael Baum dptr, dlen, olx); 3043256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 3044256fb0e3SMichael Baum /* Update sent data bytes counter. */ 3045256fb0e3SMichael Baum slen += sizeof(struct rte_vlan_hdr); 3046256fb0e3SMichael Baum #endif 3047256fb0e3SMichael Baum } else { 3048256fb0e3SMichael Baum if (room < tlen) 3049256fb0e3SMichael Baum break; 3050a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3051256fb0e3SMichael Baum dseg = mlx5_tx_dseg_empw(txq, loc, dseg, 3052256fb0e3SMichael Baum dptr, dlen, olx); 3053256fb0e3SMichael Baum } 3054256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(MPW)) 3055256fb0e3SMichael Baum tlen = RTE_ALIGN(tlen, MLX5_WSEG_SIZE); 3056256fb0e3SMichael Baum MLX5_ASSERT(room >= tlen); 3057256fb0e3SMichael Baum room -= tlen; 3058256fb0e3SMichael Baum /* 3059256fb0e3SMichael Baum * Packet data are completely inline, 3060256fb0e3SMichael Baum * we can try to free the packet. 3061256fb0e3SMichael Baum */ 3062256fb0e3SMichael Baum if (likely(loc->pkts_sent == loc->mbuf_free)) { 3063256fb0e3SMichael Baum /* 3064256fb0e3SMichael Baum * All the packets from the burst beginning 3065256fb0e3SMichael Baum * are inline, we can free mbufs directly 3066256fb0e3SMichael Baum * from the origin array on tx_burst exit(). 3067256fb0e3SMichael Baum */ 3068256fb0e3SMichael Baum loc->mbuf_free++; 3069256fb0e3SMichael Baum goto next_mbuf; 3070256fb0e3SMichael Baum } 3071256fb0e3SMichael Baum /* 3072256fb0e3SMichael Baum * In order no to call rte_pktmbuf_free_seg() here, 3073256fb0e3SMichael Baum * in the most inner loop (that might be very 3074256fb0e3SMichael Baum * expensive) we just save the mbuf in elts. 3075256fb0e3SMichael Baum */ 3076256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 3077256fb0e3SMichael Baum loc->elts_free--; 3078256fb0e3SMichael Baum goto next_mbuf; 3079256fb0e3SMichael Baum pointer_empw: 3080256fb0e3SMichael Baum /* 3081256fb0e3SMichael Baum * No pointer and inline descriptor 3082256fb0e3SMichael Baum * intermix for legacy MPW sessions. 3083256fb0e3SMichael Baum */ 3084256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MPW) && 3085256fb0e3SMichael Baum part != room && 3086256fb0e3SMichael Baum wqem->dseg[0].bcount == RTE_BE32(0)) 3087256fb0e3SMichael Baum break; 3088256fb0e3SMichael Baum /* 3089256fb0e3SMichael Baum * Not inlinable VLAN packets are 3090256fb0e3SMichael Baum * proceeded outside of this routine. 3091256fb0e3SMichael Baum */ 3092256fb0e3SMichael Baum MLX5_ASSERT(room >= MLX5_WQE_DSEG_SIZE); 3093256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN)) 3094256fb0e3SMichael Baum MLX5_ASSERT(!(loc->mbuf->ol_flags & 3095daa02b5cSOlivier Matz RTE_MBUF_F_TX_VLAN)); 3096a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3097256fb0e3SMichael Baum mlx5_tx_dseg_ptr(txq, loc, dseg, dptr, dlen, olx); 3098256fb0e3SMichael Baum /* We have to store mbuf in elts.*/ 3099256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf; 3100256fb0e3SMichael Baum loc->elts_free--; 3101256fb0e3SMichael Baum room -= MLX5_WQE_DSEG_SIZE; 3102256fb0e3SMichael Baum /* Ring buffer wraparound is checked at the loop end.*/ 3103256fb0e3SMichael Baum ++dseg; 3104256fb0e3SMichael Baum next_mbuf: 3105256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 3106256fb0e3SMichael Baum /* Update sent data bytes counter. */ 3107256fb0e3SMichael Baum slen += dlen; 3108256fb0e3SMichael Baum #endif 3109256fb0e3SMichael Baum loc->pkts_sent++; 3110256fb0e3SMichael Baum pkts_n--; 3111256fb0e3SMichael Baum if (unlikely(!pkts_n || !loc->elts_free)) { 3112256fb0e3SMichael Baum /* 3113256fb0e3SMichael Baum * We have no resources/packets to 3114256fb0e3SMichael Baum * continue build descriptors. 3115256fb0e3SMichael Baum */ 3116256fb0e3SMichael Baum part -= room; 3117256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 3118256fb0e3SMichael Baum slen, wqem, olx); 3119256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3120256fb0e3SMichael Baum } 3121256fb0e3SMichael Baum loc->mbuf = *pkts++; 3122256fb0e3SMichael Baum if (likely(pkts_n > 1)) 3123256fb0e3SMichael Baum rte_prefetch0(*pkts); 3124256fb0e3SMichael Baum ret = mlx5_tx_able_to_empw(txq, loc, olx, true); 3125256fb0e3SMichael Baum /* 3126256fb0e3SMichael Baum * Unroll the completion code to avoid 3127256fb0e3SMichael Baum * returning variable value - it results in 3128256fb0e3SMichael Baum * unoptimized sequent checking in caller. 3129256fb0e3SMichael Baum */ 3130256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_MULTI) { 3131256fb0e3SMichael Baum part -= room; 3132256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 3133256fb0e3SMichael Baum slen, wqem, olx); 3134256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 3135256fb0e3SMichael Baum !loc->wqe_free)) 3136256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3137256fb0e3SMichael Baum return MLX5_TXCMP_CODE_MULTI; 3138256fb0e3SMichael Baum } 3139256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 3140256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_TSO) { 3141256fb0e3SMichael Baum part -= room; 3142256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 3143256fb0e3SMichael Baum slen, wqem, olx); 3144256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 3145256fb0e3SMichael Baum !loc->wqe_free)) 3146256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3147256fb0e3SMichael Baum return MLX5_TXCMP_CODE_TSO; 3148256fb0e3SMichael Baum } 3149256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_SINGLE) { 3150256fb0e3SMichael Baum part -= room; 3151256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 3152256fb0e3SMichael Baum slen, wqem, olx); 3153256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 3154256fb0e3SMichael Baum !loc->wqe_free)) 3155256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3156256fb0e3SMichael Baum return MLX5_TXCMP_CODE_SINGLE; 3157256fb0e3SMichael Baum } 3158256fb0e3SMichael Baum if (ret != MLX5_TXCMP_CODE_EMPW) { 3159256fb0e3SMichael Baum MLX5_ASSERT(false); 3160256fb0e3SMichael Baum part -= room; 3161256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, 3162256fb0e3SMichael Baum slen, wqem, olx); 3163256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 3164256fb0e3SMichael Baum } 3165256fb0e3SMichael Baum /* Check if we have minimal room left. */ 3166256fb0e3SMichael Baum nlim--; 3167256fb0e3SMichael Baum if (unlikely(!nlim || room < MLX5_WQE_DSEG_SIZE)) 3168256fb0e3SMichael Baum break; 3169256fb0e3SMichael Baum /* 3170256fb0e3SMichael Baum * Check whether packet parameters coincide 3171256fb0e3SMichael Baum * within assumed eMPW batch: 3172256fb0e3SMichael Baum * - check sum settings 3173256fb0e3SMichael Baum * - metadata value 3174256fb0e3SMichael Baum * - software parser settings 3175256fb0e3SMichael Baum * - packets length (legacy MPW only) 3176256fb0e3SMichael Baum * - scheduling is not required 3177256fb0e3SMichael Baum */ 3178256fb0e3SMichael Baum if (!mlx5_tx_match_empw(txq, &wqem->eseg, 3179256fb0e3SMichael Baum loc, dlen, olx)) 3180256fb0e3SMichael Baum break; 3181256fb0e3SMichael Baum /* Packet attributes match, continue the same eMPW. */ 3182256fb0e3SMichael Baum if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end) 3183256fb0e3SMichael Baum dseg = (struct mlx5_wqe_dseg *)txq->wqes; 3184256fb0e3SMichael Baum } 3185256fb0e3SMichael Baum /* 3186256fb0e3SMichael Baum * We get here to close an existing eMPW 3187256fb0e3SMichael Baum * session and start the new one. 3188256fb0e3SMichael Baum */ 3189256fb0e3SMichael Baum MLX5_ASSERT(pkts_n); 3190256fb0e3SMichael Baum part -= room; 3191256fb0e3SMichael Baum if (unlikely(!part)) 3192256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3193256fb0e3SMichael Baum mlx5_tx_idone_empw(txq, loc, part, slen, wqem, olx); 3194256fb0e3SMichael Baum if (unlikely(!loc->elts_free || 3195256fb0e3SMichael Baum !loc->wqe_free)) 3196256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3197256fb0e3SMichael Baum /* Continue the loop with new eMPW session. */ 3198256fb0e3SMichael Baum } 3199256fb0e3SMichael Baum MLX5_ASSERT(false); 3200256fb0e3SMichael Baum } 3201256fb0e3SMichael Baum 3202256fb0e3SMichael Baum /** 3203256fb0e3SMichael Baum * The routine sends packets with ordinary MLX5_OPCODE_SEND. 3204256fb0e3SMichael Baum * Data inlining and VLAN insertion are supported. 3205256fb0e3SMichael Baum */ 3206256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 3207256fb0e3SMichael Baum mlx5_tx_burst_single_send(struct mlx5_txq_data *__rte_restrict txq, 3208256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 3209256fb0e3SMichael Baum unsigned int pkts_n, 3210256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 3211256fb0e3SMichael Baum unsigned int olx) 3212256fb0e3SMichael Baum { 3213256fb0e3SMichael Baum /* 3214256fb0e3SMichael Baum * Subroutine is the part of mlx5_tx_burst_single() 3215256fb0e3SMichael Baum * and sends single-segment packet with SEND opcode. 3216256fb0e3SMichael Baum */ 3217256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 3218256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc->pkts_sent); 3219256fb0e3SMichael Baum pkts += loc->pkts_sent + 1; 3220256fb0e3SMichael Baum pkts_n -= loc->pkts_sent; 3221256fb0e3SMichael Baum for (;;) { 3222256fb0e3SMichael Baum struct mlx5_wqe *__rte_restrict wqe; 3223256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 3224256fb0e3SMichael Baum 3225256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc->mbuf) == 1); 322637d6fc30SViacheslav Ovsiienko MLX5_ASSERT(loc->elts_free); 3227256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TXPP)) { 3228256fb0e3SMichael Baum enum mlx5_txcmp_code wret; 3229256fb0e3SMichael Baum 3230256fb0e3SMichael Baum /* Generate WAIT for scheduling if requested. */ 323137d6fc30SViacheslav Ovsiienko wret = mlx5_tx_schedule_send(txq, loc, 0, olx); 3232256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_EXIT) 3233256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3234256fb0e3SMichael Baum if (wret == MLX5_TXCMP_CODE_ERROR) 3235256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 3236256fb0e3SMichael Baum } 3237256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(INLINE)) { 3238256fb0e3SMichael Baum unsigned int inlen, vlan = 0; 3239256fb0e3SMichael Baum 3240256fb0e3SMichael Baum inlen = rte_pktmbuf_data_len(loc->mbuf); 3241256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 3242daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) { 3243256fb0e3SMichael Baum vlan = sizeof(struct rte_vlan_hdr); 3244256fb0e3SMichael Baum inlen += vlan; 3245256fb0e3SMichael Baum } 3246256fb0e3SMichael Baum /* 3247256fb0e3SMichael Baum * If inlining is enabled at configuration time 3248256fb0e3SMichael Baum * the limit must be not less than minimal size. 3249256fb0e3SMichael Baum * Otherwise we would do extra check for data 3250256fb0e3SMichael Baum * size to avoid crashes due to length overflow. 3251256fb0e3SMichael Baum */ 3252256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_send >= 3253256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE); 3254256fb0e3SMichael Baum if (inlen <= txq->inlen_send) { 3255256fb0e3SMichael Baum unsigned int seg_n, wqe_n; 3256256fb0e3SMichael Baum 3257256fb0e3SMichael Baum rte_prefetch0(rte_pktmbuf_mtod 3258256fb0e3SMichael Baum (loc->mbuf, uint8_t *)); 3259256fb0e3SMichael Baum /* Check against minimal length. */ 3260256fb0e3SMichael Baum if (inlen <= MLX5_ESEG_MIN_INLINE_SIZE) 3261256fb0e3SMichael Baum return MLX5_TXCMP_CODE_ERROR; 3262256fb0e3SMichael Baum if (loc->mbuf->ol_flags & 3263daa02b5cSOlivier Matz RTE_MBUF_F_TX_DYNF_NOINLINE) { 3264256fb0e3SMichael Baum /* 3265256fb0e3SMichael Baum * The hint flag not to inline packet 3266256fb0e3SMichael Baum * data is set. Check whether we can 3267256fb0e3SMichael Baum * follow the hint. 3268256fb0e3SMichael Baum */ 3269256fb0e3SMichael Baum if ((!MLX5_TXOFF_CONFIG(EMPW) && 3270256fb0e3SMichael Baum txq->inlen_mode) || 3271256fb0e3SMichael Baum (MLX5_TXOFF_CONFIG(MPW) && 3272256fb0e3SMichael Baum txq->inlen_mode)) { 3273256fb0e3SMichael Baum if (inlen <= txq->inlen_send) 3274256fb0e3SMichael Baum goto single_inline; 3275256fb0e3SMichael Baum /* 3276256fb0e3SMichael Baum * The hardware requires the 3277256fb0e3SMichael Baum * minimal inline data header. 3278256fb0e3SMichael Baum */ 3279256fb0e3SMichael Baum goto single_min_inline; 3280256fb0e3SMichael Baum } 3281256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 3282256fb0e3SMichael Baum vlan && !txq->vlan_en) { 3283256fb0e3SMichael Baum /* 3284256fb0e3SMichael Baum * We must insert VLAN tag 3285256fb0e3SMichael Baum * by software means. 3286256fb0e3SMichael Baum */ 3287256fb0e3SMichael Baum goto single_part_inline; 3288256fb0e3SMichael Baum } 3289256fb0e3SMichael Baum goto single_no_inline; 3290256fb0e3SMichael Baum } 3291256fb0e3SMichael Baum single_inline: 3292256fb0e3SMichael Baum /* 3293256fb0e3SMichael Baum * Completely inlined packet data WQE: 3294256fb0e3SMichael Baum * - Control Segment, SEND opcode 3295256fb0e3SMichael Baum * - Ethernet Segment, no VLAN insertion 3296256fb0e3SMichael Baum * - Data inlined, VLAN optionally inserted 3297256fb0e3SMichael Baum * - Alignment to MLX5_WSEG_SIZE 3298256fb0e3SMichael Baum * Have to estimate amount of WQEBBs 3299256fb0e3SMichael Baum */ 3300256fb0e3SMichael Baum seg_n = (inlen + 3 * MLX5_WSEG_SIZE - 3301256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE + 3302256fb0e3SMichael Baum MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 3303256fb0e3SMichael Baum /* Check if there are enough WQEBBs. */ 3304256fb0e3SMichael Baum wqe_n = (seg_n + 3) / 4; 3305256fb0e3SMichael Baum if (wqe_n > loc->wqe_free) 3306256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3307256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 3308256fb0e3SMichael Baum loc->wqe_last = wqe; 3309256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, seg_n, 3310256fb0e3SMichael Baum MLX5_OPCODE_SEND, olx); 3311a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3312256fb0e3SMichael Baum mlx5_tx_eseg_data(txq, loc, wqe, 3313256fb0e3SMichael Baum vlan, inlen, 0, olx); 3314256fb0e3SMichael Baum txq->wqe_ci += wqe_n; 3315256fb0e3SMichael Baum loc->wqe_free -= wqe_n; 3316256fb0e3SMichael Baum /* 3317256fb0e3SMichael Baum * Packet data are completely inlined, 3318256fb0e3SMichael Baum * free the packet immediately. 3319256fb0e3SMichael Baum */ 3320256fb0e3SMichael Baum rte_pktmbuf_free_seg(loc->mbuf); 3321256fb0e3SMichael Baum } else if ((!MLX5_TXOFF_CONFIG(EMPW) || 3322256fb0e3SMichael Baum MLX5_TXOFF_CONFIG(MPW)) && 3323256fb0e3SMichael Baum txq->inlen_mode) { 3324256fb0e3SMichael Baum /* 3325256fb0e3SMichael Baum * If minimal inlining is requested the eMPW 3326256fb0e3SMichael Baum * feature should be disabled due to data is 3327256fb0e3SMichael Baum * inlined into Ethernet Segment, which can 3328256fb0e3SMichael Baum * not contain inlined data for eMPW due to 3329256fb0e3SMichael Baum * segment shared for all packets. 3330256fb0e3SMichael Baum */ 3331256fb0e3SMichael Baum struct mlx5_wqe_dseg *__rte_restrict dseg; 3332256fb0e3SMichael Baum unsigned int ds; 3333256fb0e3SMichael Baum uint8_t *dptr; 3334256fb0e3SMichael Baum 3335256fb0e3SMichael Baum /* 3336256fb0e3SMichael Baum * The inline-mode settings require 3337256fb0e3SMichael Baum * to inline the specified amount of 3338256fb0e3SMichael Baum * data bytes to the Ethernet Segment. 3339256fb0e3SMichael Baum * We should check the free space in 3340256fb0e3SMichael Baum * WQE ring buffer to inline partially. 3341256fb0e3SMichael Baum */ 3342256fb0e3SMichael Baum single_min_inline: 3343256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_send >= txq->inlen_mode); 3344256fb0e3SMichael Baum MLX5_ASSERT(inlen > txq->inlen_mode); 3345256fb0e3SMichael Baum MLX5_ASSERT(txq->inlen_mode >= 3346256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE); 3347256fb0e3SMichael Baum /* 3348256fb0e3SMichael Baum * Check whether there are enough free WQEBBs: 3349256fb0e3SMichael Baum * - Control Segment 3350256fb0e3SMichael Baum * - Ethernet Segment 3351256fb0e3SMichael Baum * - First Segment of inlined Ethernet data 3352256fb0e3SMichael Baum * - ... data continued ... 3353256fb0e3SMichael Baum * - Finishing Data Segment of pointer type 3354256fb0e3SMichael Baum */ 3355256fb0e3SMichael Baum ds = (MLX5_WQE_CSEG_SIZE + 3356256fb0e3SMichael Baum MLX5_WQE_ESEG_SIZE + 3357256fb0e3SMichael Baum MLX5_WQE_DSEG_SIZE + 3358256fb0e3SMichael Baum txq->inlen_mode - 3359256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE + 3360256fb0e3SMichael Baum MLX5_WQE_DSEG_SIZE + 3361256fb0e3SMichael Baum MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE; 3362256fb0e3SMichael Baum if (loc->wqe_free < ((ds + 3) / 4)) 3363256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3364256fb0e3SMichael Baum /* 3365256fb0e3SMichael Baum * Build the ordinary SEND WQE: 3366256fb0e3SMichael Baum * - Control Segment 3367256fb0e3SMichael Baum * - Ethernet Segment, inline inlen_mode bytes 3368256fb0e3SMichael Baum * - Data Segment of pointer type 3369256fb0e3SMichael Baum */ 3370256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 3371256fb0e3SMichael Baum loc->wqe_last = wqe; 3372256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, ds, 3373256fb0e3SMichael Baum MLX5_OPCODE_SEND, olx); 3374a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3375256fb0e3SMichael Baum dseg = mlx5_tx_eseg_data(txq, loc, wqe, vlan, 3376256fb0e3SMichael Baum txq->inlen_mode, 3377256fb0e3SMichael Baum 0, olx); 3378256fb0e3SMichael Baum dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) + 3379256fb0e3SMichael Baum txq->inlen_mode - vlan; 3380256fb0e3SMichael Baum inlen -= txq->inlen_mode; 3381256fb0e3SMichael Baum mlx5_tx_dseg_ptr(txq, loc, dseg, 3382256fb0e3SMichael Baum dptr, inlen, olx); 3383256fb0e3SMichael Baum /* 3384256fb0e3SMichael Baum * WQE is built, update the loop parameters 3385256fb0e3SMichael Baum * and got to the next packet. 3386256fb0e3SMichael Baum */ 3387256fb0e3SMichael Baum txq->wqe_ci += (ds + 3) / 4; 3388256fb0e3SMichael Baum loc->wqe_free -= (ds + 3) / 4; 3389256fb0e3SMichael Baum /* We have to store mbuf in elts.*/ 3390256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE)); 3391256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = 3392256fb0e3SMichael Baum loc->mbuf; 3393256fb0e3SMichael Baum --loc->elts_free; 3394256fb0e3SMichael Baum } else { 3395256fb0e3SMichael Baum uint8_t *dptr; 3396256fb0e3SMichael Baum unsigned int dlen; 3397256fb0e3SMichael Baum 3398256fb0e3SMichael Baum /* 3399256fb0e3SMichael Baum * Partially inlined packet data WQE, we have 3400256fb0e3SMichael Baum * some space in title WQEBB, we can fill it 3401256fb0e3SMichael Baum * with some packet data. It takes one WQEBB, 3402256fb0e3SMichael Baum * it is available, no extra space check: 3403256fb0e3SMichael Baum * - Control Segment, SEND opcode 3404256fb0e3SMichael Baum * - Ethernet Segment, no VLAN insertion 3405256fb0e3SMichael Baum * - MLX5_ESEG_MIN_INLINE_SIZE bytes of Data 3406256fb0e3SMichael Baum * - Data Segment, pointer type 3407256fb0e3SMichael Baum * 3408256fb0e3SMichael Baum * We also get here if VLAN insertion is not 3409256fb0e3SMichael Baum * supported by HW, the inline is enabled. 3410256fb0e3SMichael Baum */ 3411256fb0e3SMichael Baum single_part_inline: 3412256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 3413256fb0e3SMichael Baum loc->wqe_last = wqe; 3414256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, 4, 3415256fb0e3SMichael Baum MLX5_OPCODE_SEND, olx); 3416a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3417256fb0e3SMichael Baum mlx5_tx_eseg_dmin(txq, loc, wqe, vlan, olx); 3418256fb0e3SMichael Baum dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) + 3419256fb0e3SMichael Baum MLX5_ESEG_MIN_INLINE_SIZE - vlan; 3420256fb0e3SMichael Baum /* 3421256fb0e3SMichael Baum * The length check is performed above, by 3422256fb0e3SMichael Baum * comparing with txq->inlen_send. We should 3423256fb0e3SMichael Baum * not get overflow here. 3424256fb0e3SMichael Baum */ 3425256fb0e3SMichael Baum MLX5_ASSERT(inlen > MLX5_ESEG_MIN_INLINE_SIZE); 3426256fb0e3SMichael Baum dlen = inlen - MLX5_ESEG_MIN_INLINE_SIZE; 3427256fb0e3SMichael Baum mlx5_tx_dseg_ptr(txq, loc, &wqe->dseg[1], 3428256fb0e3SMichael Baum dptr, dlen, olx); 3429256fb0e3SMichael Baum ++txq->wqe_ci; 3430256fb0e3SMichael Baum --loc->wqe_free; 3431256fb0e3SMichael Baum /* We have to store mbuf in elts.*/ 3432256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE)); 3433256fb0e3SMichael Baum txq->elts[txq->elts_head++ & txq->elts_m] = 3434256fb0e3SMichael Baum loc->mbuf; 3435256fb0e3SMichael Baum --loc->elts_free; 3436256fb0e3SMichael Baum } 3437256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 3438256fb0e3SMichael Baum /* Update sent data bytes counter. */ 3439256fb0e3SMichael Baum txq->stats.obytes += vlan + 3440256fb0e3SMichael Baum rte_pktmbuf_data_len(loc->mbuf); 3441256fb0e3SMichael Baum #endif 3442256fb0e3SMichael Baum } else { 3443256fb0e3SMichael Baum /* 3444256fb0e3SMichael Baum * No inline at all, it means the CPU cycles saving 3445256fb0e3SMichael Baum * is prioritized at configuration, we should not 3446256fb0e3SMichael Baum * copy any packet data to WQE. 3447256fb0e3SMichael Baum * 3448256fb0e3SMichael Baum * SEND WQE, one WQEBB: 3449256fb0e3SMichael Baum * - Control Segment, SEND opcode 3450256fb0e3SMichael Baum * - Ethernet Segment, optional VLAN, no inline 3451256fb0e3SMichael Baum * - Data Segment, pointer type 3452256fb0e3SMichael Baum */ 3453256fb0e3SMichael Baum single_no_inline: 3454256fb0e3SMichael Baum wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m); 3455256fb0e3SMichael Baum loc->wqe_last = wqe; 3456256fb0e3SMichael Baum mlx5_tx_cseg_init(txq, loc, wqe, 3, 3457256fb0e3SMichael Baum MLX5_OPCODE_SEND, olx); 3458a1e910f5SViacheslav Ovsiienko rte_pmd_mlx5_trace_tx_push(loc->mbuf, txq->wqe_ci); 3459256fb0e3SMichael Baum mlx5_tx_eseg_none(txq, loc, wqe, olx); 3460256fb0e3SMichael Baum mlx5_tx_dseg_ptr 3461256fb0e3SMichael Baum (txq, loc, &wqe->dseg[0], 3462256fb0e3SMichael Baum rte_pktmbuf_mtod(loc->mbuf, uint8_t *), 3463256fb0e3SMichael Baum rte_pktmbuf_data_len(loc->mbuf), olx); 3464256fb0e3SMichael Baum ++txq->wqe_ci; 3465256fb0e3SMichael Baum --loc->wqe_free; 3466256fb0e3SMichael Baum /* 3467256fb0e3SMichael Baum * We should not store mbuf pointer in elts 3468256fb0e3SMichael Baum * if no inlining is configured, this is done 3469256fb0e3SMichael Baum * by calling routine in a batch copy. 3470256fb0e3SMichael Baum */ 3471166f185fSViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(INLINE)) 3472166f185fSViacheslav Ovsiienko txq->elts[txq->elts_head++ & txq->elts_m] = 3473166f185fSViacheslav Ovsiienko loc->mbuf; 3474256fb0e3SMichael Baum --loc->elts_free; 3475256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 3476256fb0e3SMichael Baum /* Update sent data bytes counter. */ 3477256fb0e3SMichael Baum txq->stats.obytes += rte_pktmbuf_data_len(loc->mbuf); 3478256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(VLAN) && 3479daa02b5cSOlivier Matz loc->mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) 3480256fb0e3SMichael Baum txq->stats.obytes += 3481256fb0e3SMichael Baum sizeof(struct rte_vlan_hdr); 3482256fb0e3SMichael Baum #endif 3483256fb0e3SMichael Baum } 3484256fb0e3SMichael Baum ++loc->pkts_sent; 3485256fb0e3SMichael Baum --pkts_n; 3486256fb0e3SMichael Baum if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free)) 3487256fb0e3SMichael Baum return MLX5_TXCMP_CODE_EXIT; 3488256fb0e3SMichael Baum loc->mbuf = *pkts++; 3489256fb0e3SMichael Baum if (pkts_n > 1) 3490256fb0e3SMichael Baum rte_prefetch0(*pkts); 3491256fb0e3SMichael Baum ret = mlx5_tx_able_to_empw(txq, loc, olx, true); 3492256fb0e3SMichael Baum if (unlikely(ret != MLX5_TXCMP_CODE_SINGLE)) 3493256fb0e3SMichael Baum return ret; 3494256fb0e3SMichael Baum } 3495256fb0e3SMichael Baum MLX5_ASSERT(false); 3496256fb0e3SMichael Baum } 3497256fb0e3SMichael Baum 3498256fb0e3SMichael Baum static __rte_always_inline enum mlx5_txcmp_code 3499256fb0e3SMichael Baum mlx5_tx_burst_single(struct mlx5_txq_data *__rte_restrict txq, 3500256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 3501256fb0e3SMichael Baum unsigned int pkts_n, 3502256fb0e3SMichael Baum struct mlx5_txq_local *__rte_restrict loc, 3503256fb0e3SMichael Baum unsigned int olx) 3504256fb0e3SMichael Baum { 3505256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 3506256fb0e3SMichael Baum 3507256fb0e3SMichael Baum ret = mlx5_tx_able_to_empw(txq, loc, olx, false); 3508256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_SINGLE) 3509256fb0e3SMichael Baum goto ordinary_send; 3510256fb0e3SMichael Baum MLX5_ASSERT(ret == MLX5_TXCMP_CODE_EMPW); 3511256fb0e3SMichael Baum for (;;) { 3512256fb0e3SMichael Baum /* Optimize for inline/no inline eMPW send. */ 3513256fb0e3SMichael Baum ret = (MLX5_TXOFF_CONFIG(INLINE)) ? 3514256fb0e3SMichael Baum mlx5_tx_burst_empw_inline 3515256fb0e3SMichael Baum (txq, pkts, pkts_n, loc, olx) : 3516256fb0e3SMichael Baum mlx5_tx_burst_empw_simple 3517256fb0e3SMichael Baum (txq, pkts, pkts_n, loc, olx); 3518256fb0e3SMichael Baum if (ret != MLX5_TXCMP_CODE_SINGLE) 3519256fb0e3SMichael Baum return ret; 3520256fb0e3SMichael Baum /* The resources to send one packet should remain. */ 3521256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 3522256fb0e3SMichael Baum ordinary_send: 3523256fb0e3SMichael Baum ret = mlx5_tx_burst_single_send(txq, pkts, pkts_n, loc, olx); 3524256fb0e3SMichael Baum MLX5_ASSERT(ret != MLX5_TXCMP_CODE_SINGLE); 3525256fb0e3SMichael Baum if (ret != MLX5_TXCMP_CODE_EMPW) 3526256fb0e3SMichael Baum return ret; 3527256fb0e3SMichael Baum /* The resources to send one packet should remain. */ 3528256fb0e3SMichael Baum MLX5_ASSERT(loc->elts_free && loc->wqe_free); 3529256fb0e3SMichael Baum } 3530256fb0e3SMichael Baum } 3531256fb0e3SMichael Baum 3532256fb0e3SMichael Baum /** 3533256fb0e3SMichael Baum * DPDK Tx callback template. This is configured template used to generate 3534256fb0e3SMichael Baum * routines optimized for specified offload setup. 3535256fb0e3SMichael Baum * One of this generated functions is chosen at SQ configuration time. 3536256fb0e3SMichael Baum * 3537256fb0e3SMichael Baum * @param txq 3538256fb0e3SMichael Baum * Generic pointer to TX queue structure. 3539256fb0e3SMichael Baum * @param[in] pkts 3540256fb0e3SMichael Baum * Packets to transmit. 3541256fb0e3SMichael Baum * @param pkts_n 3542256fb0e3SMichael Baum * Number of packets in array. 3543256fb0e3SMichael Baum * @param olx 3544256fb0e3SMichael Baum * Configured offloads mask, presents the bits of MLX5_TXOFF_CONFIG_xxx 3545256fb0e3SMichael Baum * values. Should be static to take compile time static configuration 3546256fb0e3SMichael Baum * advantages. 3547256fb0e3SMichael Baum * 3548256fb0e3SMichael Baum * @return 3549256fb0e3SMichael Baum * Number of packets successfully transmitted (<= pkts_n). 3550256fb0e3SMichael Baum */ 3551256fb0e3SMichael Baum static __rte_always_inline uint16_t 3552256fb0e3SMichael Baum mlx5_tx_burst_tmpl(struct mlx5_txq_data *__rte_restrict txq, 3553256fb0e3SMichael Baum struct rte_mbuf **__rte_restrict pkts, 3554256fb0e3SMichael Baum uint16_t pkts_n, 3555256fb0e3SMichael Baum unsigned int olx) 3556256fb0e3SMichael Baum { 3557256fb0e3SMichael Baum struct mlx5_txq_local loc; 3558256fb0e3SMichael Baum enum mlx5_txcmp_code ret; 3559256fb0e3SMichael Baum unsigned int part; 3560256fb0e3SMichael Baum 3561256fb0e3SMichael Baum MLX5_ASSERT(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail)); 3562256fb0e3SMichael Baum MLX5_ASSERT(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi)); 3563256fb0e3SMichael Baum if (unlikely(!pkts_n)) 3564256fb0e3SMichael Baum return 0; 3565256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(INLINE)) 3566256fb0e3SMichael Baum loc.mbuf_free = 0; 3567256fb0e3SMichael Baum loc.pkts_sent = 0; 3568256fb0e3SMichael Baum loc.pkts_copy = 0; 3569256fb0e3SMichael Baum loc.wqe_last = NULL; 3570256fb0e3SMichael Baum 3571256fb0e3SMichael Baum send_loop: 3572256fb0e3SMichael Baum loc.pkts_loop = loc.pkts_sent; 3573256fb0e3SMichael Baum /* 3574256fb0e3SMichael Baum * Check if there are some CQEs, if any: 3575256fb0e3SMichael Baum * - process an encountered errors 3576256fb0e3SMichael Baum * - process the completed WQEs 3577256fb0e3SMichael Baum * - free related mbufs 3578256fb0e3SMichael Baum * - doorbell the NIC about processed CQEs 3579256fb0e3SMichael Baum */ 3580256fb0e3SMichael Baum rte_prefetch0(*(pkts + loc.pkts_sent)); 3581256fb0e3SMichael Baum mlx5_tx_handle_completion(txq, olx); 3582256fb0e3SMichael Baum /* 3583256fb0e3SMichael Baum * Calculate the number of available resources - elts and WQEs. 3584256fb0e3SMichael Baum * There are two possible different scenarios: 3585256fb0e3SMichael Baum * - no data inlining into WQEs, one WQEBB may contains up to 3586256fb0e3SMichael Baum * four packets, in this case elts become scarce resource 3587256fb0e3SMichael Baum * - data inlining into WQEs, one packet may require multiple 3588256fb0e3SMichael Baum * WQEBBs, the WQEs become the limiting factor. 3589256fb0e3SMichael Baum */ 3590256fb0e3SMichael Baum MLX5_ASSERT(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail)); 3591256fb0e3SMichael Baum loc.elts_free = txq->elts_s - 3592256fb0e3SMichael Baum (uint16_t)(txq->elts_head - txq->elts_tail); 3593256fb0e3SMichael Baum MLX5_ASSERT(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi)); 3594256fb0e3SMichael Baum loc.wqe_free = txq->wqe_s - 3595256fb0e3SMichael Baum (uint16_t)(txq->wqe_ci - txq->wqe_pi); 3596256fb0e3SMichael Baum if (unlikely(!loc.elts_free || !loc.wqe_free)) 3597256fb0e3SMichael Baum goto burst_exit; 3598256fb0e3SMichael Baum for (;;) { 3599256fb0e3SMichael Baum /* 3600256fb0e3SMichael Baum * Fetch the packet from array. Usually this is the first 3601256fb0e3SMichael Baum * packet in series of multi/single segment packets. 3602256fb0e3SMichael Baum */ 3603256fb0e3SMichael Baum loc.mbuf = *(pkts + loc.pkts_sent); 3604256fb0e3SMichael Baum /* Dedicated branch for multi-segment packets. */ 3605256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MULTI) && 3606256fb0e3SMichael Baum unlikely(NB_SEGS(loc.mbuf) > 1)) { 3607256fb0e3SMichael Baum /* 3608256fb0e3SMichael Baum * Multi-segment packet encountered. 3609256fb0e3SMichael Baum * Hardware is able to process it only 3610256fb0e3SMichael Baum * with SEND/TSO opcodes, one packet 3611256fb0e3SMichael Baum * per WQE, do it in dedicated routine. 3612256fb0e3SMichael Baum */ 3613256fb0e3SMichael Baum enter_send_multi: 3614256fb0e3SMichael Baum MLX5_ASSERT(loc.pkts_sent >= loc.pkts_copy); 3615256fb0e3SMichael Baum part = loc.pkts_sent - loc.pkts_copy; 3616256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(INLINE) && part) { 3617256fb0e3SMichael Baum /* 3618256fb0e3SMichael Baum * There are some single-segment mbufs not 3619256fb0e3SMichael Baum * stored in elts. The mbufs must be in the 3620256fb0e3SMichael Baum * same order as WQEs, so we must copy the 3621256fb0e3SMichael Baum * mbufs to elts here, before the coming 3622256fb0e3SMichael Baum * multi-segment packet mbufs is appended. 3623256fb0e3SMichael Baum */ 3624256fb0e3SMichael Baum mlx5_tx_copy_elts(txq, pkts + loc.pkts_copy, 3625256fb0e3SMichael Baum part, olx); 3626256fb0e3SMichael Baum loc.pkts_copy = loc.pkts_sent; 3627256fb0e3SMichael Baum } 3628256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc.pkts_sent); 3629256fb0e3SMichael Baum ret = mlx5_tx_burst_mseg(txq, pkts, pkts_n, &loc, olx); 3630256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(INLINE)) 3631256fb0e3SMichael Baum loc.pkts_copy = loc.pkts_sent; 3632256fb0e3SMichael Baum /* 3633256fb0e3SMichael Baum * These returned code checks are supposed 3634256fb0e3SMichael Baum * to be optimized out due to routine inlining. 3635256fb0e3SMichael Baum */ 3636256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_EXIT) { 3637256fb0e3SMichael Baum /* 3638256fb0e3SMichael Baum * The routine returns this code when 3639256fb0e3SMichael Baum * all packets are sent or there is no 3640256fb0e3SMichael Baum * enough resources to complete request. 3641256fb0e3SMichael Baum */ 3642256fb0e3SMichael Baum break; 3643256fb0e3SMichael Baum } 3644256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_ERROR) { 3645256fb0e3SMichael Baum /* 3646256fb0e3SMichael Baum * The routine returns this code when some error 3647256fb0e3SMichael Baum * in the incoming packets format occurred. 3648256fb0e3SMichael Baum */ 3649256fb0e3SMichael Baum txq->stats.oerrors++; 3650256fb0e3SMichael Baum break; 3651256fb0e3SMichael Baum } 3652256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_SINGLE) { 3653256fb0e3SMichael Baum /* 3654256fb0e3SMichael Baum * The single-segment packet was encountered 3655256fb0e3SMichael Baum * in the array, try to send it with the 3656256fb0e3SMichael Baum * best optimized way, possible engaging eMPW. 3657256fb0e3SMichael Baum */ 3658256fb0e3SMichael Baum goto enter_send_single; 3659256fb0e3SMichael Baum } 3660256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TSO) && 3661256fb0e3SMichael Baum ret == MLX5_TXCMP_CODE_TSO) { 3662256fb0e3SMichael Baum /* 3663256fb0e3SMichael Baum * The single-segment TSO packet was 3664256fb0e3SMichael Baum * encountered in the array. 3665256fb0e3SMichael Baum */ 3666256fb0e3SMichael Baum goto enter_send_tso; 3667256fb0e3SMichael Baum } 3668256fb0e3SMichael Baum /* We must not get here. Something is going wrong. */ 3669256fb0e3SMichael Baum MLX5_ASSERT(false); 3670256fb0e3SMichael Baum txq->stats.oerrors++; 3671256fb0e3SMichael Baum break; 3672256fb0e3SMichael Baum } 3673256fb0e3SMichael Baum /* Dedicated branch for single-segment TSO packets. */ 3674256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TSO) && 3675daa02b5cSOlivier Matz unlikely(loc.mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { 3676256fb0e3SMichael Baum /* 3677256fb0e3SMichael Baum * TSO might require special way for inlining 3678256fb0e3SMichael Baum * (dedicated parameters) and is sent with 3679256fb0e3SMichael Baum * MLX5_OPCODE_TSO opcode only, provide this 3680256fb0e3SMichael Baum * in dedicated branch. 3681256fb0e3SMichael Baum */ 3682256fb0e3SMichael Baum enter_send_tso: 3683256fb0e3SMichael Baum MLX5_ASSERT(NB_SEGS(loc.mbuf) == 1); 3684256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc.pkts_sent); 3685256fb0e3SMichael Baum ret = mlx5_tx_burst_tso(txq, pkts, pkts_n, &loc, olx); 3686256fb0e3SMichael Baum /* 3687256fb0e3SMichael Baum * These returned code checks are supposed 3688256fb0e3SMichael Baum * to be optimized out due to routine inlining. 3689256fb0e3SMichael Baum */ 3690256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_EXIT) 3691256fb0e3SMichael Baum break; 3692256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_ERROR) { 3693256fb0e3SMichael Baum txq->stats.oerrors++; 3694256fb0e3SMichael Baum break; 3695256fb0e3SMichael Baum } 3696256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_SINGLE) 3697256fb0e3SMichael Baum goto enter_send_single; 3698256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MULTI) && 3699256fb0e3SMichael Baum ret == MLX5_TXCMP_CODE_MULTI) { 3700256fb0e3SMichael Baum /* 3701256fb0e3SMichael Baum * The multi-segment packet was 3702256fb0e3SMichael Baum * encountered in the array. 3703256fb0e3SMichael Baum */ 3704256fb0e3SMichael Baum goto enter_send_multi; 3705256fb0e3SMichael Baum } 3706256fb0e3SMichael Baum /* We must not get here. Something is going wrong. */ 3707256fb0e3SMichael Baum MLX5_ASSERT(false); 3708256fb0e3SMichael Baum txq->stats.oerrors++; 3709256fb0e3SMichael Baum break; 3710256fb0e3SMichael Baum } 3711256fb0e3SMichael Baum /* 3712256fb0e3SMichael Baum * The dedicated branch for the single-segment packets 3713256fb0e3SMichael Baum * without TSO. Often these ones can be sent using 3714256fb0e3SMichael Baum * MLX5_OPCODE_EMPW with multiple packets in one WQE. 3715256fb0e3SMichael Baum * The routine builds the WQEs till it encounters 3716256fb0e3SMichael Baum * the TSO or multi-segment packet (in case if these 3717256fb0e3SMichael Baum * offloads are requested at SQ configuration time). 3718256fb0e3SMichael Baum */ 3719256fb0e3SMichael Baum enter_send_single: 3720256fb0e3SMichael Baum MLX5_ASSERT(pkts_n > loc.pkts_sent); 3721256fb0e3SMichael Baum ret = mlx5_tx_burst_single(txq, pkts, pkts_n, &loc, olx); 3722256fb0e3SMichael Baum /* 3723256fb0e3SMichael Baum * These returned code checks are supposed 3724256fb0e3SMichael Baum * to be optimized out due to routine inlining. 3725256fb0e3SMichael Baum */ 3726256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_EXIT) 3727256fb0e3SMichael Baum break; 3728256fb0e3SMichael Baum if (ret == MLX5_TXCMP_CODE_ERROR) { 3729256fb0e3SMichael Baum txq->stats.oerrors++; 3730256fb0e3SMichael Baum break; 3731256fb0e3SMichael Baum } 3732256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(MULTI) && 3733256fb0e3SMichael Baum ret == MLX5_TXCMP_CODE_MULTI) { 3734256fb0e3SMichael Baum /* 3735256fb0e3SMichael Baum * The multi-segment packet was 3736256fb0e3SMichael Baum * encountered in the array. 3737256fb0e3SMichael Baum */ 3738256fb0e3SMichael Baum goto enter_send_multi; 3739256fb0e3SMichael Baum } 3740256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(TSO) && 3741256fb0e3SMichael Baum ret == MLX5_TXCMP_CODE_TSO) { 3742256fb0e3SMichael Baum /* 3743256fb0e3SMichael Baum * The single-segment TSO packet was 3744256fb0e3SMichael Baum * encountered in the array. 3745256fb0e3SMichael Baum */ 3746256fb0e3SMichael Baum goto enter_send_tso; 3747256fb0e3SMichael Baum } 3748256fb0e3SMichael Baum /* We must not get here. Something is going wrong. */ 3749256fb0e3SMichael Baum MLX5_ASSERT(false); 3750256fb0e3SMichael Baum txq->stats.oerrors++; 3751256fb0e3SMichael Baum break; 3752256fb0e3SMichael Baum } 3753256fb0e3SMichael Baum /* 3754256fb0e3SMichael Baum * Main Tx loop is completed, do the rest: 3755256fb0e3SMichael Baum * - set completion request if thresholds are reached 3756256fb0e3SMichael Baum * - doorbell the hardware 3757256fb0e3SMichael Baum * - copy the rest of mbufs to elts (if any) 3758256fb0e3SMichael Baum */ 3759256fb0e3SMichael Baum MLX5_ASSERT(MLX5_TXOFF_CONFIG(INLINE) || 3760256fb0e3SMichael Baum loc.pkts_sent >= loc.pkts_copy); 3761256fb0e3SMichael Baum /* Take a shortcut if nothing is sent. */ 3762256fb0e3SMichael Baum if (unlikely(loc.pkts_sent == loc.pkts_loop)) 3763256fb0e3SMichael Baum goto burst_exit; 3764256fb0e3SMichael Baum /* Request CQE generation if limits are reached. */ 37658fa8d147SViacheslav Ovsiienko if (MLX5_TXOFF_CONFIG(TXPP) && __rte_trace_point_fp_is_enabled()) 37668fa8d147SViacheslav Ovsiienko mlx5_tx_request_completion_trace(txq, &loc, olx); 37678fa8d147SViacheslav Ovsiienko else 3768256fb0e3SMichael Baum mlx5_tx_request_completion(txq, &loc, olx); 3769256fb0e3SMichael Baum /* 3770256fb0e3SMichael Baum * Ring QP doorbell immediately after WQE building completion 3771256fb0e3SMichael Baum * to improve latencies. The pure software related data treatment 3772256fb0e3SMichael Baum * can be completed after doorbell. Tx CQEs for this SQ are 3773256fb0e3SMichael Baum * processed in this thread only by the polling. 3774256fb0e3SMichael Baum * 3775256fb0e3SMichael Baum * The rdma core library can map doorbell register in two ways, 3776256fb0e3SMichael Baum * depending on the environment variable "MLX5_SHUT_UP_BF": 3777256fb0e3SMichael Baum * 3778256fb0e3SMichael Baum * - as regular cached memory, the variable is either missing or 3779256fb0e3SMichael Baum * set to zero. This type of mapping may cause the significant 3780256fb0e3SMichael Baum * doorbell register writing latency and requires explicit memory 3781256fb0e3SMichael Baum * write barrier to mitigate this issue and prevent write combining. 3782256fb0e3SMichael Baum * 3783256fb0e3SMichael Baum * - as non-cached memory, the variable is present and set to not "0" 3784256fb0e3SMichael Baum * value. This type of mapping may cause performance impact under 3785256fb0e3SMichael Baum * heavy loading conditions but the explicit write memory barrier is 3786256fb0e3SMichael Baum * not required and it may improve core performance. 3787256fb0e3SMichael Baum * 3788256fb0e3SMichael Baum * - the legacy behaviour (prior 19.08 release) was to use some 3789256fb0e3SMichael Baum * heuristics to decide whether write memory barrier should 3790256fb0e3SMichael Baum * be performed. This behavior is supported with specifying 3791256fb0e3SMichael Baum * tx_db_nc=2, write barrier is skipped if application provides 3792256fb0e3SMichael Baum * the full recommended burst of packets, it supposes the next 3793256fb0e3SMichael Baum * packets are coming and the write barrier will be issued on 3794256fb0e3SMichael Baum * the next burst (after descriptor writing, at least). 3795256fb0e3SMichael Baum */ 37965dfa003dSMichael Baum mlx5_doorbell_ring(mlx5_tx_bfreg(txq), 37975dfa003dSMichael Baum *(volatile uint64_t *)loc.wqe_last, txq->wqe_ci, 37985dfa003dSMichael Baum txq->qp_db, !txq->db_nc && 3799256fb0e3SMichael Baum (!txq->db_heu || pkts_n % MLX5_TX_DEFAULT_BURST)); 3800256fb0e3SMichael Baum /* Not all of the mbufs may be stored into elts yet. */ 3801256fb0e3SMichael Baum part = MLX5_TXOFF_CONFIG(INLINE) ? 0 : loc.pkts_sent - loc.pkts_copy; 3802256fb0e3SMichael Baum if (!MLX5_TXOFF_CONFIG(INLINE) && part) { 3803256fb0e3SMichael Baum /* 3804256fb0e3SMichael Baum * There are some single-segment mbufs not stored in elts. 3805256fb0e3SMichael Baum * It can be only if the last packet was single-segment. 3806256fb0e3SMichael Baum * The copying is gathered into one place due to it is 3807256fb0e3SMichael Baum * a good opportunity to optimize that with SIMD. 3808256fb0e3SMichael Baum * Unfortunately if inlining is enabled the gaps in pointer 3809256fb0e3SMichael Baum * array may happen due to early freeing of the inlined mbufs. 3810256fb0e3SMichael Baum */ 3811256fb0e3SMichael Baum mlx5_tx_copy_elts(txq, pkts + loc.pkts_copy, part, olx); 3812256fb0e3SMichael Baum loc.pkts_copy = loc.pkts_sent; 3813256fb0e3SMichael Baum } 3814256fb0e3SMichael Baum MLX5_ASSERT(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail)); 3815256fb0e3SMichael Baum MLX5_ASSERT(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi)); 3816256fb0e3SMichael Baum if (pkts_n > loc.pkts_sent) { 3817256fb0e3SMichael Baum /* 3818256fb0e3SMichael Baum * If burst size is large there might be no enough CQE 3819256fb0e3SMichael Baum * fetched from completion queue and no enough resources 3820256fb0e3SMichael Baum * freed to send all the packets. 3821256fb0e3SMichael Baum */ 3822256fb0e3SMichael Baum goto send_loop; 3823256fb0e3SMichael Baum } 3824256fb0e3SMichael Baum burst_exit: 3825256fb0e3SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 3826256fb0e3SMichael Baum /* Increment sent packets counter. */ 3827256fb0e3SMichael Baum txq->stats.opackets += loc.pkts_sent; 3828256fb0e3SMichael Baum #endif 3829256fb0e3SMichael Baum if (MLX5_TXOFF_CONFIG(INLINE) && loc.mbuf_free) 3830256fb0e3SMichael Baum __mlx5_tx_free_mbuf(txq, pkts, loc.mbuf_free, olx); 3831a1e910f5SViacheslav Ovsiienko /* Trace productive bursts only. */ 3832a1e910f5SViacheslav Ovsiienko if (__rte_trace_point_fp_is_enabled() && loc.pkts_sent) 3833*02932480STim Martin rte_pmd_mlx5_trace_tx_exit(mlx5_read_pcibar_clock_from_txq(txq), 3834*02932480STim Martin loc.pkts_sent, pkts_n); 3835256fb0e3SMichael Baum return loc.pkts_sent; 3836256fb0e3SMichael Baum } 3837256fb0e3SMichael Baum 38381944fbc3SSuanming Mou /** 38391944fbc3SSuanming Mou * Check whether given TxQ is external. 38401944fbc3SSuanming Mou * 38411944fbc3SSuanming Mou * @param dev 38421944fbc3SSuanming Mou * Pointer to Ethernet device. 38431944fbc3SSuanming Mou * @param queue_idx 38441944fbc3SSuanming Mou * Tx queue index. 38451944fbc3SSuanming Mou * 38461944fbc3SSuanming Mou * @return 38471944fbc3SSuanming Mou * True if is external TxQ, otherwise false. 38481944fbc3SSuanming Mou */ 38491944fbc3SSuanming Mou static __rte_always_inline bool 38501944fbc3SSuanming Mou mlx5_is_external_txq(struct rte_eth_dev *dev, uint16_t queue_idx) 38511944fbc3SSuanming Mou { 38521944fbc3SSuanming Mou struct mlx5_priv *priv = dev->data->dev_private; 38531944fbc3SSuanming Mou struct mlx5_external_q *txq; 38541944fbc3SSuanming Mou 38551944fbc3SSuanming Mou if (!priv->ext_txqs || queue_idx < MLX5_EXTERNAL_TX_QUEUE_ID_MIN) 38561944fbc3SSuanming Mou return false; 38571944fbc3SSuanming Mou txq = &priv->ext_txqs[queue_idx - MLX5_EXTERNAL_TX_QUEUE_ID_MIN]; 38581944fbc3SSuanming Mou return !!rte_atomic_load_explicit(&txq->refcnt, rte_memory_order_relaxed); 38591944fbc3SSuanming Mou } 38601944fbc3SSuanming Mou 3861377b69fbSMichael Baum #endif /* RTE_PMD_MLX5_TX_H_ */ 3862