0b8563491926449c49acae46236b407f34a5ebcb
[dpdk.git] / drivers / net / mlx5 / mlx5_rxtx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2015 6WIND S.A.
3  * Copyright 2015-2019 Mellanox Technologies, Ltd
4  */
5
6 #include <assert.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <stdlib.h>
10
11 /* Verbs header. */
12 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
13 #ifdef PEDANTIC
14 #pragma GCC diagnostic ignored "-Wpedantic"
15 #endif
16 #include <infiniband/verbs.h>
17 #include <infiniband/mlx5dv.h>
18 #ifdef PEDANTIC
19 #pragma GCC diagnostic error "-Wpedantic"
20 #endif
21
22 #include <rte_mbuf.h>
23 #include <rte_mempool.h>
24 #include <rte_prefetch.h>
25 #include <rte_common.h>
26 #include <rte_branch_prediction.h>
27 #include <rte_ether.h>
28 #include <rte_cycles.h>
29 #include <rte_flow.h>
30
31 #include "mlx5.h"
32 #include "mlx5_utils.h"
33 #include "mlx5_rxtx.h"
34 #include "mlx5_autoconf.h"
35 #include "mlx5_defs.h"
36 #include "mlx5_prm.h"
37
38 /* TX burst subroutines return codes. */
39 enum mlx5_txcmp_code {
40         MLX5_TXCMP_CODE_EXIT = 0,
41         MLX5_TXCMP_CODE_ERROR,
42         MLX5_TXCMP_CODE_SINGLE,
43         MLX5_TXCMP_CODE_MULTI,
44         MLX5_TXCMP_CODE_TSO,
45         MLX5_TXCMP_CODE_EMPW,
46 };
47
48 /*
49  * These defines are used to configure Tx burst routine option set
50  * supported at compile time. The not specified options are optimized out
51  * out due to if conditions can be explicitly calculated at compile time.
52  * The offloads with bigger runtime check (require more CPU cycles to
53  * skip) overhead should have the bigger index - this is needed to
54  * select the better matching routine function if no exact match and
55  * some offloads are not actually requested.
56  */
57 #define MLX5_TXOFF_CONFIG_MULTI (1u << 0) /* Multi-segment packets.*/
58 #define MLX5_TXOFF_CONFIG_TSO (1u << 1) /* TCP send offload supported.*/
59 #define MLX5_TXOFF_CONFIG_SWP (1u << 2) /* Tunnels/SW Parser offloads.*/
60 #define MLX5_TXOFF_CONFIG_CSUM (1u << 3) /* Check Sums offloaded. */
61 #define MLX5_TXOFF_CONFIG_INLINE (1u << 4) /* Data inlining supported. */
62 #define MLX5_TXOFF_CONFIG_VLAN (1u << 5) /* VLAN insertion supported.*/
63 #define MLX5_TXOFF_CONFIG_METADATA (1u << 6) /* Flow metadata. */
64 #define MLX5_TXOFF_CONFIG_EMPW (1u << 8) /* Enhanced MPW supported.*/
65 #define MLX5_TXOFF_CONFIG_MPW (1u << 9) /* Legacy MPW supported.*/
66
67 /* The most common offloads groups. */
68 #define MLX5_TXOFF_CONFIG_NONE 0
69 #define MLX5_TXOFF_CONFIG_FULL (MLX5_TXOFF_CONFIG_MULTI | \
70                                 MLX5_TXOFF_CONFIG_TSO | \
71                                 MLX5_TXOFF_CONFIG_SWP | \
72                                 MLX5_TXOFF_CONFIG_CSUM | \
73                                 MLX5_TXOFF_CONFIG_INLINE | \
74                                 MLX5_TXOFF_CONFIG_VLAN | \
75                                 MLX5_TXOFF_CONFIG_METADATA)
76
77 #define MLX5_TXOFF_CONFIG(mask) (olx & MLX5_TXOFF_CONFIG_##mask)
78
79 #define MLX5_TXOFF_DECL(func, olx) \
80 static uint16_t mlx5_tx_burst_##func(void *txq, \
81                                      struct rte_mbuf **pkts, \
82                                     uint16_t pkts_n) \
83 { \
84         return mlx5_tx_burst_tmpl((struct mlx5_txq_data *)txq, \
85                     pkts, pkts_n, (olx)); \
86 }
87
88 #define MLX5_TXOFF_INFO(func, olx) {mlx5_tx_burst_##func, olx},
89
90 static __rte_always_inline uint32_t
91 rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe);
92
93 static __rte_always_inline int
94 mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
95                  uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe);
96
97 static __rte_always_inline uint32_t
98 rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
99
100 static __rte_always_inline void
101 rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
102                volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res);
103
104 static __rte_always_inline void
105 mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx,
106                  const unsigned int strd_n);
107
108 static int
109 mlx5_queue_state_modify(struct rte_eth_dev *dev,
110                         struct mlx5_mp_arg_queue_state_modify *sm);
111
112 static inline void
113 mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *restrict tcp,
114                         volatile struct mlx5_cqe *restrict cqe,
115                         uint32_t phcsum);
116
117 static inline void
118 mlx5_lro_update_hdr(uint8_t *restrict padd,
119                     volatile struct mlx5_cqe *restrict cqe,
120                     uint32_t len);
121
122 uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
123         [0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
124 };
125
126 uint8_t mlx5_cksum_table[1 << 10] __rte_cache_aligned;
127 uint8_t mlx5_swp_types_table[1 << 10] __rte_cache_aligned;
128
129 /**
130  * Build a table to translate Rx completion flags to packet type.
131  *
132  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
133  */
134 void
135 mlx5_set_ptype_table(void)
136 {
137         unsigned int i;
138         uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
139
140         /* Last entry must not be overwritten, reserved for errored packet. */
141         for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
142                 (*p)[i] = RTE_PTYPE_UNKNOWN;
143         /*
144          * The index to the array should have:
145          * bit[1:0] = l3_hdr_type
146          * bit[4:2] = l4_hdr_type
147          * bit[5] = ip_frag
148          * bit[6] = tunneled
149          * bit[7] = outer_l3_type
150          */
151         /* L2 */
152         (*p)[0x00] = RTE_PTYPE_L2_ETHER;
153         /* L3 */
154         (*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
155                      RTE_PTYPE_L4_NONFRAG;
156         (*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
157                      RTE_PTYPE_L4_NONFRAG;
158         /* Fragmented */
159         (*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
160                      RTE_PTYPE_L4_FRAG;
161         (*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
162                      RTE_PTYPE_L4_FRAG;
163         /* TCP */
164         (*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
165                      RTE_PTYPE_L4_TCP;
166         (*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
167                      RTE_PTYPE_L4_TCP;
168         (*p)[0x0d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
169                      RTE_PTYPE_L4_TCP;
170         (*p)[0x0e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
171                      RTE_PTYPE_L4_TCP;
172         (*p)[0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
173                      RTE_PTYPE_L4_TCP;
174         (*p)[0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
175                      RTE_PTYPE_L4_TCP;
176         /* UDP */
177         (*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
178                      RTE_PTYPE_L4_UDP;
179         (*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
180                      RTE_PTYPE_L4_UDP;
181         /* Repeat with outer_l3_type being set. Just in case. */
182         (*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
183                      RTE_PTYPE_L4_NONFRAG;
184         (*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
185                      RTE_PTYPE_L4_NONFRAG;
186         (*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
187                      RTE_PTYPE_L4_FRAG;
188         (*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
189                      RTE_PTYPE_L4_FRAG;
190         (*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
191                      RTE_PTYPE_L4_TCP;
192         (*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
193                      RTE_PTYPE_L4_TCP;
194         (*p)[0x8d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
195                      RTE_PTYPE_L4_TCP;
196         (*p)[0x8e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
197                      RTE_PTYPE_L4_TCP;
198         (*p)[0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
199                      RTE_PTYPE_L4_TCP;
200         (*p)[0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
201                      RTE_PTYPE_L4_TCP;
202         (*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
203                      RTE_PTYPE_L4_UDP;
204         (*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
205                      RTE_PTYPE_L4_UDP;
206         /* Tunneled - L3 */
207         (*p)[0x40] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
208         (*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
209                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
210                      RTE_PTYPE_INNER_L4_NONFRAG;
211         (*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
212                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
213                      RTE_PTYPE_INNER_L4_NONFRAG;
214         (*p)[0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
215         (*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
216                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
217                      RTE_PTYPE_INNER_L4_NONFRAG;
218         (*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
219                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
220                      RTE_PTYPE_INNER_L4_NONFRAG;
221         /* Tunneled - Fragmented */
222         (*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
223                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
224                      RTE_PTYPE_INNER_L4_FRAG;
225         (*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
226                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
227                      RTE_PTYPE_INNER_L4_FRAG;
228         (*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
229                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
230                      RTE_PTYPE_INNER_L4_FRAG;
231         (*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
232                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
233                      RTE_PTYPE_INNER_L4_FRAG;
234         /* Tunneled - TCP */
235         (*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
236                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
237                      RTE_PTYPE_INNER_L4_TCP;
238         (*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
239                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
240                      RTE_PTYPE_INNER_L4_TCP;
241         (*p)[0x4d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
242                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
243                      RTE_PTYPE_INNER_L4_TCP;
244         (*p)[0x4e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
245                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
246                      RTE_PTYPE_INNER_L4_TCP;
247         (*p)[0x51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
248                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
249                      RTE_PTYPE_INNER_L4_TCP;
250         (*p)[0x52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
251                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
252                      RTE_PTYPE_INNER_L4_TCP;
253         (*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
254                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
255                      RTE_PTYPE_INNER_L4_TCP;
256         (*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
257                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
258                      RTE_PTYPE_INNER_L4_TCP;
259         (*p)[0xcd] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
260                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
261                      RTE_PTYPE_INNER_L4_TCP;
262         (*p)[0xce] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
263                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
264                      RTE_PTYPE_INNER_L4_TCP;
265         (*p)[0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
266                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
267                      RTE_PTYPE_INNER_L4_TCP;
268         (*p)[0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
269                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
270                      RTE_PTYPE_INNER_L4_TCP;
271         /* Tunneled - UDP */
272         (*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
273                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
274                      RTE_PTYPE_INNER_L4_UDP;
275         (*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
276                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
277                      RTE_PTYPE_INNER_L4_UDP;
278         (*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
279                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
280                      RTE_PTYPE_INNER_L4_UDP;
281         (*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
282                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
283                      RTE_PTYPE_INNER_L4_UDP;
284 }
285
286 /**
287  * Build a table to translate packet to checksum type of Verbs.
288  */
289 void
290 mlx5_set_cksum_table(void)
291 {
292         unsigned int i;
293         uint8_t v;
294
295         /*
296          * The index should have:
297          * bit[0] = PKT_TX_TCP_SEG
298          * bit[2:3] = PKT_TX_UDP_CKSUM, PKT_TX_TCP_CKSUM
299          * bit[4] = PKT_TX_IP_CKSUM
300          * bit[8] = PKT_TX_OUTER_IP_CKSUM
301          * bit[9] = tunnel
302          */
303         for (i = 0; i < RTE_DIM(mlx5_cksum_table); ++i) {
304                 v = 0;
305                 if (i & (1 << 9)) {
306                         /* Tunneled packet. */
307                         if (i & (1 << 8)) /* Outer IP. */
308                                 v |= MLX5_ETH_WQE_L3_CSUM;
309                         if (i & (1 << 4)) /* Inner IP. */
310                                 v |= MLX5_ETH_WQE_L3_INNER_CSUM;
311                         if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
312                                 v |= MLX5_ETH_WQE_L4_INNER_CSUM;
313                 } else {
314                         /* No tunnel. */
315                         if (i & (1 << 4)) /* IP. */
316                                 v |= MLX5_ETH_WQE_L3_CSUM;
317                         if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
318                                 v |= MLX5_ETH_WQE_L4_CSUM;
319                 }
320                 mlx5_cksum_table[i] = v;
321         }
322 }
323
324 /**
325  * Build a table to translate packet type of mbuf to SWP type of Verbs.
326  */
327 void
328 mlx5_set_swp_types_table(void)
329 {
330         unsigned int i;
331         uint8_t v;
332
333         /*
334          * The index should have:
335          * bit[0:1] = PKT_TX_L4_MASK
336          * bit[4] = PKT_TX_IPV6
337          * bit[8] = PKT_TX_OUTER_IPV6
338          * bit[9] = PKT_TX_OUTER_UDP
339          */
340         for (i = 0; i < RTE_DIM(mlx5_swp_types_table); ++i) {
341                 v = 0;
342                 if (i & (1 << 8))
343                         v |= MLX5_ETH_WQE_L3_OUTER_IPV6;
344                 if (i & (1 << 9))
345                         v |= MLX5_ETH_WQE_L4_OUTER_UDP;
346                 if (i & (1 << 4))
347                         v |= MLX5_ETH_WQE_L3_INNER_IPV6;
348                 if ((i & 3) == (PKT_TX_UDP_CKSUM >> 52))
349                         v |= MLX5_ETH_WQE_L4_INNER_UDP;
350                 mlx5_swp_types_table[i] = v;
351         }
352 }
353
354 /**
355  * Set Software Parser flags and offsets in Ethernet Segment of WQE.
356  * Flags must be preliminary initialized to zero.
357  *
358  * @param loc
359  *   Pointer to burst routine local context.
360  * @param swp_flags
361  *   Pointer to store Software Parser flags
362  * @param olx
363  *   Configured Tx offloads mask. It is fully defined at
364  *   compile time and may be used for optimization.
365  *
366  * @return
367  *   Software Parser offsets packed in dword.
368  *   Software Parser flags are set by pointer.
369  */
370 static __rte_always_inline uint32_t
371 txq_mbuf_to_swp(struct mlx5_txq_local *restrict loc,
372                 uint8_t *swp_flags,
373                 unsigned int olx)
374 {
375         uint64_t ol, tunnel;
376         unsigned int idx, off;
377         uint32_t set;
378
379         if (!MLX5_TXOFF_CONFIG(SWP))
380                 return 0;
381         ol = loc->mbuf->ol_flags;
382         tunnel = ol & PKT_TX_TUNNEL_MASK;
383         /*
384          * Check whether Software Parser is required.
385          * Only customized tunnels may ask for.
386          */
387         if (likely(tunnel != PKT_TX_TUNNEL_UDP && tunnel != PKT_TX_TUNNEL_IP))
388                 return 0;
389         /*
390          * The index should have:
391          * bit[0:1] = PKT_TX_L4_MASK
392          * bit[4] = PKT_TX_IPV6
393          * bit[8] = PKT_TX_OUTER_IPV6
394          * bit[9] = PKT_TX_OUTER_UDP
395          */
396         idx = (ol & (PKT_TX_L4_MASK | PKT_TX_IPV6 | PKT_TX_OUTER_IPV6)) >> 52;
397         idx |= (tunnel == PKT_TX_TUNNEL_UDP) ? (1 << 9) : 0;
398         *swp_flags = mlx5_swp_types_table[idx];
399         /*
400          * Set offsets for SW parser. Since ConnectX-5, SW parser just
401          * complements HW parser. SW parser starts to engage only if HW parser
402          * can't reach a header. For the older devices, HW parser will not kick
403          * in if any of SWP offsets is set. Therefore, all of the L3 offsets
404          * should be set regardless of HW offload.
405          */
406         off = loc->mbuf->outer_l2_len;
407         if (MLX5_TXOFF_CONFIG(VLAN) && ol & PKT_TX_VLAN_PKT)
408                 off += sizeof(struct rte_vlan_hdr);
409         set = (off >> 1) << 8; /* Outer L3 offset. */
410         off += loc->mbuf->outer_l3_len;
411         if (tunnel == PKT_TX_TUNNEL_UDP)
412                 set |= off >> 1; /* Outer L4 offset. */
413         if (ol & (PKT_TX_IPV4 | PKT_TX_IPV6)) { /* Inner IP. */
414                 const uint64_t csum = ol & PKT_TX_L4_MASK;
415                         off += loc->mbuf->l2_len;
416                 set |= (off >> 1) << 24; /* Inner L3 offset. */
417                 if (csum == PKT_TX_TCP_CKSUM ||
418                     csum == PKT_TX_UDP_CKSUM ||
419                     (MLX5_TXOFF_CONFIG(TSO) && ol & PKT_TX_TCP_SEG)) {
420                         off += loc->mbuf->l3_len;
421                         set |= (off >> 1) << 16; /* Inner L4 offset. */
422                 }
423         }
424         set = rte_cpu_to_le_32(set);
425         return set;
426 }
427
428 /**
429  * Convert the Checksum offloads to Verbs.
430  *
431  * @param buf
432  *   Pointer to the mbuf.
433  *
434  * @return
435  *   Converted checksum flags.
436  */
437 static __rte_always_inline uint8_t
438 txq_ol_cksum_to_cs(struct rte_mbuf *buf)
439 {
440         uint32_t idx;
441         uint8_t is_tunnel = !!(buf->ol_flags & PKT_TX_TUNNEL_MASK);
442         const uint64_t ol_flags_mask = PKT_TX_TCP_SEG | PKT_TX_L4_MASK |
443                                        PKT_TX_IP_CKSUM | PKT_TX_OUTER_IP_CKSUM;
444
445         /*
446          * The index should have:
447          * bit[0] = PKT_TX_TCP_SEG
448          * bit[2:3] = PKT_TX_UDP_CKSUM, PKT_TX_TCP_CKSUM
449          * bit[4] = PKT_TX_IP_CKSUM
450          * bit[8] = PKT_TX_OUTER_IP_CKSUM
451          * bit[9] = tunnel
452          */
453         idx = ((buf->ol_flags & ol_flags_mask) >> 50) | (!!is_tunnel << 9);
454         return mlx5_cksum_table[idx];
455 }
456
457 /**
458  * Internal function to compute the number of used descriptors in an RX queue
459  *
460  * @param rxq
461  *   The Rx queue.
462  *
463  * @return
464  *   The number of used rx descriptor.
465  */
466 static uint32_t
467 rx_queue_count(struct mlx5_rxq_data *rxq)
468 {
469         struct rxq_zip *zip = &rxq->zip;
470         volatile struct mlx5_cqe *cqe;
471         const unsigned int cqe_n = (1 << rxq->cqe_n);
472         const unsigned int cqe_cnt = cqe_n - 1;
473         unsigned int cq_ci;
474         unsigned int used;
475
476         /* if we are processing a compressed cqe */
477         if (zip->ai) {
478                 used = zip->cqe_cnt - zip->ca;
479                 cq_ci = zip->cq_ci;
480         } else {
481                 used = 0;
482                 cq_ci = rxq->cq_ci;
483         }
484         cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
485         while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) {
486                 int8_t op_own;
487                 unsigned int n;
488
489                 op_own = cqe->op_own;
490                 if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
491                         n = rte_be_to_cpu_32(cqe->byte_cnt);
492                 else
493                         n = 1;
494                 cq_ci += n;
495                 used += n;
496                 cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
497         }
498         used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
499         return used;
500 }
501
502 /**
503  * DPDK callback to check the status of a rx descriptor.
504  *
505  * @param rx_queue
506  *   The Rx queue.
507  * @param[in] offset
508  *   The index of the descriptor in the ring.
509  *
510  * @return
511  *   The status of the tx descriptor.
512  */
513 int
514 mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
515 {
516         struct mlx5_rxq_data *rxq = rx_queue;
517         struct mlx5_rxq_ctrl *rxq_ctrl =
518                         container_of(rxq, struct mlx5_rxq_ctrl, rxq);
519         struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv);
520
521         if (dev->rx_pkt_burst != mlx5_rx_burst) {
522                 rte_errno = ENOTSUP;
523                 return -rte_errno;
524         }
525         if (offset >= (1 << rxq->elts_n)) {
526                 rte_errno = EINVAL;
527                 return -rte_errno;
528         }
529         if (offset < rx_queue_count(rxq))
530                 return RTE_ETH_RX_DESC_DONE;
531         return RTE_ETH_RX_DESC_AVAIL;
532 }
533
534 /**
535  * DPDK callback to get the number of used descriptors in a RX queue
536  *
537  * @param dev
538  *   Pointer to the device structure.
539  *
540  * @param rx_queue_id
541  *   The Rx queue.
542  *
543  * @return
544  *   The number of used rx descriptor.
545  *   -EINVAL if the queue is invalid
546  */
547 uint32_t
548 mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
549 {
550         struct mlx5_priv *priv = dev->data->dev_private;
551         struct mlx5_rxq_data *rxq;
552
553         if (dev->rx_pkt_burst != mlx5_rx_burst) {
554                 rte_errno = ENOTSUP;
555                 return -rte_errno;
556         }
557         rxq = (*priv->rxqs)[rx_queue_id];
558         if (!rxq) {
559                 rte_errno = EINVAL;
560                 return -rte_errno;
561         }
562         return rx_queue_count(rxq);
563 }
564
565 #define MLX5_SYSTEM_LOG_DIR "/var/log"
566 /**
567  * Dump debug information to log file.
568  *
569  * @param fname
570  *   The file name.
571  * @param hex_title
572  *   If not NULL this string is printed as a header to the output
573  *   and the output will be in hexadecimal view.
574  * @param buf
575  *   This is the buffer address to print out.
576  * @param len
577  *   The number of bytes to dump out.
578  */
579 void
580 mlx5_dump_debug_information(const char *fname, const char *hex_title,
581                             const void *buf, unsigned int hex_len)
582 {
583         FILE *fd;
584
585         MKSTR(path, "%s/%s", MLX5_SYSTEM_LOG_DIR, fname);
586         fd = fopen(path, "a+");
587         if (!fd) {
588                 DRV_LOG(WARNING, "cannot open %s for debug dump", path);
589                 MKSTR(path2, "./%s", fname);
590                 fd = fopen(path2, "a+");
591                 if (!fd) {
592                         DRV_LOG(ERR, "cannot open %s for debug dump", path2);
593                         return;
594                 }
595                 DRV_LOG(INFO, "New debug dump in file %s", path2);
596         } else {
597                 DRV_LOG(INFO, "New debug dump in file %s", path);
598         }
599         if (hex_title)
600                 rte_hexdump(fd, hex_title, buf, hex_len);
601         else
602                 fprintf(fd, "%s", (const char *)buf);
603         fprintf(fd, "\n\n\n");
604         fclose(fd);
605 }
606
607 /**
608  * Move QP from error state to running state and initialize indexes.
609  *
610  * @param txq_ctrl
611  *   Pointer to TX queue control structure.
612  *
613  * @return
614  *   0 on success, else -1.
615  */
616 static int
617 tx_recover_qp(struct mlx5_txq_ctrl *txq_ctrl)
618 {
619         struct mlx5_mp_arg_queue_state_modify sm = {
620                         .is_wq = 0,
621                         .queue_id = txq_ctrl->txq.idx,
622         };
623
624         if (mlx5_queue_state_modify(ETH_DEV(txq_ctrl->priv), &sm))
625                 return -1;
626         txq_ctrl->txq.wqe_ci = 0;
627         txq_ctrl->txq.wqe_pi = 0;
628         txq_ctrl->txq.elts_comp = 0;
629         return 0;
630 }
631
632 /* Return 1 if the error CQE is signed otherwise, sign it and return 0. */
633 static int
634 check_err_cqe_seen(volatile struct mlx5_err_cqe *err_cqe)
635 {
636         static const uint8_t magic[] = "seen";
637         int ret = 1;
638         unsigned int i;
639
640         for (i = 0; i < sizeof(magic); ++i)
641                 if (!ret || err_cqe->rsvd1[i] != magic[i]) {
642                         ret = 0;
643                         err_cqe->rsvd1[i] = magic[i];
644                 }
645         return ret;
646 }
647
648 /**
649  * Handle error CQE.
650  *
651  * @param txq
652  *   Pointer to TX queue structure.
653  * @param error_cqe
654  *   Pointer to the error CQE.
655  *
656  * @return
657  *   Negative value if queue recovery failed,
658  *   the last Tx buffer element to free otherwise.
659  */
660 int
661 mlx5_tx_error_cqe_handle(struct mlx5_txq_data *restrict txq,
662                          volatile struct mlx5_err_cqe *err_cqe)
663 {
664         if (err_cqe->syndrome != MLX5_CQE_SYNDROME_WR_FLUSH_ERR) {
665                 const uint16_t wqe_m = ((1 << txq->wqe_n) - 1);
666                 struct mlx5_txq_ctrl *txq_ctrl =
667                                 container_of(txq, struct mlx5_txq_ctrl, txq);
668                 uint16_t new_wqe_pi = rte_be_to_cpu_16(err_cqe->wqe_counter);
669                 int seen = check_err_cqe_seen(err_cqe);
670
671                 if (!seen && txq_ctrl->dump_file_n <
672                     txq_ctrl->priv->config.max_dump_files_num) {
673                         MKSTR(err_str, "Unexpected CQE error syndrome "
674                               "0x%02x CQN = %u SQN = %u wqe_counter = %u "
675                               "wq_ci = %u cq_ci = %u", err_cqe->syndrome,
676                               txq->cqe_s, txq->qp_num_8s >> 8,
677                               rte_be_to_cpu_16(err_cqe->wqe_counter),
678                               txq->wqe_ci, txq->cq_ci);
679                         MKSTR(name, "dpdk_mlx5_port_%u_txq_%u_index_%u_%u",
680                               PORT_ID(txq_ctrl->priv), txq->idx,
681                               txq_ctrl->dump_file_n, (uint32_t)rte_rdtsc());
682                         mlx5_dump_debug_information(name, NULL, err_str, 0);
683                         mlx5_dump_debug_information(name, "MLX5 Error CQ:",
684                                                     (const void *)((uintptr_t)
685                                                     txq->cqes),
686                                                     sizeof(*err_cqe) *
687                                                     (1 << txq->cqe_n));
688                         mlx5_dump_debug_information(name, "MLX5 Error SQ:",
689                                                     (const void *)((uintptr_t)
690                                                     txq->wqes),
691                                                     MLX5_WQE_SIZE *
692                                                     (1 << txq->wqe_n));
693                         txq_ctrl->dump_file_n++;
694                 }
695                 if (!seen)
696                         /*
697                          * Count errors in WQEs units.
698                          * Later it can be improved to count error packets,
699                          * for example, by SQ parsing to find how much packets
700                          * should be counted for each WQE.
701                          */
702                         txq->stats.oerrors += ((txq->wqe_ci & wqe_m) -
703                                                 new_wqe_pi) & wqe_m;
704                 if (tx_recover_qp(txq_ctrl) == 0) {
705                         txq->cq_ci++;
706                         /* Release all the remaining buffers. */
707                         return txq->elts_head;
708                 }
709                 /* Recovering failed - try again later on the same WQE. */
710                 return -1;
711         } else {
712                 txq->cq_ci++;
713         }
714         /* Do not release buffers. */
715         return txq->elts_tail;
716 }
717
718 /**
719  * Translate RX completion flags to packet type.
720  *
721  * @param[in] rxq
722  *   Pointer to RX queue structure.
723  * @param[in] cqe
724  *   Pointer to CQE.
725  *
726  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
727  *
728  * @return
729  *   Packet type for struct rte_mbuf.
730  */
731 static inline uint32_t
732 rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe)
733 {
734         uint8_t idx;
735         uint8_t pinfo = cqe->pkt_info;
736         uint16_t ptype = cqe->hdr_type_etc;
737
738         /*
739          * The index to the array should have:
740          * bit[1:0] = l3_hdr_type
741          * bit[4:2] = l4_hdr_type
742          * bit[5] = ip_frag
743          * bit[6] = tunneled
744          * bit[7] = outer_l3_type
745          */
746         idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
747         return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
748 }
749
750 /**
751  * Initialize Rx WQ and indexes.
752  *
753  * @param[in] rxq
754  *   Pointer to RX queue structure.
755  */
756 void
757 mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
758 {
759         const unsigned int wqe_n = 1 << rxq->elts_n;
760         unsigned int i;
761
762         for (i = 0; (i != wqe_n); ++i) {
763                 volatile struct mlx5_wqe_data_seg *scat;
764                 uintptr_t addr;
765                 uint32_t byte_count;
766
767                 if (mlx5_rxq_mprq_enabled(rxq)) {
768                         struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
769
770                         scat = &((volatile struct mlx5_wqe_mprq *)
771                                 rxq->wqes)[i].dseg;
772                         addr = (uintptr_t)mlx5_mprq_buf_addr(buf,
773                                                          1 << rxq->strd_num_n);
774                         byte_count = (1 << rxq->strd_sz_n) *
775                                         (1 << rxq->strd_num_n);
776                 } else {
777                         struct rte_mbuf *buf = (*rxq->elts)[i];
778
779                         scat = &((volatile struct mlx5_wqe_data_seg *)
780                                         rxq->wqes)[i];
781                         addr = rte_pktmbuf_mtod(buf, uintptr_t);
782                         byte_count = DATA_LEN(buf);
783                 }
784                 /* scat->addr must be able to store a pointer. */
785                 assert(sizeof(scat->addr) >= sizeof(uintptr_t));
786                 *scat = (struct mlx5_wqe_data_seg){
787                         .addr = rte_cpu_to_be_64(addr),
788                         .byte_count = rte_cpu_to_be_32(byte_count),
789                         .lkey = mlx5_rx_addr2mr(rxq, addr),
790                 };
791         }
792         rxq->consumed_strd = 0;
793         rxq->decompressed = 0;
794         rxq->rq_pi = 0;
795         rxq->zip = (struct rxq_zip){
796                 .ai = 0,
797         };
798         /* Update doorbell counter. */
799         rxq->rq_ci = wqe_n >> rxq->sges_n;
800         rte_cio_wmb();
801         *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
802 }
803
804 /**
805  * Modify a Verbs/DevX queue state.
806  * This must be called from the primary process.
807  *
808  * @param dev
809  *   Pointer to Ethernet device.
810  * @param sm
811  *   State modify request parameters.
812  *
813  * @return
814  *   0 in case of success else non-zero value and rte_errno is set.
815  */
816 int
817 mlx5_queue_state_modify_primary(struct rte_eth_dev *dev,
818                         const struct mlx5_mp_arg_queue_state_modify *sm)
819 {
820         int ret;
821         struct mlx5_priv *priv = dev->data->dev_private;
822
823         if (sm->is_wq) {
824                 struct mlx5_rxq_data *rxq = (*priv->rxqs)[sm->queue_id];
825                 struct mlx5_rxq_ctrl *rxq_ctrl =
826                         container_of(rxq, struct mlx5_rxq_ctrl, rxq);
827
828                 if (rxq_ctrl->obj->type == MLX5_RXQ_OBJ_TYPE_IBV) {
829                         struct ibv_wq_attr mod = {
830                                 .attr_mask = IBV_WQ_ATTR_STATE,
831                                 .wq_state = sm->state,
832                         };
833
834                         ret = mlx5_glue->modify_wq(rxq_ctrl->obj->wq, &mod);
835                 } else { /* rxq_ctrl->obj->type == MLX5_RXQ_OBJ_TYPE_DEVX_RQ. */
836                         struct mlx5_devx_modify_rq_attr rq_attr;
837
838                         memset(&rq_attr, 0, sizeof(rq_attr));
839                         if (sm->state == IBV_WQS_RESET) {
840                                 rq_attr.rq_state = MLX5_RQC_STATE_ERR;
841                                 rq_attr.state = MLX5_RQC_STATE_RST;
842                         } else if (sm->state == IBV_WQS_RDY) {
843                                 rq_attr.rq_state = MLX5_RQC_STATE_RST;
844                                 rq_attr.state = MLX5_RQC_STATE_RDY;
845                         } else if (sm->state == IBV_WQS_ERR) {
846                                 rq_attr.rq_state = MLX5_RQC_STATE_RDY;
847                                 rq_attr.state = MLX5_RQC_STATE_ERR;
848                         }
849                         ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq,
850                                                       &rq_attr);
851                 }
852                 if (ret) {
853                         DRV_LOG(ERR, "Cannot change Rx WQ state to %u  - %s",
854                                         sm->state, strerror(errno));
855                         rte_errno = errno;
856                         return ret;
857                 }
858         } else {
859                 struct mlx5_txq_data *txq = (*priv->txqs)[sm->queue_id];
860                 struct mlx5_txq_ctrl *txq_ctrl =
861                         container_of(txq, struct mlx5_txq_ctrl, txq);
862                 struct ibv_qp_attr mod = {
863                         .qp_state = IBV_QPS_RESET,
864                         .port_num = (uint8_t)priv->ibv_port,
865                 };
866                 struct ibv_qp *qp = txq_ctrl->obj->qp;
867
868                 ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
869                 if (ret) {
870                         DRV_LOG(ERR, "Cannot change the Tx QP state to RESET "
871                                 "%s", strerror(errno));
872                         rte_errno = errno;
873                         return ret;
874                 }
875                 mod.qp_state = IBV_QPS_INIT;
876                 ret = mlx5_glue->modify_qp(qp, &mod,
877                                            (IBV_QP_STATE | IBV_QP_PORT));
878                 if (ret) {
879                         DRV_LOG(ERR, "Cannot change Tx QP state to INIT %s",
880                                 strerror(errno));
881                         rte_errno = errno;
882                         return ret;
883                 }
884                 mod.qp_state = IBV_QPS_RTR;
885                 ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
886                 if (ret) {
887                         DRV_LOG(ERR, "Cannot change Tx QP state to RTR %s",
888                                 strerror(errno));
889                         rte_errno = errno;
890                         return ret;
891                 }
892                 mod.qp_state = IBV_QPS_RTS;
893                 ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
894                 if (ret) {
895                         DRV_LOG(ERR, "Cannot change Tx QP state to RTS %s",
896                                 strerror(errno));
897                         rte_errno = errno;
898                         return ret;
899                 }
900         }
901         return 0;
902 }
903
904 /**
905  * Modify a Verbs queue state.
906  *
907  * @param dev
908  *   Pointer to Ethernet device.
909  * @param sm
910  *   State modify request parameters.
911  *
912  * @return
913  *   0 in case of success else non-zero value.
914  */
915 static int
916 mlx5_queue_state_modify(struct rte_eth_dev *dev,
917                         struct mlx5_mp_arg_queue_state_modify *sm)
918 {
919         int ret = 0;
920
921         switch (rte_eal_process_type()) {
922         case RTE_PROC_PRIMARY:
923                 ret = mlx5_queue_state_modify_primary(dev, sm);
924                 break;
925         case RTE_PROC_SECONDARY:
926                 ret = mlx5_mp_req_queue_state_modify(dev, sm);
927                 break;
928         default:
929                 break;
930         }
931         return ret;
932 }
933
934 /**
935  * Handle a Rx error.
936  * The function inserts the RQ state to reset when the first error CQE is
937  * shown, then drains the CQ by the caller function loop. When the CQ is empty,
938  * it moves the RQ state to ready and initializes the RQ.
939  * Next CQE identification and error counting are in the caller responsibility.
940  *
941  * @param[in] rxq
942  *   Pointer to RX queue structure.
943  * @param[in] vec
944  *   1 when called from vectorized Rx burst, need to prepare mbufs for the RQ.
945  *   0 when called from non-vectorized Rx burst.
946  *
947  * @return
948  *   -1 in case of recovery error, otherwise the CQE status.
949  */
950 int
951 mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec)
952 {
953         const uint16_t cqe_n = 1 << rxq->cqe_n;
954         const uint16_t cqe_mask = cqe_n - 1;
955         const unsigned int wqe_n = 1 << rxq->elts_n;
956         struct mlx5_rxq_ctrl *rxq_ctrl =
957                         container_of(rxq, struct mlx5_rxq_ctrl, rxq);
958         union {
959                 volatile struct mlx5_cqe *cqe;
960                 volatile struct mlx5_err_cqe *err_cqe;
961         } u = {
962                 .cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask],
963         };
964         struct mlx5_mp_arg_queue_state_modify sm;
965         int ret;
966
967         switch (rxq->err_state) {
968         case MLX5_RXQ_ERR_STATE_NO_ERROR:
969                 rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET;
970                 /* Fall-through */
971         case MLX5_RXQ_ERR_STATE_NEED_RESET:
972                 sm.is_wq = 1;
973                 sm.queue_id = rxq->idx;
974                 sm.state = IBV_WQS_RESET;
975                 if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv), &sm))
976                         return -1;
977                 if (rxq_ctrl->dump_file_n <
978                     rxq_ctrl->priv->config.max_dump_files_num) {
979                         MKSTR(err_str, "Unexpected CQE error syndrome "
980                               "0x%02x CQN = %u RQN = %u wqe_counter = %u"
981                               " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome,
982                               rxq->cqn, rxq_ctrl->wqn,
983                               rte_be_to_cpu_16(u.err_cqe->wqe_counter),
984                               rxq->rq_ci << rxq->sges_n, rxq->cq_ci);
985                         MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u",
986                               rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc());
987                         mlx5_dump_debug_information(name, NULL, err_str, 0);
988                         mlx5_dump_debug_information(name, "MLX5 Error CQ:",
989                                                     (const void *)((uintptr_t)
990                                                                     rxq->cqes),
991                                                     sizeof(*u.cqe) * cqe_n);
992                         mlx5_dump_debug_information(name, "MLX5 Error RQ:",
993                                                     (const void *)((uintptr_t)
994                                                                     rxq->wqes),
995                                                     16 * wqe_n);
996                         rxq_ctrl->dump_file_n++;
997                 }
998                 rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY;
999                 /* Fall-through */
1000         case MLX5_RXQ_ERR_STATE_NEED_READY:
1001                 ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci);
1002                 if (ret == MLX5_CQE_STATUS_HW_OWN) {
1003                         rte_cio_wmb();
1004                         *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1005                         rte_cio_wmb();
1006                         /*
1007                          * The RQ consumer index must be zeroed while moving
1008                          * from RESET state to RDY state.
1009                          */
1010                         *rxq->rq_db = rte_cpu_to_be_32(0);
1011                         rte_cio_wmb();
1012                         sm.is_wq = 1;
1013                         sm.queue_id = rxq->idx;
1014                         sm.state = IBV_WQS_RDY;
1015                         if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv),
1016                                                     &sm))
1017                                 return -1;
1018                         if (vec) {
1019                                 const uint16_t q_mask = wqe_n - 1;
1020                                 uint16_t elt_idx;
1021                                 struct rte_mbuf **elt;
1022                                 int i;
1023                                 unsigned int n = wqe_n - (rxq->rq_ci -
1024                                                           rxq->rq_pi);
1025
1026                                 for (i = 0; i < (int)n; ++i) {
1027                                         elt_idx = (rxq->rq_ci + i) & q_mask;
1028                                         elt = &(*rxq->elts)[elt_idx];
1029                                         *elt = rte_mbuf_raw_alloc(rxq->mp);
1030                                         if (!*elt) {
1031                                                 for (i--; i >= 0; --i) {
1032                                                         elt_idx = (rxq->rq_ci +
1033                                                                    i) & q_mask;
1034                                                         elt = &(*rxq->elts)
1035                                                                 [elt_idx];
1036                                                         rte_pktmbuf_free_seg
1037                                                                 (*elt);
1038                                                 }
1039                                                 return -1;
1040                                         }
1041                                 }
1042                                 for (i = 0; i < (int)wqe_n; ++i) {
1043                                         elt = &(*rxq->elts)[i];
1044                                         DATA_LEN(*elt) =
1045                                                 (uint16_t)((*elt)->buf_len -
1046                                                 rte_pktmbuf_headroom(*elt));
1047                                 }
1048                                 /* Padding with a fake mbuf for vec Rx. */
1049                                 for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i)
1050                                         (*rxq->elts)[wqe_n + i] =
1051                                                                 &rxq->fake_mbuf;
1052                         }
1053                         mlx5_rxq_initialize(rxq);
1054                         rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
1055                 }
1056                 return ret;
1057         default:
1058                 return -1;
1059         }
1060 }
1061
1062 /**
1063  * Get size of the next packet for a given CQE. For compressed CQEs, the
1064  * consumer index is updated only once all packets of the current one have
1065  * been processed.
1066  *
1067  * @param rxq
1068  *   Pointer to RX queue.
1069  * @param cqe
1070  *   CQE to process.
1071  * @param[out] mcqe
1072  *   Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
1073  *   written.
1074  *
1075  * @return
1076  *   0 in case of empty CQE, otherwise the packet size in bytes.
1077  */
1078 static inline int
1079 mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
1080                  uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe)
1081 {
1082         struct rxq_zip *zip = &rxq->zip;
1083         uint16_t cqe_n = cqe_cnt + 1;
1084         int len;
1085         uint16_t idx, end;
1086
1087         do {
1088                 len = 0;
1089                 /* Process compressed data in the CQE and mini arrays. */
1090                 if (zip->ai) {
1091                         volatile struct mlx5_mini_cqe8 (*mc)[8] =
1092                                 (volatile struct mlx5_mini_cqe8 (*)[8])
1093                                 (uintptr_t)(&(*rxq->cqes)[zip->ca &
1094                                                           cqe_cnt].pkt_info);
1095
1096                         len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
1097                         *mcqe = &(*mc)[zip->ai & 7];
1098                         if ((++zip->ai & 7) == 0) {
1099                                 /* Invalidate consumed CQEs */
1100                                 idx = zip->ca;
1101                                 end = zip->na;
1102                                 while (idx != end) {
1103                                         (*rxq->cqes)[idx & cqe_cnt].op_own =
1104                                                 MLX5_CQE_INVALIDATE;
1105                                         ++idx;
1106                                 }
1107                                 /*
1108                                  * Increment consumer index to skip the number
1109                                  * of CQEs consumed. Hardware leaves holes in
1110                                  * the CQ ring for software use.
1111                                  */
1112                                 zip->ca = zip->na;
1113                                 zip->na += 8;
1114                         }
1115                         if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1116                                 /* Invalidate the rest */
1117                                 idx = zip->ca;
1118                                 end = zip->cq_ci;
1119
1120                                 while (idx != end) {
1121                                         (*rxq->cqes)[idx & cqe_cnt].op_own =
1122                                                 MLX5_CQE_INVALIDATE;
1123                                         ++idx;
1124                                 }
1125                                 rxq->cq_ci = zip->cq_ci;
1126                                 zip->ai = 0;
1127                         }
1128                 /*
1129                  * No compressed data, get next CQE and verify if it is
1130                  * compressed.
1131                  */
1132                 } else {
1133                         int ret;
1134                         int8_t op_own;
1135
1136                         ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
1137                         if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1138                                 if (unlikely(ret == MLX5_CQE_STATUS_ERR ||
1139                                              rxq->err_state)) {
1140                                         ret = mlx5_rx_err_handle(rxq, 0);
1141                                         if (ret == MLX5_CQE_STATUS_HW_OWN ||
1142                                             ret == -1)
1143                                                 return 0;
1144                                 } else {
1145                                         return 0;
1146                                 }
1147                         }
1148                         ++rxq->cq_ci;
1149                         op_own = cqe->op_own;
1150                         if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
1151                                 volatile struct mlx5_mini_cqe8 (*mc)[8] =
1152                                         (volatile struct mlx5_mini_cqe8 (*)[8])
1153                                         (uintptr_t)(&(*rxq->cqes)
1154                                                 [rxq->cq_ci &
1155                                                  cqe_cnt].pkt_info);
1156
1157                                 /* Fix endianness. */
1158                                 zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
1159                                 /*
1160                                  * Current mini array position is the one
1161                                  * returned by check_cqe64().
1162                                  *
1163                                  * If completion comprises several mini arrays,
1164                                  * as a special case the second one is located
1165                                  * 7 CQEs after the initial CQE instead of 8
1166                                  * for subsequent ones.
1167                                  */
1168                                 zip->ca = rxq->cq_ci;
1169                                 zip->na = zip->ca + 7;
1170                                 /* Compute the next non compressed CQE. */
1171                                 --rxq->cq_ci;
1172                                 zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
1173                                 /* Get packet size to return. */
1174                                 len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
1175                                 *mcqe = &(*mc)[0];
1176                                 zip->ai = 1;
1177                                 /* Prefetch all to be invalidated */
1178                                 idx = zip->ca;
1179                                 end = zip->cq_ci;
1180                                 while (idx != end) {
1181                                         rte_prefetch0(&(*rxq->cqes)[(idx) &
1182                                                                     cqe_cnt]);
1183                                         ++idx;
1184                                 }
1185                         } else {
1186                                 len = rte_be_to_cpu_32(cqe->byte_cnt);
1187                         }
1188                 }
1189                 if (unlikely(rxq->err_state)) {
1190                         cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1191                         ++rxq->stats.idropped;
1192                 } else {
1193                         return len;
1194                 }
1195         } while (1);
1196 }
1197
1198 /**
1199  * Translate RX completion flags to offload flags.
1200  *
1201  * @param[in] cqe
1202  *   Pointer to CQE.
1203  *
1204  * @return
1205  *   Offload flags (ol_flags) for struct rte_mbuf.
1206  */
1207 static inline uint32_t
1208 rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
1209 {
1210         uint32_t ol_flags = 0;
1211         uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
1212
1213         ol_flags =
1214                 TRANSPOSE(flags,
1215                           MLX5_CQE_RX_L3_HDR_VALID,
1216                           PKT_RX_IP_CKSUM_GOOD) |
1217                 TRANSPOSE(flags,
1218                           MLX5_CQE_RX_L4_HDR_VALID,
1219                           PKT_RX_L4_CKSUM_GOOD);
1220         return ol_flags;
1221 }
1222
1223 /**
1224  * Fill in mbuf fields from RX completion flags.
1225  * Note that pkt->ol_flags should be initialized outside of this function.
1226  *
1227  * @param rxq
1228  *   Pointer to RX queue.
1229  * @param pkt
1230  *   mbuf to fill.
1231  * @param cqe
1232  *   CQE to process.
1233  * @param rss_hash_res
1234  *   Packet RSS Hash result.
1235  */
1236 static inline void
1237 rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
1238                volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res)
1239 {
1240         /* Update packet information. */
1241         pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe);
1242         if (rss_hash_res && rxq->rss_hash) {
1243                 pkt->hash.rss = rss_hash_res;
1244                 pkt->ol_flags |= PKT_RX_RSS_HASH;
1245         }
1246         if (rxq->mark && MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1247                 pkt->ol_flags |= PKT_RX_FDIR;
1248                 if (cqe->sop_drop_qpn !=
1249                     rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
1250                         uint32_t mark = cqe->sop_drop_qpn;
1251
1252                         pkt->ol_flags |= PKT_RX_FDIR_ID;
1253                         pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
1254                 }
1255         }
1256         if (rte_flow_dynf_metadata_avail() && cqe->flow_table_metadata) {
1257                 pkt->ol_flags |= PKT_RX_DYNF_METADATA;
1258                 *RTE_FLOW_DYNF_METADATA(pkt) = cqe->flow_table_metadata;
1259         }
1260         if (rxq->csum)
1261                 pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
1262         if (rxq->vlan_strip &&
1263             (cqe->hdr_type_etc & rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
1264                 pkt->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
1265                 pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
1266         }
1267         if (rxq->hw_timestamp) {
1268                 pkt->timestamp = rte_be_to_cpu_64(cqe->timestamp);
1269                 pkt->ol_flags |= PKT_RX_TIMESTAMP;
1270         }
1271 }
1272
1273 /**
1274  * DPDK callback for RX.
1275  *
1276  * @param dpdk_rxq
1277  *   Generic pointer to RX queue structure.
1278  * @param[out] pkts
1279  *   Array to store received packets.
1280  * @param pkts_n
1281  *   Maximum number of packets in array.
1282  *
1283  * @return
1284  *   Number of packets successfully received (<= pkts_n).
1285  */
1286 uint16_t
1287 mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1288 {
1289         struct mlx5_rxq_data *rxq = dpdk_rxq;
1290         const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1291         const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
1292         const unsigned int sges_n = rxq->sges_n;
1293         struct rte_mbuf *pkt = NULL;
1294         struct rte_mbuf *seg = NULL;
1295         volatile struct mlx5_cqe *cqe =
1296                 &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1297         unsigned int i = 0;
1298         unsigned int rq_ci = rxq->rq_ci << sges_n;
1299         int len = 0; /* keep its value across iterations. */
1300
1301         while (pkts_n) {
1302                 unsigned int idx = rq_ci & wqe_cnt;
1303                 volatile struct mlx5_wqe_data_seg *wqe =
1304                         &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
1305                 struct rte_mbuf *rep = (*rxq->elts)[idx];
1306                 volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1307                 uint32_t rss_hash_res;
1308
1309                 if (pkt)
1310                         NEXT(seg) = rep;
1311                 seg = rep;
1312                 rte_prefetch0(seg);
1313                 rte_prefetch0(cqe);
1314                 rte_prefetch0(wqe);
1315                 rep = rte_mbuf_raw_alloc(rxq->mp);
1316                 if (unlikely(rep == NULL)) {
1317                         ++rxq->stats.rx_nombuf;
1318                         if (!pkt) {
1319                                 /*
1320                                  * no buffers before we even started,
1321                                  * bail out silently.
1322                                  */
1323                                 break;
1324                         }
1325                         while (pkt != seg) {
1326                                 assert(pkt != (*rxq->elts)[idx]);
1327                                 rep = NEXT(pkt);
1328                                 NEXT(pkt) = NULL;
1329                                 NB_SEGS(pkt) = 1;
1330                                 rte_mbuf_raw_free(pkt);
1331                                 pkt = rep;
1332                         }
1333                         break;
1334                 }
1335                 if (!pkt) {
1336                         cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1337                         len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe);
1338                         if (!len) {
1339                                 rte_mbuf_raw_free(rep);
1340                                 break;
1341                         }
1342                         pkt = seg;
1343                         assert(len >= (rxq->crc_present << 2));
1344                         pkt->ol_flags &= EXT_ATTACHED_MBUF;
1345                         /* If compressed, take hash result from mini-CQE. */
1346                         rss_hash_res = rte_be_to_cpu_32(mcqe == NULL ?
1347                                                         cqe->rx_hash_res :
1348                                                         mcqe->rx_hash_result);
1349                         rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
1350                         if (rxq->crc_present)
1351                                 len -= RTE_ETHER_CRC_LEN;
1352                         PKT_LEN(pkt) = len;
1353                         if (cqe->lro_num_seg > 1) {
1354                                 mlx5_lro_update_hdr
1355                                         (rte_pktmbuf_mtod(pkt, uint8_t *), cqe,
1356                                          len);
1357                                 pkt->ol_flags |= PKT_RX_LRO;
1358                                 pkt->tso_segsz = len / cqe->lro_num_seg;
1359                         }
1360                 }
1361                 DATA_LEN(rep) = DATA_LEN(seg);
1362                 PKT_LEN(rep) = PKT_LEN(seg);
1363                 SET_DATA_OFF(rep, DATA_OFF(seg));
1364                 PORT(rep) = PORT(seg);
1365                 (*rxq->elts)[idx] = rep;
1366                 /*
1367                  * Fill NIC descriptor with the new buffer.  The lkey and size
1368                  * of the buffers are already known, only the buffer address
1369                  * changes.
1370                  */
1371                 wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
1372                 /* If there's only one MR, no need to replace LKey in WQE. */
1373                 if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1374                         wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
1375                 if (len > DATA_LEN(seg)) {
1376                         len -= DATA_LEN(seg);
1377                         ++NB_SEGS(pkt);
1378                         ++rq_ci;
1379                         continue;
1380                 }
1381                 DATA_LEN(seg) = len;
1382 #ifdef MLX5_PMD_SOFT_COUNTERS
1383                 /* Increment bytes counter. */
1384                 rxq->stats.ibytes += PKT_LEN(pkt);
1385 #endif
1386                 /* Return packet. */
1387                 *(pkts++) = pkt;
1388                 pkt = NULL;
1389                 --pkts_n;
1390                 ++i;
1391                 /* Align consumer index to the next stride. */
1392                 rq_ci >>= sges_n;
1393                 ++rq_ci;
1394                 rq_ci <<= sges_n;
1395         }
1396         if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
1397                 return 0;
1398         /* Update the consumer index. */
1399         rxq->rq_ci = rq_ci >> sges_n;
1400         rte_cio_wmb();
1401         *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1402         rte_cio_wmb();
1403         *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1404 #ifdef MLX5_PMD_SOFT_COUNTERS
1405         /* Increment packets counter. */
1406         rxq->stats.ipackets += i;
1407 #endif
1408         return i;
1409 }
1410
1411 /**
1412  * Update LRO packet TCP header.
1413  * The HW LRO feature doesn't update the TCP header after coalescing the
1414  * TCP segments but supplies information in CQE to fill it by SW.
1415  *
1416  * @param tcp
1417  *   Pointer to the TCP header.
1418  * @param cqe
1419  *   Pointer to the completion entry..
1420  * @param phcsum
1421  *   The L3 pseudo-header checksum.
1422  */
1423 static inline void
1424 mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *restrict tcp,
1425                         volatile struct mlx5_cqe *restrict cqe,
1426                         uint32_t phcsum)
1427 {
1428         uint8_t l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) &
1429                            MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1430         /*
1431          * The HW calculates only the TCP payload checksum, need to complete
1432          * the TCP header checksum and the L3 pseudo-header checksum.
1433          */
1434         uint32_t csum = phcsum + cqe->csum;
1435
1436         if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK ||
1437             l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) {
1438                 tcp->tcp_flags |= RTE_TCP_ACK_FLAG;
1439                 tcp->recv_ack = cqe->lro_ack_seq_num;
1440                 tcp->rx_win = cqe->lro_tcp_win;
1441         }
1442         if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK)
1443                 tcp->tcp_flags |= RTE_TCP_PSH_FLAG;
1444         tcp->cksum = 0;
1445         csum += rte_raw_cksum(tcp, (tcp->data_off & 0xF) * 4);
1446         csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
1447         csum = (~csum) & 0xffff;
1448         if (csum == 0)
1449                 csum = 0xffff;
1450         tcp->cksum = csum;
1451 }
1452
1453 /**
1454  * Update LRO packet headers.
1455  * The HW LRO feature doesn't update the L3/TCP headers after coalescing the
1456  * TCP segments but supply information in CQE to fill it by SW.
1457  *
1458  * @param padd
1459  *   The packet address.
1460  * @param cqe
1461  *   Pointer to the completion entry..
1462  * @param len
1463  *   The packet length.
1464  */
1465 static inline void
1466 mlx5_lro_update_hdr(uint8_t *restrict padd,
1467                     volatile struct mlx5_cqe *restrict cqe,
1468                     uint32_t len)
1469 {
1470         union {
1471                 struct rte_ether_hdr *eth;
1472                 struct rte_vlan_hdr *vlan;
1473                 struct rte_ipv4_hdr *ipv4;
1474                 struct rte_ipv6_hdr *ipv6;
1475                 struct rte_tcp_hdr *tcp;
1476                 uint8_t *hdr;
1477         } h = {
1478                         .hdr = padd,
1479         };
1480         uint16_t proto = h.eth->ether_type;
1481         uint32_t phcsum;
1482
1483         h.eth++;
1484         while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
1485                proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
1486                 proto = h.vlan->eth_proto;
1487                 h.vlan++;
1488         }
1489         if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
1490                 h.ipv4->time_to_live = cqe->lro_min_ttl;
1491                 h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd));
1492                 h.ipv4->hdr_checksum = 0;
1493                 h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4);
1494                 phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0);
1495                 h.ipv4++;
1496         } else {
1497                 h.ipv6->hop_limits = cqe->lro_min_ttl;
1498                 h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) -
1499                                                        sizeof(*h.ipv6));
1500                 phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0);
1501                 h.ipv6++;
1502         }
1503         mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum);
1504 }
1505
1506 void
1507 mlx5_mprq_buf_free_cb(void *addr __rte_unused, void *opaque)
1508 {
1509         struct mlx5_mprq_buf *buf = opaque;
1510
1511         if (rte_atomic16_read(&buf->refcnt) == 1) {
1512                 rte_mempool_put(buf->mp, buf);
1513         } else if (rte_atomic16_add_return(&buf->refcnt, -1) == 0) {
1514                 rte_atomic16_set(&buf->refcnt, 1);
1515                 rte_mempool_put(buf->mp, buf);
1516         }
1517 }
1518
1519 void
1520 mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
1521 {
1522         mlx5_mprq_buf_free_cb(NULL, buf);
1523 }
1524
1525 static inline void
1526 mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx,
1527                  const unsigned int strd_n)
1528 {
1529         struct mlx5_mprq_buf *rep = rxq->mprq_repl;
1530         volatile struct mlx5_wqe_data_seg *wqe =
1531                 &((volatile struct mlx5_wqe_mprq *)rxq->wqes)[rq_idx].dseg;
1532         void *addr;
1533
1534         assert(rep != NULL);
1535         /* Replace MPRQ buf. */
1536         (*rxq->mprq_bufs)[rq_idx] = rep;
1537         /* Replace WQE. */
1538         addr = mlx5_mprq_buf_addr(rep, strd_n);
1539         wqe->addr = rte_cpu_to_be_64((uintptr_t)addr);
1540         /* If there's only one MR, no need to replace LKey in WQE. */
1541         if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1542                 wqe->lkey = mlx5_rx_addr2mr(rxq, (uintptr_t)addr);
1543         /* Stash a mbuf for next replacement. */
1544         if (likely(!rte_mempool_get(rxq->mprq_mp, (void **)&rep)))
1545                 rxq->mprq_repl = rep;
1546         else
1547                 rxq->mprq_repl = NULL;
1548 }
1549
1550 /**
1551  * DPDK callback for RX with Multi-Packet RQ support.
1552  *
1553  * @param dpdk_rxq
1554  *   Generic pointer to RX queue structure.
1555  * @param[out] pkts
1556  *   Array to store received packets.
1557  * @param pkts_n
1558  *   Maximum number of packets in array.
1559  *
1560  * @return
1561  *   Number of packets successfully received (<= pkts_n).
1562  */
1563 uint16_t
1564 mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1565 {
1566         struct mlx5_rxq_data *rxq = dpdk_rxq;
1567         const unsigned int strd_n = 1 << rxq->strd_num_n;
1568         const unsigned int strd_sz = 1 << rxq->strd_sz_n;
1569         const unsigned int strd_shift =
1570                 MLX5_MPRQ_STRIDE_SHIFT_BYTE * rxq->strd_shift_en;
1571         const unsigned int cq_mask = (1 << rxq->cqe_n) - 1;
1572         const unsigned int wq_mask = (1 << rxq->elts_n) - 1;
1573         volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1574         unsigned int i = 0;
1575         uint32_t rq_ci = rxq->rq_ci;
1576         uint16_t consumed_strd = rxq->consumed_strd;
1577         uint16_t headroom_sz = rxq->strd_headroom_en * RTE_PKTMBUF_HEADROOM;
1578         struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1579
1580         while (i < pkts_n) {
1581                 struct rte_mbuf *pkt;
1582                 void *addr;
1583                 int ret;
1584                 unsigned int len;
1585                 uint16_t strd_cnt;
1586                 uint16_t strd_idx;
1587                 uint32_t offset;
1588                 uint32_t byte_cnt;
1589                 volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1590                 uint32_t rss_hash_res = 0;
1591                 uint8_t lro_num_seg;
1592
1593                 if (consumed_strd == strd_n) {
1594                         /* Replace WQE only if the buffer is still in use. */
1595                         if (rte_atomic16_read(&buf->refcnt) > 1) {
1596                                 mprq_buf_replace(rxq, rq_ci & wq_mask, strd_n);
1597                                 /* Release the old buffer. */
1598                                 mlx5_mprq_buf_free(buf);
1599                         } else if (unlikely(rxq->mprq_repl == NULL)) {
1600                                 struct mlx5_mprq_buf *rep;
1601
1602                                 /*
1603                                  * Currently, the MPRQ mempool is out of buffer
1604                                  * and doing memcpy regardless of the size of Rx
1605                                  * packet. Retry allocation to get back to
1606                                  * normal.
1607                                  */
1608                                 if (!rte_mempool_get(rxq->mprq_mp,
1609                                                      (void **)&rep))
1610                                         rxq->mprq_repl = rep;
1611                         }
1612                         /* Advance to the next WQE. */
1613                         consumed_strd = 0;
1614                         ++rq_ci;
1615                         buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1616                 }
1617                 cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1618                 ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe);
1619                 if (!ret)
1620                         break;
1621                 byte_cnt = ret;
1622                 strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
1623                            MLX5_MPRQ_STRIDE_NUM_SHIFT;
1624                 assert(strd_cnt);
1625                 consumed_strd += strd_cnt;
1626                 if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
1627                         continue;
1628                 if (mcqe == NULL) {
1629                         rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
1630                         strd_idx = rte_be_to_cpu_16(cqe->wqe_counter);
1631                 } else {
1632                         /* mini-CQE for MPRQ doesn't have hash result. */
1633                         strd_idx = rte_be_to_cpu_16(mcqe->stride_idx);
1634                 }
1635                 assert(strd_idx < strd_n);
1636                 assert(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & wq_mask));
1637                 lro_num_seg = cqe->lro_num_seg;
1638                 /*
1639                  * Currently configured to receive a packet per a stride. But if
1640                  * MTU is adjusted through kernel interface, device could
1641                  * consume multiple strides without raising an error. In this
1642                  * case, the packet should be dropped because it is bigger than
1643                  * the max_rx_pkt_len.
1644                  */
1645                 if (unlikely(!lro_num_seg && strd_cnt > 1)) {
1646                         ++rxq->stats.idropped;
1647                         continue;
1648                 }
1649                 pkt = rte_pktmbuf_alloc(rxq->mp);
1650                 if (unlikely(pkt == NULL)) {
1651                         ++rxq->stats.rx_nombuf;
1652                         break;
1653                 }
1654                 len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1655                 assert((int)len >= (rxq->crc_present << 2));
1656                 if (rxq->crc_present)
1657                         len -= RTE_ETHER_CRC_LEN;
1658                 offset = strd_idx * strd_sz + strd_shift;
1659                 addr = RTE_PTR_ADD(mlx5_mprq_buf_addr(buf, strd_n), offset);
1660                 /*
1661                  * Memcpy packets to the target mbuf if:
1662                  * - The size of packet is smaller than mprq_max_memcpy_len.
1663                  * - Out of buffer in the Mempool for Multi-Packet RQ.
1664                  */
1665                 if (len <= rxq->mprq_max_memcpy_len || rxq->mprq_repl == NULL) {
1666                         /*
1667                          * When memcpy'ing packet due to out-of-buffer, the
1668                          * packet must be smaller than the target mbuf.
1669                          */
1670                         if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
1671                                 rte_pktmbuf_free_seg(pkt);
1672                                 ++rxq->stats.idropped;
1673                                 continue;
1674                         }
1675                         rte_memcpy(rte_pktmbuf_mtod(pkt, void *), addr, len);
1676                         DATA_LEN(pkt) = len;
1677                 } else {
1678                         rte_iova_t buf_iova;
1679                         struct rte_mbuf_ext_shared_info *shinfo;
1680                         uint16_t buf_len = strd_cnt * strd_sz;
1681                         void *buf_addr;
1682
1683                         /* Increment the refcnt of the whole chunk. */
1684                         rte_atomic16_add_return(&buf->refcnt, 1);
1685                         assert((uint16_t)rte_atomic16_read(&buf->refcnt) <=
1686                                strd_n + 1);
1687                         buf_addr = RTE_PTR_SUB(addr, headroom_sz);
1688                         /*
1689                          * MLX5 device doesn't use iova but it is necessary in a
1690                          * case where the Rx packet is transmitted via a
1691                          * different PMD.
1692                          */
1693                         buf_iova = rte_mempool_virt2iova(buf) +
1694                                    RTE_PTR_DIFF(buf_addr, buf);
1695                         shinfo = &buf->shinfos[strd_idx];
1696                         rte_mbuf_ext_refcnt_set(shinfo, 1);
1697                         /*
1698                          * EXT_ATTACHED_MBUF will be set to pkt->ol_flags when
1699                          * attaching the stride to mbuf and more offload flags
1700                          * will be added below by calling rxq_cq_to_mbuf().
1701                          * Other fields will be overwritten.
1702                          */
1703                         rte_pktmbuf_attach_extbuf(pkt, buf_addr, buf_iova,
1704                                                   buf_len, shinfo);
1705                         /* Set mbuf head-room. */
1706                         pkt->data_off = headroom_sz;
1707                         assert(pkt->ol_flags == EXT_ATTACHED_MBUF);
1708                         /*
1709                          * Prevent potential overflow due to MTU change through
1710                          * kernel interface.
1711                          */
1712                         if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
1713                                 rte_pktmbuf_free_seg(pkt);
1714                                 ++rxq->stats.idropped;
1715                                 continue;
1716                         }
1717                         DATA_LEN(pkt) = len;
1718                         /*
1719                          * LRO packet may consume all the stride memory, in this
1720                          * case packet head-room space is not guaranteed so must
1721                          * to add an empty mbuf for the head-room.
1722                          */
1723                         if (!rxq->strd_headroom_en) {
1724                                 struct rte_mbuf *headroom_mbuf =
1725                                                 rte_pktmbuf_alloc(rxq->mp);
1726
1727                                 if (unlikely(headroom_mbuf == NULL)) {
1728                                         rte_pktmbuf_free_seg(pkt);
1729                                         ++rxq->stats.rx_nombuf;
1730                                         break;
1731                                 }
1732                                 PORT(pkt) = rxq->port_id;
1733                                 NEXT(headroom_mbuf) = pkt;
1734                                 pkt = headroom_mbuf;
1735                                 NB_SEGS(pkt) = 2;
1736                         }
1737                 }
1738                 rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
1739                 if (lro_num_seg > 1) {
1740                         mlx5_lro_update_hdr(addr, cqe, len);
1741                         pkt->ol_flags |= PKT_RX_LRO;
1742                         pkt->tso_segsz = strd_sz;
1743                 }
1744                 PKT_LEN(pkt) = len;
1745                 PORT(pkt) = rxq->port_id;
1746 #ifdef MLX5_PMD_SOFT_COUNTERS
1747                 /* Increment bytes counter. */
1748                 rxq->stats.ibytes += PKT_LEN(pkt);
1749 #endif
1750                 /* Return packet. */
1751                 *(pkts++) = pkt;
1752                 ++i;
1753         }
1754         /* Update the consumer indexes. */
1755         rxq->consumed_strd = consumed_strd;
1756         rte_cio_wmb();
1757         *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1758         if (rq_ci != rxq->rq_ci) {
1759                 rxq->rq_ci = rq_ci;
1760                 rte_cio_wmb();
1761                 *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1762         }
1763 #ifdef MLX5_PMD_SOFT_COUNTERS
1764         /* Increment packets counter. */
1765         rxq->stats.ipackets += i;
1766 #endif
1767         return i;
1768 }
1769
1770 /**
1771  * Dummy DPDK callback for TX.
1772  *
1773  * This function is used to temporarily replace the real callback during
1774  * unsafe control operations on the queue, or in case of error.
1775  *
1776  * @param dpdk_txq
1777  *   Generic pointer to TX queue structure.
1778  * @param[in] pkts
1779  *   Packets to transmit.
1780  * @param pkts_n
1781  *   Number of packets in array.
1782  *
1783  * @return
1784  *   Number of packets successfully transmitted (<= pkts_n).
1785  */
1786 uint16_t
1787 removed_tx_burst(void *dpdk_txq __rte_unused,
1788                  struct rte_mbuf **pkts __rte_unused,
1789                  uint16_t pkts_n __rte_unused)
1790 {
1791         rte_mb();
1792         return 0;
1793 }
1794
1795 /**
1796  * Dummy DPDK callback for RX.
1797  *
1798  * This function is used to temporarily replace the real callback during
1799  * unsafe control operations on the queue, or in case of error.
1800  *
1801  * @param dpdk_rxq
1802  *   Generic pointer to RX queue structure.
1803  * @param[out] pkts
1804  *   Array to store received packets.
1805  * @param pkts_n
1806  *   Maximum number of packets in array.
1807  *
1808  * @return
1809  *   Number of packets successfully received (<= pkts_n).
1810  */
1811 uint16_t
1812 removed_rx_burst(void *dpdk_txq __rte_unused,
1813                  struct rte_mbuf **pkts __rte_unused,
1814                  uint16_t pkts_n __rte_unused)
1815 {
1816         rte_mb();
1817         return 0;
1818 }
1819
1820 /*
1821  * Vectorized Rx/Tx routines are not compiled in when required vector
1822  * instructions are not supported on a target architecture. The following null
1823  * stubs are needed for linkage when those are not included outside of this file
1824  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
1825  */
1826
1827 __rte_weak uint16_t
1828 mlx5_rx_burst_vec(void *dpdk_txq __rte_unused,
1829                   struct rte_mbuf **pkts __rte_unused,
1830                   uint16_t pkts_n __rte_unused)
1831 {
1832         return 0;
1833 }
1834
1835 __rte_weak int
1836 mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused)
1837 {
1838         return -ENOTSUP;
1839 }
1840
1841 __rte_weak int
1842 mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused)
1843 {
1844         return -ENOTSUP;
1845 }
1846
1847 /**
1848  * Free the mbufs from the linear array of pointers.
1849  *
1850  * @param pkts
1851  *   Pointer to array of packets to be free.
1852  * @param pkts_n
1853  *   Number of packets to be freed.
1854  * @param olx
1855  *   Configured Tx offloads mask. It is fully defined at
1856  *   compile time and may be used for optimization.
1857  */
1858 static __rte_always_inline void
1859 mlx5_tx_free_mbuf(struct rte_mbuf **restrict pkts,
1860                   unsigned int pkts_n,
1861                   unsigned int olx __rte_unused)
1862 {
1863         struct rte_mempool *pool = NULL;
1864         struct rte_mbuf **p_free = NULL;
1865         struct rte_mbuf *mbuf;
1866         unsigned int n_free = 0;
1867
1868         /*
1869          * The implemented algorithm eliminates
1870          * copying pointers to temporary array
1871          * for rte_mempool_put_bulk() calls.
1872          */
1873         assert(pkts);
1874         assert(pkts_n);
1875         for (;;) {
1876                 for (;;) {
1877                         /*
1878                          * Decrement mbuf reference counter, detach
1879                          * indirect and external buffers if needed.
1880                          */
1881                         mbuf = rte_pktmbuf_prefree_seg(*pkts);
1882                         if (likely(mbuf != NULL)) {
1883                                 assert(mbuf == *pkts);
1884                                 if (likely(n_free != 0)) {
1885                                         if (unlikely(pool != mbuf->pool))
1886                                                 /* From different pool. */
1887                                                 break;
1888                                 } else {
1889                                         /* Start new scan array. */
1890                                         pool = mbuf->pool;
1891                                         p_free = pkts;
1892                                 }
1893                                 ++n_free;
1894                                 ++pkts;
1895                                 --pkts_n;
1896                                 if (unlikely(pkts_n == 0)) {
1897                                         mbuf = NULL;
1898                                         break;
1899                                 }
1900                         } else {
1901                                 /*
1902                                  * This happens if mbuf is still referenced.
1903                                  * We can't put it back to the pool, skip.
1904                                  */
1905                                 ++pkts;
1906                                 --pkts_n;
1907                                 if (unlikely(n_free != 0))
1908                                         /* There is some array to free.*/
1909                                         break;
1910                                 if (unlikely(pkts_n == 0))
1911                                         /* Last mbuf, nothing to free. */
1912                                         return;
1913                         }
1914                 }
1915                 for (;;) {
1916                         /*
1917                          * This loop is implemented to avoid multiple
1918                          * inlining of rte_mempool_put_bulk().
1919                          */
1920                         assert(pool);
1921                         assert(p_free);
1922                         assert(n_free);
1923                         /*
1924                          * Free the array of pre-freed mbufs
1925                          * belonging to the same memory pool.
1926                          */
1927                         rte_mempool_put_bulk(pool, (void *)p_free, n_free);
1928                         if (unlikely(mbuf != NULL)) {
1929                                 /* There is the request to start new scan. */
1930                                 pool = mbuf->pool;
1931                                 p_free = pkts++;
1932                                 n_free = 1;
1933                                 --pkts_n;
1934                                 if (likely(pkts_n != 0))
1935                                         break;
1936                                 /*
1937                                  * This is the last mbuf to be freed.
1938                                  * Do one more loop iteration to complete.
1939                                  * This is rare case of the last unique mbuf.
1940                                  */
1941                                 mbuf = NULL;
1942                                 continue;
1943                         }
1944                         if (likely(pkts_n == 0))
1945                                 return;
1946                         n_free = 0;
1947                         break;
1948                 }
1949         }
1950 }
1951
1952 /**
1953  * Free the mbuf from the elts ring buffer till new tail.
1954  *
1955  * @param txq
1956  *   Pointer to Tx queue structure.
1957  * @param tail
1958  *   Index in elts to free up to, becomes new elts tail.
1959  * @param olx
1960  *   Configured Tx offloads mask. It is fully defined at
1961  *   compile time and may be used for optimization.
1962  */
1963 static __rte_always_inline void
1964 mlx5_tx_free_elts(struct mlx5_txq_data *restrict txq,
1965                   uint16_t tail,
1966                   unsigned int olx __rte_unused)
1967 {
1968         uint16_t n_elts = tail - txq->elts_tail;
1969
1970         assert(n_elts);
1971         assert(n_elts <= txq->elts_s);
1972         /*
1973          * Implement a loop to support ring buffer wraparound
1974          * with single inlining of mlx5_tx_free_mbuf().
1975          */
1976         do {
1977                 unsigned int part;
1978
1979                 part = txq->elts_s - (txq->elts_tail & txq->elts_m);
1980                 part = RTE_MIN(part, n_elts);
1981                 assert(part);
1982                 assert(part <= txq->elts_s);
1983                 mlx5_tx_free_mbuf(&txq->elts[txq->elts_tail & txq->elts_m],
1984                                   part, olx);
1985                 txq->elts_tail += part;
1986                 n_elts -= part;
1987         } while (n_elts);
1988 }
1989
1990 /**
1991  * Store the mbuf being sent into elts ring buffer.
1992  * On Tx completion these mbufs will be freed.
1993  *
1994  * @param txq
1995  *   Pointer to Tx queue structure.
1996  * @param pkts
1997  *   Pointer to array of packets to be stored.
1998  * @param pkts_n
1999  *   Number of packets to be stored.
2000  * @param olx
2001  *   Configured Tx offloads mask. It is fully defined at
2002  *   compile time and may be used for optimization.
2003  */
2004 static __rte_always_inline void
2005 mlx5_tx_copy_elts(struct mlx5_txq_data *restrict txq,
2006                   struct rte_mbuf **restrict pkts,
2007                   unsigned int pkts_n,
2008                   unsigned int olx __rte_unused)
2009 {
2010         unsigned int part;
2011         struct rte_mbuf **elts = (struct rte_mbuf **)txq->elts;
2012
2013         assert(pkts);
2014         assert(pkts_n);
2015         part = txq->elts_s - (txq->elts_head & txq->elts_m);
2016         assert(part);
2017         assert(part <= txq->elts_s);
2018         /* This code is a good candidate for vectorizing with SIMD. */
2019         rte_memcpy((void *)(elts + (txq->elts_head & txq->elts_m)),
2020                    (void *)pkts,
2021                    RTE_MIN(part, pkts_n) * sizeof(struct rte_mbuf *));
2022         txq->elts_head += pkts_n;
2023         if (unlikely(part < pkts_n))
2024                 /* The copy is wrapping around the elts array. */
2025                 rte_memcpy((void *)elts, (void *)(pkts + part),
2026                            (pkts_n - part) * sizeof(struct rte_mbuf *));
2027 }
2028
2029 /**
2030  * Update completion queue consuming index via doorbell
2031  * and flush the completed data buffers.
2032  *
2033  * @param txq
2034  *   Pointer to TX queue structure.
2035  * @param valid CQE pointer
2036  *   if not NULL update txq->wqe_pi and flush the buffers
2037  * @param itail
2038  *   if not negative - flush the buffers till this index.
2039  * @param olx
2040  *   Configured Tx offloads mask. It is fully defined at
2041  *   compile time and may be used for optimization.
2042  */
2043 static __rte_always_inline void
2044 mlx5_tx_comp_flush(struct mlx5_txq_data *restrict txq,
2045                    volatile struct mlx5_cqe *last_cqe,
2046                    int itail,
2047                    unsigned int olx __rte_unused)
2048 {
2049         uint16_t tail;
2050
2051         if (likely(last_cqe != NULL)) {
2052                 txq->wqe_pi = rte_be_to_cpu_16(last_cqe->wqe_counter);
2053                 tail = ((volatile struct mlx5_wqe_cseg *)
2054                         (txq->wqes + (txq->wqe_pi & txq->wqe_m)))->misc;
2055         } else if (itail >= 0) {
2056                 tail = (uint16_t)itail;
2057         } else {
2058                 return;
2059         }
2060         rte_compiler_barrier();
2061         *txq->cq_db = rte_cpu_to_be_32(txq->cq_ci);
2062         if (likely(tail != txq->elts_tail)) {
2063                 mlx5_tx_free_elts(txq, tail, olx);
2064                 assert(tail == txq->elts_tail);
2065         }
2066 }
2067
2068 /**
2069  * Manage TX completions. This routine checks the CQ for
2070  * arrived CQEs, deduces the last accomplished WQE in SQ,
2071  * updates SQ producing index and frees all completed mbufs.
2072  *
2073  * @param txq
2074  *   Pointer to TX queue structure.
2075  * @param olx
2076  *   Configured Tx offloads mask. It is fully defined at
2077  *   compile time and may be used for optimization.
2078  *
2079  * NOTE: not inlined intentionally, it makes tx_burst
2080  * routine smaller, simple and faster - from experiments.
2081  */
2082 static void
2083 mlx5_tx_handle_completion(struct mlx5_txq_data *restrict txq,
2084                           unsigned int olx __rte_unused)
2085 {
2086         unsigned int count = MLX5_TX_COMP_MAX_CQE;
2087         volatile struct mlx5_cqe *last_cqe = NULL;
2088         int ret;
2089
2090         static_assert(MLX5_CQE_STATUS_HW_OWN < 0, "Must be negative value");
2091         static_assert(MLX5_CQE_STATUS_SW_OWN < 0, "Must be negative value");
2092         do {
2093                 volatile struct mlx5_cqe *cqe;
2094
2095                 cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
2096                 ret = check_cqe(cqe, txq->cqe_s, txq->cq_ci);
2097                 if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
2098                         if (likely(ret != MLX5_CQE_STATUS_ERR)) {
2099                                 /* No new CQEs in completion queue. */
2100                                 assert(ret == MLX5_CQE_STATUS_HW_OWN);
2101                                 break;
2102                         }
2103                         /*
2104                          * Some error occurred, try to restart.
2105                          * We have no barrier after WQE related Doorbell
2106                          * written, make sure all writes are completed
2107                          * here, before we might perform SQ reset.
2108                          */
2109                         rte_wmb();
2110                         ret = mlx5_tx_error_cqe_handle
2111                                 (txq, (volatile struct mlx5_err_cqe *)cqe);
2112                         /*
2113                          * Flush buffers, update consuming index
2114                          * if recovery succeeded. Otherwise
2115                          * just try to recover later.
2116                          */
2117                         last_cqe = NULL;
2118                         break;
2119                 }
2120                 /* Normal transmit completion. */
2121                 ++txq->cq_ci;
2122                 last_cqe = cqe;
2123 #ifndef NDEBUG
2124                 if (txq->cq_pi)
2125                         --txq->cq_pi;
2126 #endif
2127         /*
2128          * We have to restrict the amount of processed CQEs
2129          * in one tx_burst routine call. The CQ may be large
2130          * and many CQEs may be updated by the NIC in one
2131          * transaction. Buffers freeing is time consuming,
2132          * multiple iterations may introduce significant
2133          * latency.
2134          */
2135         } while (--count);
2136         mlx5_tx_comp_flush(txq, last_cqe, ret, olx);
2137 }
2138
2139 /**
2140  * Check if the completion request flag should be set in the last WQE.
2141  * Both pushed mbufs and WQEs are monitored and the completion request
2142  * flag is set if any of thresholds is reached.
2143  *
2144  * @param txq
2145  *   Pointer to TX queue structure.
2146  * @param loc
2147  *   Pointer to burst routine local context.
2148  * @param olx
2149  *   Configured Tx offloads mask. It is fully defined at
2150  *   compile time and may be used for optimization.
2151  */
2152 static __rte_always_inline void
2153 mlx5_tx_request_completion(struct mlx5_txq_data *restrict txq,
2154                            struct mlx5_txq_local *restrict loc,
2155                            unsigned int olx)
2156 {
2157         uint16_t head = txq->elts_head;
2158         unsigned int part;
2159
2160         part = MLX5_TXOFF_CONFIG(INLINE) ?
2161                0 : loc->pkts_sent - loc->pkts_copy;
2162         head += part;
2163         if ((uint16_t)(head - txq->elts_comp) >= MLX5_TX_COMP_THRESH ||
2164              (MLX5_TXOFF_CONFIG(INLINE) &&
2165              (uint16_t)(txq->wqe_ci - txq->wqe_comp) >= txq->wqe_thres)) {
2166                 volatile struct mlx5_wqe *last = loc->wqe_last;
2167
2168                 txq->elts_comp = head;
2169                 if (MLX5_TXOFF_CONFIG(INLINE))
2170                         txq->wqe_comp = txq->wqe_ci;
2171                 /* Request unconditional completion on last WQE. */
2172                 last->cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
2173                                             MLX5_COMP_MODE_OFFSET);
2174                 /* Save elts_head in unused "immediate" field of WQE. */
2175                 last->cseg.misc = head;
2176                 /*
2177                  * A CQE slot must always be available. Count the
2178                  * issued CEQ "always" request instead of production
2179                  * index due to here can be CQE with errors and
2180                  * difference with ci may become inconsistent.
2181                  */
2182                 assert(txq->cqe_s > ++txq->cq_pi);
2183         }
2184 }
2185
2186 /**
2187  * DPDK callback to check the status of a tx descriptor.
2188  *
2189  * @param tx_queue
2190  *   The tx queue.
2191  * @param[in] offset
2192  *   The index of the descriptor in the ring.
2193  *
2194  * @return
2195  *   The status of the tx descriptor.
2196  */
2197 int
2198 mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
2199 {
2200         struct mlx5_txq_data *restrict txq = tx_queue;
2201         uint16_t used;
2202
2203         mlx5_tx_handle_completion(txq, 0);
2204         used = txq->elts_head - txq->elts_tail;
2205         if (offset < used)
2206                 return RTE_ETH_TX_DESC_FULL;
2207         return RTE_ETH_TX_DESC_DONE;
2208 }
2209
2210 /**
2211  * Build the Control Segment with specified opcode:
2212  * - MLX5_OPCODE_SEND
2213  * - MLX5_OPCODE_ENHANCED_MPSW
2214  * - MLX5_OPCODE_TSO
2215  *
2216  * @param txq
2217  *   Pointer to TX queue structure.
2218  * @param loc
2219  *   Pointer to burst routine local context.
2220  * @param wqe
2221  *   Pointer to WQE to fill with built Control Segment.
2222  * @param ds
2223  *   Supposed length of WQE in segments.
2224  * @param opcode
2225  *   SQ WQE opcode to put into Control Segment.
2226  * @param olx
2227  *   Configured Tx offloads mask. It is fully defined at
2228  *   compile time and may be used for optimization.
2229  */
2230 static __rte_always_inline void
2231 mlx5_tx_cseg_init(struct mlx5_txq_data *restrict txq,
2232                   struct mlx5_txq_local *restrict loc __rte_unused,
2233                   struct mlx5_wqe *restrict wqe,
2234                   unsigned int ds,
2235                   unsigned int opcode,
2236                   unsigned int olx __rte_unused)
2237 {
2238         struct mlx5_wqe_cseg *restrict cs = &wqe->cseg;
2239
2240         /* For legacy MPW replace the EMPW by TSO with modifier. */
2241         if (MLX5_TXOFF_CONFIG(MPW) && opcode == MLX5_OPCODE_ENHANCED_MPSW)
2242                 opcode = MLX5_OPCODE_TSO | MLX5_OPC_MOD_MPW << 24;
2243         cs->opcode = rte_cpu_to_be_32((txq->wqe_ci << 8) | opcode);
2244         cs->sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds);
2245         cs->flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
2246                              MLX5_COMP_MODE_OFFSET);
2247         cs->misc = RTE_BE32(0);
2248 }
2249
2250 /**
2251  * Build the Ethernet Segment without inlined data.
2252  * Supports Software Parser, Checksums and VLAN
2253  * insertion Tx offload features.
2254  *
2255  * @param txq
2256  *   Pointer to TX queue structure.
2257  * @param loc
2258  *   Pointer to burst routine local context.
2259  * @param wqe
2260  *   Pointer to WQE to fill with built Ethernet Segment.
2261  * @param olx
2262  *   Configured Tx offloads mask. It is fully defined at
2263  *   compile time and may be used for optimization.
2264  */
2265 static __rte_always_inline void
2266 mlx5_tx_eseg_none(struct mlx5_txq_data *restrict txq __rte_unused,
2267                   struct mlx5_txq_local *restrict loc,
2268                   struct mlx5_wqe *restrict wqe,
2269                   unsigned int olx)
2270 {
2271         struct mlx5_wqe_eseg *restrict es = &wqe->eseg;
2272         uint32_t csum;
2273
2274         /*
2275          * Calculate and set check sum flags first, dword field
2276          * in segment may be shared with Software Parser flags.
2277          */
2278         csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0;
2279         es->flags = rte_cpu_to_le_32(csum);
2280         /*
2281          * Calculate and set Software Parser offsets and flags.
2282          * These flags a set for custom UDP and IP tunnel packets.
2283          */
2284         es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx);
2285         /* Fill metadata field if needed. */
2286         es->metadata = MLX5_TXOFF_CONFIG(METADATA) ?
2287                        loc->mbuf->ol_flags & PKT_TX_DYNF_METADATA ?
2288                        *RTE_FLOW_DYNF_METADATA(loc->mbuf) : 0 : 0;
2289         /* Engage VLAN tag insertion feature if requested. */
2290         if (MLX5_TXOFF_CONFIG(VLAN) &&
2291             loc->mbuf->ol_flags & PKT_TX_VLAN_PKT) {
2292                 /*
2293                  * We should get here only if device support
2294                  * this feature correctly.
2295                  */
2296                 assert(txq->vlan_en);
2297                 es->inline_hdr = rte_cpu_to_be_32(MLX5_ETH_WQE_VLAN_INSERT |
2298                                                   loc->mbuf->vlan_tci);
2299         } else {
2300                 es->inline_hdr = RTE_BE32(0);
2301         }
2302 }
2303
2304 /**
2305  * Build the Ethernet Segment with minimal inlined data
2306  * of MLX5_ESEG_MIN_INLINE_SIZE bytes length. This is
2307  * used to fill the gap in single WQEBB WQEs.
2308  * Supports Software Parser, Checksums and VLAN
2309  * insertion Tx offload features.
2310  *
2311  * @param txq
2312  *   Pointer to TX queue structure.
2313  * @param loc
2314  *   Pointer to burst routine local context.
2315  * @param wqe
2316  *   Pointer to WQE to fill with built Ethernet Segment.
2317  * @param vlan
2318  *   Length of VLAN tag insertion if any.
2319  * @param olx
2320  *   Configured Tx offloads mask. It is fully defined at
2321  *   compile time and may be used for optimization.
2322  */
2323 static __rte_always_inline void
2324 mlx5_tx_eseg_dmin(struct mlx5_txq_data *restrict txq __rte_unused,
2325                   struct mlx5_txq_local *restrict loc,
2326                   struct mlx5_wqe *restrict wqe,
2327                   unsigned int vlan,
2328                   unsigned int olx)
2329 {
2330         struct mlx5_wqe_eseg *restrict es = &wqe->eseg;
2331         uint32_t csum;
2332         uint8_t *psrc, *pdst;
2333
2334         /*
2335          * Calculate and set check sum flags first, dword field
2336          * in segment may be shared with Software Parser flags.
2337          */
2338         csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0;
2339         es->flags = rte_cpu_to_le_32(csum);
2340         /*
2341          * Calculate and set Software Parser offsets and flags.
2342          * These flags a set for custom UDP and IP tunnel packets.
2343          */
2344         es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx);
2345         /* Fill metadata field if needed. */
2346         es->metadata = MLX5_TXOFF_CONFIG(METADATA) ?
2347                        loc->mbuf->ol_flags & PKT_TX_DYNF_METADATA ?
2348                        *RTE_FLOW_DYNF_METADATA(loc->mbuf) : 0 : 0;
2349         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2350                                 (sizeof(uint16_t) +
2351                                  sizeof(rte_v128u32_t)),
2352                       "invalid Ethernet Segment data size");
2353         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2354                                 (sizeof(uint16_t) +
2355                                  sizeof(struct rte_vlan_hdr) +
2356                                  2 * RTE_ETHER_ADDR_LEN),
2357                       "invalid Ethernet Segment data size");
2358         psrc = rte_pktmbuf_mtod(loc->mbuf, uint8_t *);
2359         es->inline_hdr_sz = RTE_BE16(MLX5_ESEG_MIN_INLINE_SIZE);
2360         es->inline_data = *(unaligned_uint16_t *)psrc;
2361         psrc += sizeof(uint16_t);
2362         pdst = (uint8_t *)(es + 1);
2363         if (MLX5_TXOFF_CONFIG(VLAN) && vlan) {
2364                 /* Implement VLAN tag insertion as part inline data. */
2365                 memcpy(pdst, psrc, 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t));
2366                 pdst += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t);
2367                 psrc += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t);
2368                 /* Insert VLAN ethertype + VLAN tag. */
2369                 *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32
2370                                                 ((RTE_ETHER_TYPE_VLAN << 16) |
2371                                                  loc->mbuf->vlan_tci);
2372                 pdst += sizeof(struct rte_vlan_hdr);
2373                 /* Copy the rest two bytes from packet data. */
2374                 assert(pdst == RTE_PTR_ALIGN(pdst, sizeof(uint16_t)));
2375                 *(uint16_t *)pdst = *(unaligned_uint16_t *)psrc;
2376         } else {
2377                 /* Fill the gap in the title WQEBB with inline data. */
2378                 rte_mov16(pdst, psrc);
2379         }
2380 }
2381
2382 /**
2383  * Build the Ethernet Segment with entire packet
2384  * data inlining. Checks the boundary of WQEBB and
2385  * ring buffer wrapping, supports Software Parser,
2386  * Checksums and VLAN insertion Tx offload features.
2387  *
2388  * @param txq
2389  *   Pointer to TX queue structure.
2390  * @param loc
2391  *   Pointer to burst routine local context.
2392  * @param wqe
2393  *   Pointer to WQE to fill with built Ethernet Segment.
2394  * @param vlan
2395  *   Length of VLAN tag insertion if any.
2396  * @param inlen
2397  *   Length of data to inline (VLAN included, if any).
2398  * @param tso
2399  *   TSO flag, set mss field from the packet.
2400  * @param olx
2401  *   Configured Tx offloads mask. It is fully defined at
2402  *   compile time and may be used for optimization.
2403  *
2404  * @return
2405  *   Pointer to the next Data Segment (aligned and wrapped around).
2406  */
2407 static __rte_always_inline struct mlx5_wqe_dseg *
2408 mlx5_tx_eseg_data(struct mlx5_txq_data *restrict txq,
2409                   struct mlx5_txq_local *restrict loc,
2410                   struct mlx5_wqe *restrict wqe,
2411                   unsigned int vlan,
2412                   unsigned int inlen,
2413                   unsigned int tso,
2414                   unsigned int olx)
2415 {
2416         struct mlx5_wqe_eseg *restrict es = &wqe->eseg;
2417         uint32_t csum;
2418         uint8_t *psrc, *pdst;
2419         unsigned int part;
2420
2421         /*
2422          * Calculate and set check sum flags first, dword field
2423          * in segment may be shared with Software Parser flags.
2424          */
2425         csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0;
2426         if (tso) {
2427                 csum <<= 24;
2428                 csum |= loc->mbuf->tso_segsz;
2429                 es->flags = rte_cpu_to_be_32(csum);
2430         } else {
2431                 es->flags = rte_cpu_to_le_32(csum);
2432         }
2433         /*
2434          * Calculate and set Software Parser offsets and flags.
2435          * These flags a set for custom UDP and IP tunnel packets.
2436          */
2437         es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx);
2438         /* Fill metadata field if needed. */
2439         es->metadata = MLX5_TXOFF_CONFIG(METADATA) ?
2440                        loc->mbuf->ol_flags & PKT_TX_DYNF_METADATA ?
2441                        *RTE_FLOW_DYNF_METADATA(loc->mbuf) : 0 : 0;
2442         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2443                                 (sizeof(uint16_t) +
2444                                  sizeof(rte_v128u32_t)),
2445                       "invalid Ethernet Segment data size");
2446         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2447                                 (sizeof(uint16_t) +
2448                                  sizeof(struct rte_vlan_hdr) +
2449                                  2 * RTE_ETHER_ADDR_LEN),
2450                       "invalid Ethernet Segment data size");
2451         psrc = rte_pktmbuf_mtod(loc->mbuf, uint8_t *);
2452         es->inline_hdr_sz = rte_cpu_to_be_16(inlen);
2453         es->inline_data = *(unaligned_uint16_t *)psrc;
2454         psrc += sizeof(uint16_t);
2455         pdst = (uint8_t *)(es + 1);
2456         if (MLX5_TXOFF_CONFIG(VLAN) && vlan) {
2457                 /* Implement VLAN tag insertion as part inline data. */
2458                 memcpy(pdst, psrc, 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t));
2459                 pdst += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t);
2460                 psrc += 2 * RTE_ETHER_ADDR_LEN - sizeof(uint16_t);
2461                 /* Insert VLAN ethertype + VLAN tag. */
2462                 *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32
2463                                                 ((RTE_ETHER_TYPE_VLAN << 16) |
2464                                                  loc->mbuf->vlan_tci);
2465                 pdst += sizeof(struct rte_vlan_hdr);
2466                 /* Copy the rest two bytes from packet data. */
2467                 assert(pdst == RTE_PTR_ALIGN(pdst, sizeof(uint16_t)));
2468                 *(uint16_t *)pdst = *(unaligned_uint16_t *)psrc;
2469                 psrc += sizeof(uint16_t);
2470         } else {
2471                 /* Fill the gap in the title WQEBB with inline data. */
2472                 rte_mov16(pdst, psrc);
2473                 psrc += sizeof(rte_v128u32_t);
2474         }
2475         pdst = (uint8_t *)(es + 2);
2476         assert(inlen >= MLX5_ESEG_MIN_INLINE_SIZE);
2477         assert(pdst < (uint8_t *)txq->wqes_end);
2478         inlen -= MLX5_ESEG_MIN_INLINE_SIZE;
2479         if (!inlen) {
2480                 assert(pdst == RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE));
2481                 return (struct mlx5_wqe_dseg *)pdst;
2482         }
2483         /*
2484          * The WQEBB space availability is checked by caller.
2485          * Here we should be aware of WQE ring buffer wraparound only.
2486          */
2487         part = (uint8_t *)txq->wqes_end - pdst;
2488         part = RTE_MIN(part, inlen);
2489         do {
2490                 rte_memcpy(pdst, psrc, part);
2491                 inlen -= part;
2492                 if (likely(!inlen)) {
2493                         /*
2494                          * If return value is not used by the caller
2495                          * the code below will be optimized out.
2496                          */
2497                         pdst += part;
2498                         pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE);
2499                         if (unlikely(pdst >= (uint8_t *)txq->wqes_end))
2500                                 pdst = (uint8_t *)txq->wqes;
2501                         return (struct mlx5_wqe_dseg *)pdst;
2502                 }
2503                 pdst = (uint8_t *)txq->wqes;
2504                 psrc += part;
2505                 part = inlen;
2506         } while (true);
2507 }
2508
2509 /**
2510  * Copy data from chain of mbuf to the specified linear buffer.
2511  * Checksums and VLAN insertion Tx offload features. If data
2512  * from some mbuf copied completely this mbuf is freed. Local
2513  * structure is used to keep the byte stream state.
2514  *
2515  * @param pdst
2516  *   Pointer to the destination linear buffer.
2517  * @param loc
2518  *   Pointer to burst routine local context.
2519  * @param len
2520  *   Length of data to be copied.
2521  * @param olx
2522  *   Configured Tx offloads mask. It is fully defined at
2523  *   compile time and may be used for optimization.
2524  */
2525 static __rte_always_inline void
2526 mlx5_tx_mseg_memcpy(uint8_t *pdst,
2527                     struct mlx5_txq_local *restrict loc,
2528                     unsigned int len,
2529                     unsigned int olx __rte_unused)
2530 {
2531         struct rte_mbuf *mbuf;
2532         unsigned int part, dlen;
2533         uint8_t *psrc;
2534
2535         assert(len);
2536         do {
2537                 /* Allow zero length packets, must check first. */
2538                 dlen = rte_pktmbuf_data_len(loc->mbuf);
2539                 if (dlen <= loc->mbuf_off) {
2540                         /* Exhausted packet, just free. */
2541                         mbuf = loc->mbuf;
2542                         loc->mbuf = mbuf->next;
2543                         rte_pktmbuf_free_seg(mbuf);
2544                         loc->mbuf_off = 0;
2545                         assert(loc->mbuf_nseg > 1);
2546                         assert(loc->mbuf);
2547                         --loc->mbuf_nseg;
2548                         continue;
2549                 }
2550                 dlen -= loc->mbuf_off;
2551                 psrc = rte_pktmbuf_mtod_offset(loc->mbuf, uint8_t *,
2552                                                loc->mbuf_off);
2553                 part = RTE_MIN(len, dlen);
2554                 rte_memcpy(pdst, psrc, part);
2555                 loc->mbuf_off += part;
2556                 len -= part;
2557                 if (!len) {
2558                         if (loc->mbuf_off >= rte_pktmbuf_data_len(loc->mbuf)) {
2559                                 loc->mbuf_off = 0;
2560                                 /* Exhausted packet, just free. */
2561                                 mbuf = loc->mbuf;
2562                                 loc->mbuf = mbuf->next;
2563                                 rte_pktmbuf_free_seg(mbuf);
2564                                 loc->mbuf_off = 0;
2565                                 assert(loc->mbuf_nseg >= 1);
2566                                 --loc->mbuf_nseg;
2567                         }
2568                         return;
2569                 }
2570                 pdst += part;
2571         } while (true);
2572 }
2573
2574 /**
2575  * Build the Ethernet Segment with inlined data from
2576  * multi-segment packet. Checks the boundary of WQEBB
2577  * and ring buffer wrapping, supports Software Parser,
2578  * Checksums and VLAN insertion Tx offload features.
2579  *
2580  * @param txq
2581  *   Pointer to TX queue structure.
2582  * @param loc
2583  *   Pointer to burst routine local context.
2584  * @param wqe
2585  *   Pointer to WQE to fill with built Ethernet Segment.
2586  * @param vlan
2587  *   Length of VLAN tag insertion if any.
2588  * @param inlen
2589  *   Length of data to inline (VLAN included, if any).
2590  * @param tso
2591  *   TSO flag, set mss field from the packet.
2592  * @param olx
2593  *   Configured Tx offloads mask. It is fully defined at
2594  *   compile time and may be used for optimization.
2595  *
2596  * @return
2597  *   Pointer to the next Data Segment (aligned and
2598  *   possible NOT wrapped around - caller should do
2599  *   wrapping check on its own).
2600  */
2601 static __rte_always_inline struct mlx5_wqe_dseg *
2602 mlx5_tx_eseg_mdat(struct mlx5_txq_data *restrict txq,
2603                   struct mlx5_txq_local *restrict loc,
2604                   struct mlx5_wqe *restrict wqe,
2605                   unsigned int vlan,
2606                   unsigned int inlen,
2607                   unsigned int tso,
2608                   unsigned int olx)
2609 {
2610         struct mlx5_wqe_eseg *restrict es = &wqe->eseg;
2611         uint32_t csum;
2612         uint8_t *pdst;
2613         unsigned int part;
2614
2615         /*
2616          * Calculate and set check sum flags first, uint32_t field
2617          * in segment may be shared with Software Parser flags.
2618          */
2619         csum = MLX5_TXOFF_CONFIG(CSUM) ? txq_ol_cksum_to_cs(loc->mbuf) : 0;
2620         if (tso) {
2621                 csum <<= 24;
2622                 csum |= loc->mbuf->tso_segsz;
2623                 es->flags = rte_cpu_to_be_32(csum);
2624         } else {
2625                 es->flags = rte_cpu_to_le_32(csum);
2626         }
2627         /*
2628          * Calculate and set Software Parser offsets and flags.
2629          * These flags a set for custom UDP and IP tunnel packets.
2630          */
2631         es->swp_offs = txq_mbuf_to_swp(loc, &es->swp_flags, olx);
2632         /* Fill metadata field if needed. */
2633         es->metadata = MLX5_TXOFF_CONFIG(METADATA) ?
2634                        loc->mbuf->ol_flags & PKT_TX_DYNF_METADATA ?
2635                        *RTE_FLOW_DYNF_METADATA(loc->mbuf) : 0 : 0;
2636         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2637                                 (sizeof(uint16_t) +
2638                                  sizeof(rte_v128u32_t)),
2639                       "invalid Ethernet Segment data size");
2640         static_assert(MLX5_ESEG_MIN_INLINE_SIZE ==
2641                                 (sizeof(uint16_t) +
2642                                  sizeof(struct rte_vlan_hdr) +
2643                                  2 * RTE_ETHER_ADDR_LEN),
2644                       "invalid Ethernet Segment data size");
2645         assert(inlen >= MLX5_ESEG_MIN_INLINE_SIZE);
2646         es->inline_hdr_sz = rte_cpu_to_be_16(inlen);
2647         pdst = (uint8_t *)&es->inline_data;
2648         if (MLX5_TXOFF_CONFIG(VLAN) && vlan) {
2649                 /* Implement VLAN tag insertion as part inline data. */
2650                 mlx5_tx_mseg_memcpy(pdst, loc, 2 * RTE_ETHER_ADDR_LEN, olx);
2651                 pdst += 2 * RTE_ETHER_ADDR_LEN;
2652                 *(unaligned_uint32_t *)pdst = rte_cpu_to_be_32
2653                                                 ((RTE_ETHER_TYPE_VLAN << 16) |
2654                                                  loc->mbuf->vlan_tci);
2655                 pdst += sizeof(struct rte_vlan_hdr);
2656                 inlen -= 2 * RTE_ETHER_ADDR_LEN + sizeof(struct rte_vlan_hdr);
2657         }
2658         assert(pdst < (uint8_t *)txq->wqes_end);
2659         /*
2660          * The WQEBB space availability is checked by caller.
2661          * Here we should be aware of WQE ring buffer wraparound only.
2662          */
2663         part = (uint8_t *)txq->wqes_end - pdst;
2664         part = RTE_MIN(part, inlen);
2665         assert(part);
2666         do {
2667                 mlx5_tx_mseg_memcpy(pdst, loc, part, olx);
2668                 inlen -= part;
2669                 if (likely(!inlen)) {
2670                         pdst += part;
2671                         pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE);
2672                         return (struct mlx5_wqe_dseg *)pdst;
2673                 }
2674                 pdst = (uint8_t *)txq->wqes;
2675                 part = inlen;
2676         } while (true);
2677 }
2678
2679 /**
2680  * Build the Data Segment of pointer type.
2681  *
2682  * @param txq
2683  *   Pointer to TX queue structure.
2684  * @param loc
2685  *   Pointer to burst routine local context.
2686  * @param dseg
2687  *   Pointer to WQE to fill with built Data Segment.
2688  * @param buf
2689  *   Data buffer to point.
2690  * @param len
2691  *   Data buffer length.
2692  * @param olx
2693  *   Configured Tx offloads mask. It is fully defined at
2694  *   compile time and may be used for optimization.
2695  */
2696 static __rte_always_inline void
2697 mlx5_tx_dseg_ptr(struct mlx5_txq_data *restrict txq,
2698                  struct mlx5_txq_local *restrict loc,
2699                  struct mlx5_wqe_dseg *restrict dseg,
2700                  uint8_t *buf,
2701                  unsigned int len,
2702                  unsigned int olx __rte_unused)
2703
2704 {
2705         assert(len);
2706         dseg->bcount = rte_cpu_to_be_32(len);
2707         dseg->lkey = mlx5_tx_mb2mr(txq, loc->mbuf);
2708         dseg->pbuf = rte_cpu_to_be_64((uintptr_t)buf);
2709 }
2710
2711 /**
2712  * Build the Data Segment of pointer type or inline
2713  * if data length is less than buffer in minimal
2714  * Data Segment size.
2715  *
2716  * @param txq
2717  *   Pointer to TX queue structure.
2718  * @param loc
2719  *   Pointer to burst routine local context.
2720  * @param dseg
2721  *   Pointer to WQE to fill with built Data Segment.
2722  * @param buf
2723  *   Data buffer to point.
2724  * @param len
2725  *   Data buffer length.
2726  * @param olx
2727  *   Configured Tx offloads mask. It is fully defined at
2728  *   compile time and may be used for optimization.
2729  */
2730 static __rte_always_inline void
2731 mlx5_tx_dseg_iptr(struct mlx5_txq_data *restrict txq,
2732                   struct mlx5_txq_local *restrict loc,
2733                   struct mlx5_wqe_dseg *restrict dseg,
2734                   uint8_t *buf,
2735                   unsigned int len,
2736                   unsigned int olx __rte_unused)
2737
2738 {
2739         uintptr_t dst, src;
2740
2741         assert(len);
2742         if (len > MLX5_DSEG_MIN_INLINE_SIZE) {
2743                 dseg->bcount = rte_cpu_to_be_32(len);
2744                 dseg->lkey = mlx5_tx_mb2mr(txq, loc->mbuf);
2745                 dseg->pbuf = rte_cpu_to_be_64((uintptr_t)buf);
2746
2747                 return;
2748         }
2749         dseg->bcount = rte_cpu_to_be_32(len | MLX5_ETH_WQE_DATA_INLINE);
2750         /* Unrolled implementation of generic rte_memcpy. */
2751         dst = (uintptr_t)&dseg->inline_data[0];
2752         src = (uintptr_t)buf;
2753         if (len & 0x08) {
2754 #ifdef RTE_ARCH_STRICT_ALIGN
2755                 assert(dst == RTE_PTR_ALIGN(dst, sizeof(uint32_t)));
2756                 *(uint32_t *)dst = *(unaligned_uint32_t *)src;
2757                 dst += sizeof(uint32_t);
2758                 src += sizeof(uint32_t);
2759                 *(uint32_t *)dst = *(unaligned_uint32_t *)src;
2760                 dst += sizeof(uint32_t);
2761                 src += sizeof(uint32_t);
2762 #else
2763                 *(uint64_t *)dst = *(unaligned_uint64_t *)src;
2764                 dst += sizeof(uint64_t);
2765                 src += sizeof(uint64_t);
2766 #endif
2767         }
2768         if (len & 0x04) {
2769                 *(uint32_t *)dst = *(unaligned_uint32_t *)src;
2770                 dst += sizeof(uint32_t);
2771                 src += sizeof(uint32_t);
2772         }
2773         if (len & 0x02) {
2774                 *(uint16_t *)dst = *(unaligned_uint16_t *)src;
2775                 dst += sizeof(uint16_t);
2776                 src += sizeof(uint16_t);
2777         }
2778         if (len & 0x01)
2779                 *(uint8_t *)dst = *(uint8_t *)src;
2780 }
2781
2782 /**
2783  * Build the Data Segment of inlined data from single
2784  * segment packet, no VLAN insertion.
2785  *
2786  * @param txq
2787  *   Pointer to TX queue structure.
2788  * @param loc
2789  *   Pointer to burst routine local context.
2790  * @param dseg
2791  *   Pointer to WQE to fill with built Data Segment.
2792  * @param buf
2793  *   Data buffer to point.
2794  * @param len
2795  *   Data buffer length.
2796  * @param olx
2797  *   Configured Tx offloads mask. It is fully defined at
2798  *   compile time and may be used for optimization.
2799  *
2800  * @return
2801  *   Pointer to the next Data Segment after inlined data.
2802  *   Ring buffer wraparound check is needed. We do not
2803  *   do it here because it may not be needed for the
2804  *   last packet in the eMPW session.
2805  */
2806 static __rte_always_inline struct mlx5_wqe_dseg *
2807 mlx5_tx_dseg_empw(struct mlx5_txq_data *restrict txq,
2808                   struct mlx5_txq_local *restrict loc __rte_unused,
2809                   struct mlx5_wqe_dseg *restrict dseg,
2810                   uint8_t *buf,
2811                   unsigned int len,
2812                   unsigned int olx __rte_unused)
2813 {
2814         unsigned int part;
2815         uint8_t *pdst;
2816
2817         dseg->bcount = rte_cpu_to_be_32(len | MLX5_ETH_WQE_DATA_INLINE);
2818         pdst = &dseg->inline_data[0];
2819         /*
2820          * The WQEBB space availability is checked by caller.
2821          * Here we should be aware of WQE ring buffer wraparound only.
2822          */
2823         part = (uint8_t *)txq->wqes_end - pdst;
2824         part = RTE_MIN(part, len);
2825         do {
2826                 rte_memcpy(pdst, buf, part);
2827                 len -= part;
2828                 if (likely(!len)) {
2829                         pdst += part;
2830                         pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE);
2831                         /* Note: no final wraparound check here. */
2832                         return (struct mlx5_wqe_dseg *)pdst;
2833                 }
2834                 pdst = (uint8_t *)txq->wqes;
2835                 buf += part;
2836                 part = len;
2837         } while (true);
2838 }
2839
2840 /**
2841  * Build the Data Segment of inlined data from single
2842  * segment packet with VLAN insertion.
2843  *
2844  * @param txq
2845  *   Pointer to TX queue structure.
2846  * @param loc
2847  *   Pointer to burst routine local context.
2848  * @param dseg
2849  *   Pointer to the dseg fill with built Data Segment.
2850  * @param buf
2851  *   Data buffer to point.
2852  * @param len
2853  *   Data buffer length.
2854  * @param olx
2855  *   Configured Tx offloads mask. It is fully defined at
2856  *   compile time and may be used for optimization.
2857  *
2858  * @return
2859  *   Pointer to the next Data Segment after inlined data.
2860  *   Ring buffer wraparound check is needed.
2861  */
2862 static __rte_always_inline struct mlx5_wqe_dseg *
2863 mlx5_tx_dseg_vlan(struct mlx5_txq_data *restrict txq,
2864                   struct mlx5_txq_local *restrict loc __rte_unused,
2865                   struct mlx5_wqe_dseg *restrict dseg,
2866                   uint8_t *buf,
2867                   unsigned int len,
2868                   unsigned int olx __rte_unused)
2869
2870 {
2871         unsigned int part;
2872         uint8_t *pdst;
2873
2874         assert(len > MLX5_ESEG_MIN_INLINE_SIZE);
2875         static_assert(MLX5_DSEG_MIN_INLINE_SIZE ==
2876                                  (2 * RTE_ETHER_ADDR_LEN),
2877                       "invalid Data Segment data size");
2878         dseg->bcount = rte_cpu_to_be_32((len + sizeof(struct rte_vlan_hdr)) |
2879                                         MLX5_ETH_WQE_DATA_INLINE);
2880         pdst = &dseg->inline_data[0];
2881         memcpy(pdst, buf, MLX5_DSEG_MIN_INLINE_SIZE);
2882         buf += MLX5_DSEG_MIN_INLINE_SIZE;
2883         pdst += MLX5_DSEG_MIN_INLINE_SIZE;
2884         len -= MLX5_DSEG_MIN_INLINE_SIZE;
2885         /* Insert VLAN ethertype + VLAN tag. Pointer is aligned. */
2886         assert(pdst == RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE));
2887         if (unlikely(pdst >= (uint8_t *)txq->wqes_end))
2888                 pdst = (uint8_t *)txq->wqes;
2889         *(uint32_t *)pdst = rte_cpu_to_be_32((RTE_ETHER_TYPE_VLAN << 16) |
2890                                               loc->mbuf->vlan_tci);
2891         pdst += sizeof(struct rte_vlan_hdr);
2892         /*
2893          * The WQEBB space availability is checked by caller.
2894          * Here we should be aware of WQE ring buffer wraparound only.
2895          */
2896         part = (uint8_t *)txq->wqes_end - pdst;
2897         part = RTE_MIN(part, len);
2898         do {
2899                 rte_memcpy(pdst, buf, part);
2900                 len -= part;
2901                 if (likely(!len)) {
2902                         pdst += part;
2903                         pdst = RTE_PTR_ALIGN(pdst, MLX5_WSEG_SIZE);
2904                         /* Note: no final wraparound check here. */
2905                         return (struct mlx5_wqe_dseg *)pdst;
2906                 }
2907                 pdst = (uint8_t *)txq->wqes;
2908                 buf += part;
2909                 part = len;
2910         } while (true);
2911 }
2912
2913 /**
2914  * Build the Ethernet Segment with optionally inlined data with
2915  * VLAN insertion and following Data Segments (if any) from
2916  * multi-segment packet. Used by ordinary send and TSO.
2917  *
2918  * @param txq
2919  *   Pointer to TX queue structure.
2920  * @param loc
2921  *   Pointer to burst routine local context.
2922  * @param wqe
2923  *   Pointer to WQE to fill with built Ethernet/Data Segments.
2924  * @param vlan
2925  *   Length of VLAN header to insert, 0 means no VLAN insertion.
2926  * @param inlen
2927  *   Data length to inline. For TSO this parameter specifies
2928  *   exact value, for ordinary send routine can be aligned by
2929  *   caller to provide better WQE space saving and data buffer
2930  *   start address alignment. This length includes VLAN header
2931  *   being inserted.
2932  * @param tso
2933  *   Zero means ordinary send, inlined data can be extended,
2934  *   otherwise this is TSO, inlined data length is fixed.
2935  * @param olx
2936  *   Configured Tx offloads mask. It is fully defined at
2937  *   compile time and may be used for optimization.
2938  *
2939  * @return
2940  *   Actual size of built WQE in segments.
2941  */
2942 static __rte_always_inline unsigned int
2943 mlx5_tx_mseg_build(struct mlx5_txq_data *restrict txq,
2944                    struct mlx5_txq_local *restrict loc,
2945                    struct mlx5_wqe *restrict wqe,
2946                    unsigned int vlan,
2947                    unsigned int inlen,
2948                    unsigned int tso,
2949                    unsigned int olx __rte_unused)
2950 {
2951         struct mlx5_wqe_dseg *restrict dseg;
2952         unsigned int ds;
2953
2954         assert((rte_pktmbuf_pkt_len(loc->mbuf) + vlan) >= inlen);
2955         loc->mbuf_nseg = NB_SEGS(loc->mbuf);
2956         loc->mbuf_off = 0;
2957
2958         dseg = mlx5_tx_eseg_mdat(txq, loc, wqe, vlan, inlen, tso, olx);
2959         if (!loc->mbuf_nseg)
2960                 goto dseg_done;
2961         /*
2962          * There are still some mbuf remaining, not inlined.
2963          * The first mbuf may be partially inlined and we
2964          * must process the possible non-zero data offset.
2965          */
2966         if (loc->mbuf_off) {
2967                 unsigned int dlen;
2968                 uint8_t *dptr;
2969
2970                 /*
2971                  * Exhausted packets must be dropped before.
2972                  * Non-zero offset means there are some data
2973                  * remained in the packet.
2974                  */
2975                 assert(loc->mbuf_off < rte_pktmbuf_data_len(loc->mbuf));
2976                 assert(rte_pktmbuf_data_len(loc->mbuf));
2977                 dptr = rte_pktmbuf_mtod_offset(loc->mbuf, uint8_t *,
2978                                                loc->mbuf_off);
2979                 dlen = rte_pktmbuf_data_len(loc->mbuf) - loc->mbuf_off;
2980                 /*
2981                  * Build the pointer/minimal data Data Segment.
2982                  * Do ring buffer wrapping check in advance.
2983                  */
2984                 if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end)
2985                         dseg = (struct mlx5_wqe_dseg *)txq->wqes;
2986                 mlx5_tx_dseg_iptr(txq, loc, dseg, dptr, dlen, olx);
2987                 /* Store the mbuf to be freed on completion. */
2988                 assert(loc->elts_free);
2989                 txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
2990                 --loc->elts_free;
2991                 ++dseg;
2992                 if (--loc->mbuf_nseg == 0)
2993                         goto dseg_done;
2994                 loc->mbuf = loc->mbuf->next;
2995                 loc->mbuf_off = 0;
2996         }
2997         do {
2998                 if (unlikely(!rte_pktmbuf_data_len(loc->mbuf))) {
2999                         struct rte_mbuf *mbuf;
3000
3001                         /* Zero length segment found, just skip. */
3002                         mbuf = loc->mbuf;
3003                         loc->mbuf = loc->mbuf->next;
3004                         rte_pktmbuf_free_seg(mbuf);
3005                         if (--loc->mbuf_nseg == 0)
3006                                 break;
3007                 } else {
3008                         if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end)
3009                                 dseg = (struct mlx5_wqe_dseg *)txq->wqes;
3010                         mlx5_tx_dseg_iptr
3011                                 (txq, loc, dseg,
3012                                  rte_pktmbuf_mtod(loc->mbuf, uint8_t *),
3013                                  rte_pktmbuf_data_len(loc->mbuf), olx);
3014                         assert(loc->elts_free);
3015                         txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
3016                         --loc->elts_free;
3017                         ++dseg;
3018                         if (--loc->mbuf_nseg == 0)
3019                                 break;
3020                         loc->mbuf = loc->mbuf->next;
3021                 }
3022         } while (true);
3023
3024 dseg_done:
3025         /* Calculate actual segments used from the dseg pointer. */
3026         if ((uintptr_t)wqe < (uintptr_t)dseg)
3027                 ds = ((uintptr_t)dseg - (uintptr_t)wqe) / MLX5_WSEG_SIZE;
3028         else
3029                 ds = (((uintptr_t)dseg - (uintptr_t)wqe) +
3030                       txq->wqe_s * MLX5_WQE_SIZE) / MLX5_WSEG_SIZE;
3031         return ds;
3032 }
3033
3034 /**
3035  * Tx one packet function for multi-segment TSO. Supports all
3036  * types of Tx offloads, uses MLX5_OPCODE_TSO to build WQEs,
3037  * sends one packet per WQE.
3038  *
3039  * This routine is responsible for storing processed mbuf
3040  * into elts ring buffer and update elts_head.
3041  *
3042  * @param txq
3043  *   Pointer to TX queue structure.
3044  * @param loc
3045  *   Pointer to burst routine local context.
3046  * @param olx
3047  *   Configured Tx offloads mask. It is fully defined at
3048  *   compile time and may be used for optimization.
3049  *
3050  * @return
3051  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3052  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3053  * Local context variables partially updated.
3054  */
3055 static __rte_always_inline enum mlx5_txcmp_code
3056 mlx5_tx_packet_multi_tso(struct mlx5_txq_data *restrict txq,
3057                         struct mlx5_txq_local *restrict loc,
3058                         unsigned int olx)
3059 {
3060         struct mlx5_wqe *restrict wqe;
3061         unsigned int ds, dlen, inlen, ntcp, vlan = 0;
3062
3063         /*
3064          * Calculate data length to be inlined to estimate
3065          * the required space in WQE ring buffer.
3066          */
3067         dlen = rte_pktmbuf_pkt_len(loc->mbuf);
3068         if (MLX5_TXOFF_CONFIG(VLAN) && loc->mbuf->ol_flags & PKT_TX_VLAN_PKT)
3069                 vlan = sizeof(struct rte_vlan_hdr);
3070         inlen = loc->mbuf->l2_len + vlan +
3071                 loc->mbuf->l3_len + loc->mbuf->l4_len;
3072         if (unlikely((!inlen || !loc->mbuf->tso_segsz)))
3073                 return MLX5_TXCMP_CODE_ERROR;
3074         if (loc->mbuf->ol_flags & PKT_TX_TUNNEL_MASK)
3075                 inlen += loc->mbuf->outer_l2_len + loc->mbuf->outer_l3_len;
3076         /* Packet must contain all TSO headers. */
3077         if (unlikely(inlen > MLX5_MAX_TSO_HEADER ||
3078                      inlen <= MLX5_ESEG_MIN_INLINE_SIZE ||
3079                      inlen > (dlen + vlan)))
3080                 return MLX5_TXCMP_CODE_ERROR;
3081         assert(inlen >= txq->inlen_mode);
3082         /*
3083          * Check whether there are enough free WQEBBs:
3084          * - Control Segment
3085          * - Ethernet Segment
3086          * - First Segment of inlined Ethernet data
3087          * - ... data continued ...
3088          * - Data Segments of pointer/min inline type
3089          */
3090         ds = NB_SEGS(loc->mbuf) + 2 + (inlen -
3091                                        MLX5_ESEG_MIN_INLINE_SIZE +
3092                                        MLX5_WSEG_SIZE +
3093                                        MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE;
3094         if (unlikely(loc->wqe_free < ((ds + 3) / 4)))
3095                 return MLX5_TXCMP_CODE_EXIT;
3096         /* Check for maximal WQE size. */
3097         if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ((ds + 3) / 4)))
3098                 return MLX5_TXCMP_CODE_ERROR;
3099 #ifdef MLX5_PMD_SOFT_COUNTERS
3100         /* Update sent data bytes/packets counters. */
3101         ntcp = (dlen - (inlen - vlan) + loc->mbuf->tso_segsz - 1) /
3102                 loc->mbuf->tso_segsz;
3103         /*
3104          * One will be added for mbuf itself
3105          * at the end of the mlx5_tx_burst from
3106          * loc->pkts_sent field.
3107          */
3108         --ntcp;
3109         txq->stats.opackets += ntcp;
3110         txq->stats.obytes += dlen + vlan + ntcp * inlen;
3111 #endif
3112         wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
3113         loc->wqe_last = wqe;
3114         mlx5_tx_cseg_init(txq, loc, wqe, 0, MLX5_OPCODE_TSO, olx);
3115         ds = mlx5_tx_mseg_build(txq, loc, wqe, vlan, inlen, 1, olx);
3116         wqe->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds);
3117         txq->wqe_ci += (ds + 3) / 4;
3118         loc->wqe_free -= (ds + 3) / 4;
3119         return MLX5_TXCMP_CODE_MULTI;
3120 }
3121
3122 /**
3123  * Tx one packet function for multi-segment SEND. Supports all
3124  * types of Tx offloads, uses MLX5_OPCODE_SEND to build WQEs,
3125  * sends one packet per WQE, without any data inlining in
3126  * Ethernet Segment.
3127  *
3128  * This routine is responsible for storing processed mbuf
3129  * into elts ring buffer and update elts_head.
3130  *
3131  * @param txq
3132  *   Pointer to TX queue structure.
3133  * @param loc
3134  *   Pointer to burst routine local context.
3135  * @param olx
3136  *   Configured Tx offloads mask. It is fully defined at
3137  *   compile time and may be used for optimization.
3138  *
3139  * @return
3140  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3141  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3142  * Local context variables partially updated.
3143  */
3144 static __rte_always_inline enum mlx5_txcmp_code
3145 mlx5_tx_packet_multi_send(struct mlx5_txq_data *restrict txq,
3146                           struct mlx5_txq_local *restrict loc,
3147                           unsigned int olx)
3148 {
3149         struct mlx5_wqe_dseg *restrict dseg;
3150         struct mlx5_wqe *restrict wqe;
3151         unsigned int ds, nseg;
3152
3153         assert(NB_SEGS(loc->mbuf) > 1);
3154         /*
3155          * No inline at all, it means the CPU cycles saving
3156          * is prioritized at configuration, we should not
3157          * copy any packet data to WQE.
3158          */
3159         nseg = NB_SEGS(loc->mbuf);
3160         ds = 2 + nseg;
3161         if (unlikely(loc->wqe_free < ((ds + 3) / 4)))
3162                 return MLX5_TXCMP_CODE_EXIT;
3163         /* Check for maximal WQE size. */
3164         if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ((ds + 3) / 4)))
3165                 return MLX5_TXCMP_CODE_ERROR;
3166         /*
3167          * Some Tx offloads may cause an error if
3168          * packet is not long enough, check against
3169          * assumed minimal length.
3170          */
3171         if (rte_pktmbuf_pkt_len(loc->mbuf) <= MLX5_ESEG_MIN_INLINE_SIZE)
3172                 return MLX5_TXCMP_CODE_ERROR;
3173 #ifdef MLX5_PMD_SOFT_COUNTERS
3174         /* Update sent data bytes counter. */
3175         txq->stats.obytes += rte_pktmbuf_pkt_len(loc->mbuf);
3176         if (MLX5_TXOFF_CONFIG(VLAN) &&
3177             loc->mbuf->ol_flags & PKT_TX_VLAN_PKT)
3178                 txq->stats.obytes += sizeof(struct rte_vlan_hdr);
3179 #endif
3180         /*
3181          * SEND WQE, one WQEBB:
3182          * - Control Segment, SEND opcode
3183          * - Ethernet Segment, optional VLAN, no inline
3184          * - Data Segments, pointer only type
3185          */
3186         wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
3187         loc->wqe_last = wqe;
3188         mlx5_tx_cseg_init(txq, loc, wqe, ds, MLX5_OPCODE_SEND, olx);
3189         mlx5_tx_eseg_none(txq, loc, wqe, olx);
3190         dseg = &wqe->dseg[0];
3191         do {
3192                 if (unlikely(!rte_pktmbuf_data_len(loc->mbuf))) {
3193                         struct rte_mbuf *mbuf;
3194
3195                         /*
3196                          * Zero length segment found, have to
3197                          * correct total size of WQE in segments.
3198                          * It is supposed to be rare occasion, so
3199                          * in normal case (no zero length segments)
3200                          * we avoid extra writing to the Control
3201                          * Segment.
3202                          */
3203                         --ds;
3204                         wqe->cseg.sq_ds -= RTE_BE32(1);
3205                         mbuf = loc->mbuf;
3206                         loc->mbuf = mbuf->next;
3207                         rte_pktmbuf_free_seg(mbuf);
3208                         if (--nseg == 0)
3209                                 break;
3210                 } else {
3211                         mlx5_tx_dseg_ptr
3212                                 (txq, loc, dseg,
3213                                  rte_pktmbuf_mtod(loc->mbuf, uint8_t *),
3214                                  rte_pktmbuf_data_len(loc->mbuf), olx);
3215                         txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
3216                         --loc->elts_free;
3217                         if (--nseg == 0)
3218                                 break;
3219                         ++dseg;
3220                         if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end)
3221                                 dseg = (struct mlx5_wqe_dseg *)txq->wqes;
3222                         loc->mbuf = loc->mbuf->next;
3223                 }
3224         } while (true);
3225         txq->wqe_ci += (ds + 3) / 4;
3226         loc->wqe_free -= (ds + 3) / 4;
3227         return MLX5_TXCMP_CODE_MULTI;
3228 }
3229
3230 /**
3231  * Tx one packet function for multi-segment SEND. Supports all
3232  * types of Tx offloads, uses MLX5_OPCODE_SEND to build WQEs,
3233  * sends one packet per WQE, with data inlining in
3234  * Ethernet Segment and minimal Data Segments.
3235  *
3236  * This routine is responsible for storing processed mbuf
3237  * into elts ring buffer and update elts_head.
3238  *
3239  * @param txq
3240  *   Pointer to TX queue structure.
3241  * @param loc
3242  *   Pointer to burst routine local context.
3243  * @param olx
3244  *   Configured Tx offloads mask. It is fully defined at
3245  *   compile time and may be used for optimization.
3246  *
3247  * @return
3248  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3249  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3250  * Local context variables partially updated.
3251  */
3252 static __rte_always_inline enum mlx5_txcmp_code
3253 mlx5_tx_packet_multi_inline(struct mlx5_txq_data *restrict txq,
3254                             struct mlx5_txq_local *restrict loc,
3255                             unsigned int olx)
3256 {
3257         struct mlx5_wqe *restrict wqe;
3258         unsigned int ds, inlen, dlen, vlan = 0;
3259
3260         assert(MLX5_TXOFF_CONFIG(INLINE));
3261         assert(NB_SEGS(loc->mbuf) > 1);
3262         /*
3263          * First calculate data length to be inlined
3264          * to estimate the required space for WQE.
3265          */
3266         dlen = rte_pktmbuf_pkt_len(loc->mbuf);
3267         if (MLX5_TXOFF_CONFIG(VLAN) && loc->mbuf->ol_flags & PKT_TX_VLAN_PKT)
3268                 vlan = sizeof(struct rte_vlan_hdr);
3269         inlen = dlen + vlan;
3270         /* Check against minimal length. */
3271         if (inlen <= MLX5_ESEG_MIN_INLINE_SIZE)
3272                 return MLX5_TXCMP_CODE_ERROR;
3273         assert(txq->inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE);
3274         if (inlen > txq->inlen_send) {
3275                 struct rte_mbuf *mbuf;
3276                 unsigned int nxlen;
3277                 uintptr_t start;
3278
3279                 /*
3280                  * Packet length exceeds the allowed inline
3281                  * data length, check whether the minimal
3282                  * inlining is required.
3283                  */
3284                 if (txq->inlen_mode) {
3285                         assert(txq->inlen_mode >= MLX5_ESEG_MIN_INLINE_SIZE);
3286                         assert(txq->inlen_mode <= txq->inlen_send);
3287                         inlen = txq->inlen_mode;
3288                 } else {
3289                         if (!vlan || txq->vlan_en) {
3290                                 /*
3291                                  * VLAN insertion will be done inside by HW.
3292                                  * It is not utmost effective - VLAN flag is
3293                                  * checked twice, but we should proceed the
3294                                  * inlining length correctly and take into
3295                                  * account the VLAN header being inserted.
3296                                  */
3297                                 return mlx5_tx_packet_multi_send
3298                                                         (txq, loc, olx);
3299                         }
3300                         inlen = MLX5_ESEG_MIN_INLINE_SIZE;
3301                 }
3302                 /*
3303                  * Now we know the minimal amount of data is requested
3304                  * to inline. Check whether we should inline the buffers
3305                  * from the chain beginning to eliminate some mbufs.
3306                  */
3307                 mbuf = loc->mbuf;
3308                 nxlen = rte_pktmbuf_data_len(mbuf);
3309                 if (unlikely(nxlen <= txq->inlen_send)) {
3310                         /* We can inline first mbuf at least. */
3311                         if (nxlen < inlen) {
3312                                 unsigned int smlen;
3313
3314                                 /* Scan mbufs till inlen filled. */
3315                                 do {
3316                                         smlen = nxlen;
3317                                         mbuf = NEXT(mbuf);
3318                                         assert(mbuf);
3319                                         nxlen = rte_pktmbuf_data_len(mbuf);
3320                                         nxlen += smlen;
3321                                 } while (unlikely(nxlen < inlen));
3322                                 if (unlikely(nxlen > txq->inlen_send)) {
3323                                         /* We cannot inline entire mbuf. */
3324                                         smlen = inlen - smlen;
3325                                         start = rte_pktmbuf_mtod_offset
3326                                                     (mbuf, uintptr_t, smlen);
3327                                         goto do_align;
3328                                 }
3329                         }
3330                         do {
3331                                 inlen = nxlen;
3332                                 mbuf = NEXT(mbuf);
3333                                 /* There should be not end of packet. */
3334                                 assert(mbuf);
3335                                 nxlen = inlen + rte_pktmbuf_data_len(mbuf);
3336                         } while (unlikely(nxlen < txq->inlen_send));
3337                 }
3338                 start = rte_pktmbuf_mtod(mbuf, uintptr_t);
3339                 /*
3340                  * Check whether we can do inline to align start
3341                  * address of data buffer to cacheline.
3342                  */
3343 do_align:
3344                 start = (~start + 1) & (RTE_CACHE_LINE_SIZE - 1);
3345                 if (unlikely(start)) {
3346                         start += inlen;
3347                         if (start <= txq->inlen_send)
3348                                 inlen = start;
3349                 }
3350         }
3351         /*
3352          * Check whether there are enough free WQEBBs:
3353          * - Control Segment
3354          * - Ethernet Segment
3355          * - First Segment of inlined Ethernet data
3356          * - ... data continued ...
3357          * - Data Segments of pointer/min inline type
3358          *
3359          * Estimate the number of Data Segments conservatively,
3360          * supposing no any mbufs is being freed during inlining.
3361          */
3362         assert(inlen <= txq->inlen_send);
3363         ds = NB_SEGS(loc->mbuf) + 2 + (inlen -
3364                                        MLX5_ESEG_MIN_INLINE_SIZE +
3365                                        MLX5_WSEG_SIZE +
3366                                        MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE;
3367         if (unlikely(loc->wqe_free < ((ds + 3) / 4)))
3368                 return MLX5_TXCMP_CODE_EXIT;
3369         /* Check for maximal WQE size. */
3370         if (unlikely((MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE) < ((ds + 3) / 4)))
3371                 return MLX5_TXCMP_CODE_ERROR;
3372 #ifdef MLX5_PMD_SOFT_COUNTERS
3373         /* Update sent data bytes/packets counters. */
3374         txq->stats.obytes += dlen + vlan;
3375 #endif
3376         wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
3377         loc->wqe_last = wqe;
3378         mlx5_tx_cseg_init(txq, loc, wqe, 0, MLX5_OPCODE_SEND, olx);
3379         ds = mlx5_tx_mseg_build(txq, loc, wqe, vlan, inlen, 0, olx);
3380         wqe->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds);
3381         txq->wqe_ci += (ds + 3) / 4;
3382         loc->wqe_free -= (ds + 3) / 4;
3383         return MLX5_TXCMP_CODE_MULTI;
3384 }
3385
3386 /**
3387  * Tx burst function for multi-segment packets. Supports all
3388  * types of Tx offloads, uses MLX5_OPCODE_SEND/TSO to build WQEs,
3389  * sends one packet per WQE. Function stops sending if it
3390  * encounters the single-segment packet.
3391  *
3392  * This routine is responsible for storing processed mbuf
3393  * into elts ring buffer and update elts_head.
3394  *
3395  * @param txq
3396  *   Pointer to TX queue structure.
3397  * @param[in] pkts
3398  *   Packets to transmit.
3399  * @param pkts_n
3400  *   Number of packets in array.
3401  * @param loc
3402  *   Pointer to burst routine local context.
3403  * @param olx
3404  *   Configured Tx offloads mask. It is fully defined at
3405  *   compile time and may be used for optimization.
3406  *
3407  * @return
3408  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3409  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3410  *   MLX5_TXCMP_CODE_SINGLE - single-segment packet encountered.
3411  *   MLX5_TXCMP_CODE_TSO - TSO single-segment packet encountered.
3412  * Local context variables updated.
3413  */
3414 static __rte_always_inline enum mlx5_txcmp_code
3415 mlx5_tx_burst_mseg(struct mlx5_txq_data *restrict txq,
3416                    struct rte_mbuf **restrict pkts,
3417                    unsigned int pkts_n,
3418                    struct mlx5_txq_local *restrict loc,
3419                    unsigned int olx)
3420 {
3421         assert(loc->elts_free && loc->wqe_free);
3422         assert(pkts_n > loc->pkts_sent);
3423         pkts += loc->pkts_sent + 1;
3424         pkts_n -= loc->pkts_sent;
3425         for (;;) {
3426                 enum mlx5_txcmp_code ret;
3427
3428                 assert(NB_SEGS(loc->mbuf) > 1);
3429                 /*
3430                  * Estimate the number of free elts quickly but
3431                  * conservatively. Some segment may be fully inlined
3432                  * and freed, ignore this here - precise estimation
3433                  * is costly.
3434                  */
3435                 if (loc->elts_free < NB_SEGS(loc->mbuf))
3436                         return MLX5_TXCMP_CODE_EXIT;
3437                 if (MLX5_TXOFF_CONFIG(TSO) &&
3438                     unlikely(loc->mbuf->ol_flags & PKT_TX_TCP_SEG)) {
3439                         /* Proceed with multi-segment TSO. */
3440                         ret = mlx5_tx_packet_multi_tso(txq, loc, olx);
3441                 } else if (MLX5_TXOFF_CONFIG(INLINE)) {
3442                         /* Proceed with multi-segment SEND with inlining. */
3443                         ret = mlx5_tx_packet_multi_inline(txq, loc, olx);
3444                 } else {
3445                         /* Proceed with multi-segment SEND w/o inlining. */
3446                         ret = mlx5_tx_packet_multi_send(txq, loc, olx);
3447                 }
3448                 if (ret == MLX5_TXCMP_CODE_EXIT)
3449                         return MLX5_TXCMP_CODE_EXIT;
3450                 if (ret == MLX5_TXCMP_CODE_ERROR)
3451                         return MLX5_TXCMP_CODE_ERROR;
3452                 /* WQE is built, go to the next packet. */
3453                 ++loc->pkts_sent;
3454                 --pkts_n;
3455                 if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free))
3456                         return MLX5_TXCMP_CODE_EXIT;
3457                 loc->mbuf = *pkts++;
3458                 if (pkts_n > 1)
3459                         rte_prefetch0(*pkts);
3460                 if (likely(NB_SEGS(loc->mbuf) > 1))
3461                         continue;
3462                 /* Here ends the series of multi-segment packets. */
3463                 if (MLX5_TXOFF_CONFIG(TSO) &&
3464                     unlikely(loc->mbuf->ol_flags & PKT_TX_TCP_SEG))
3465                         return MLX5_TXCMP_CODE_TSO;
3466                 return MLX5_TXCMP_CODE_SINGLE;
3467         }
3468         assert(false);
3469 }
3470
3471 /**
3472  * Tx burst function for single-segment packets with TSO.
3473  * Supports all types of Tx offloads, except multi-packets.
3474  * Uses MLX5_OPCODE_TSO to build WQEs, sends one packet per WQE.
3475  * Function stops sending if it encounters the multi-segment
3476  * packet or packet without TSO requested.
3477  *
3478  * The routine is responsible for storing processed mbuf
3479  * into elts ring buffer and update elts_head if inline
3480  * offloads is requested due to possible early freeing
3481  * of the inlined mbufs (can not store pkts array in elts
3482  * as a batch).
3483  *
3484  * @param txq
3485  *   Pointer to TX queue structure.
3486  * @param[in] pkts
3487  *   Packets to transmit.
3488  * @param pkts_n
3489  *   Number of packets in array.
3490  * @param loc
3491  *   Pointer to burst routine local context.
3492  * @param olx
3493  *   Configured Tx offloads mask. It is fully defined at
3494  *   compile time and may be used for optimization.
3495  *
3496  * @return
3497  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3498  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3499  *   MLX5_TXCMP_CODE_SINGLE - single-segment packet encountered.
3500  *   MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered.
3501  * Local context variables updated.
3502  */
3503 static __rte_always_inline enum mlx5_txcmp_code
3504 mlx5_tx_burst_tso(struct mlx5_txq_data *restrict txq,
3505                   struct rte_mbuf **restrict pkts,
3506                   unsigned int pkts_n,
3507                   struct mlx5_txq_local *restrict loc,
3508                   unsigned int olx)
3509 {
3510         assert(loc->elts_free && loc->wqe_free);
3511         assert(pkts_n > loc->pkts_sent);
3512         pkts += loc->pkts_sent + 1;
3513         pkts_n -= loc->pkts_sent;
3514         for (;;) {
3515                 struct mlx5_wqe_dseg *restrict dseg;
3516                 struct mlx5_wqe *restrict wqe;
3517                 unsigned int ds, dlen, hlen, ntcp, vlan = 0;
3518                 uint8_t *dptr;
3519
3520                 assert(NB_SEGS(loc->mbuf) == 1);
3521                 dlen = rte_pktmbuf_data_len(loc->mbuf);
3522                 if (MLX5_TXOFF_CONFIG(VLAN) &&
3523                     loc->mbuf->ol_flags & PKT_TX_VLAN_PKT) {
3524                         vlan = sizeof(struct rte_vlan_hdr);
3525                 }
3526                 /*
3527                  * First calculate the WQE size to check
3528                  * whether we have enough space in ring buffer.
3529                  */
3530                 hlen = loc->mbuf->l2_len + vlan +
3531                        loc->mbuf->l3_len + loc->mbuf->l4_len;
3532                 if (unlikely((!hlen || !loc->mbuf->tso_segsz)))
3533                         return MLX5_TXCMP_CODE_ERROR;
3534                 if (loc->mbuf->ol_flags & PKT_TX_TUNNEL_MASK)
3535                         hlen += loc->mbuf->outer_l2_len +
3536                                 loc->mbuf->outer_l3_len;
3537                 /* Segment must contain all TSO headers. */
3538                 if (unlikely(hlen > MLX5_MAX_TSO_HEADER ||
3539                              hlen <= MLX5_ESEG_MIN_INLINE_SIZE ||
3540                              hlen > (dlen + vlan)))
3541                         return MLX5_TXCMP_CODE_ERROR;
3542                 /*
3543                  * Check whether there are enough free WQEBBs:
3544                  * - Control Segment
3545                  * - Ethernet Segment
3546                  * - First Segment of inlined Ethernet data
3547                  * - ... data continued ...
3548                  * - Finishing Data Segment of pointer type
3549                  */
3550                 ds = 4 + (hlen - MLX5_ESEG_MIN_INLINE_SIZE +
3551                           MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE;
3552                 if (loc->wqe_free < ((ds + 3) / 4))
3553                         return MLX5_TXCMP_CODE_EXIT;
3554 #ifdef MLX5_PMD_SOFT_COUNTERS
3555                 /* Update sent data bytes/packets counters. */
3556                 ntcp = (dlen + vlan - hlen +
3557                         loc->mbuf->tso_segsz - 1) /
3558                         loc->mbuf->tso_segsz;
3559                 /*
3560                  * One will be added for mbuf itself at the end
3561                  * of the mlx5_tx_burst from loc->pkts_sent field.
3562                  */
3563                 --ntcp;
3564                 txq->stats.opackets += ntcp;
3565                 txq->stats.obytes += dlen + vlan + ntcp * hlen;
3566 #endif
3567                 /*
3568                  * Build the TSO WQE:
3569                  * - Control Segment
3570                  * - Ethernet Segment with hlen bytes inlined
3571                  * - Data Segment of pointer type
3572                  */
3573                 wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
3574                 loc->wqe_last = wqe;
3575                 mlx5_tx_cseg_init(txq, loc, wqe, ds,
3576                                   MLX5_OPCODE_TSO, olx);
3577                 dseg = mlx5_tx_eseg_data(txq, loc, wqe, vlan, hlen, 1, olx);
3578                 dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) + hlen - vlan;
3579                 dlen -= hlen - vlan;
3580                 mlx5_tx_dseg_ptr(txq, loc, dseg, dptr, dlen, olx);
3581                 /*
3582                  * WQE is built, update the loop parameters
3583                  * and go to the next packet.
3584                  */
3585                 txq->wqe_ci += (ds + 3) / 4;
3586                 loc->wqe_free -= (ds + 3) / 4;
3587                 if (MLX5_TXOFF_CONFIG(INLINE))
3588                         txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
3589                 --loc->elts_free;
3590                 ++loc->pkts_sent;
3591                 --pkts_n;
3592                 if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free))
3593                         return MLX5_TXCMP_CODE_EXIT;
3594                 loc->mbuf = *pkts++;
3595                 if (pkts_n > 1)
3596                         rte_prefetch0(*pkts);
3597                 if (MLX5_TXOFF_CONFIG(MULTI) &&
3598                     unlikely(NB_SEGS(loc->mbuf) > 1))
3599                         return MLX5_TXCMP_CODE_MULTI;
3600                 if (likely(!(loc->mbuf->ol_flags & PKT_TX_TCP_SEG)))
3601                         return MLX5_TXCMP_CODE_SINGLE;
3602                 /* Continue with the next TSO packet. */
3603         }
3604         assert(false);
3605 }
3606
3607 /**
3608  * Analyze the packet and select the best method to send.
3609  *
3610  * @param txq
3611  *   Pointer to TX queue structure.
3612  * @param loc
3613  *   Pointer to burst routine local context.
3614  * @param olx
3615  *   Configured Tx offloads mask. It is fully defined at
3616  *   compile time and may be used for optimization.
3617  * @param newp
3618  *   The predefined flag whether do complete check for
3619  *   multi-segment packets and TSO.
3620  *
3621  * @return
3622  *  MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered.
3623  *  MLX5_TXCMP_CODE_TSO - TSO required, use TSO/LSO.
3624  *  MLX5_TXCMP_CODE_SINGLE - single-segment packet, use SEND.
3625  *  MLX5_TXCMP_CODE_EMPW - single-segment packet, use MPW.
3626  */
3627 static __rte_always_inline enum mlx5_txcmp_code
3628 mlx5_tx_able_to_empw(struct mlx5_txq_data *restrict txq,
3629                      struct mlx5_txq_local *restrict loc,
3630                      unsigned int olx,
3631                      bool newp)
3632 {
3633         /* Check for multi-segment packet. */
3634         if (newp &&
3635             MLX5_TXOFF_CONFIG(MULTI) &&
3636             unlikely(NB_SEGS(loc->mbuf) > 1))
3637                 return MLX5_TXCMP_CODE_MULTI;
3638         /* Check for TSO packet. */
3639         if (newp &&
3640             MLX5_TXOFF_CONFIG(TSO) &&
3641             unlikely(loc->mbuf->ol_flags & PKT_TX_TCP_SEG))
3642                 return MLX5_TXCMP_CODE_TSO;
3643         /* Check if eMPW is enabled at all. */
3644         if (!MLX5_TXOFF_CONFIG(EMPW))
3645                 return MLX5_TXCMP_CODE_SINGLE;
3646         /* Check if eMPW can be engaged. */
3647         if (MLX5_TXOFF_CONFIG(VLAN) &&
3648             unlikely(loc->mbuf->ol_flags & PKT_TX_VLAN_PKT) &&
3649                 (!MLX5_TXOFF_CONFIG(INLINE) ||
3650                  unlikely((rte_pktmbuf_data_len(loc->mbuf) +
3651                            sizeof(struct rte_vlan_hdr)) > txq->inlen_empw))) {
3652                 /*
3653                  * eMPW does not support VLAN insertion offload,
3654                  * we have to inline the entire packet but
3655                  * packet is too long for inlining.
3656                  */
3657                 return MLX5_TXCMP_CODE_SINGLE;
3658         }
3659         return MLX5_TXCMP_CODE_EMPW;
3660 }
3661
3662 /**
3663  * Check the next packet attributes to match with the eMPW batch ones.
3664  * In addition, for legacy MPW the packet length is checked either.
3665  *
3666  * @param txq
3667  *   Pointer to TX queue structure.
3668  * @param es
3669  *   Pointer to Ethernet Segment of eMPW batch.
3670  * @param loc
3671  *   Pointer to burst routine local context.
3672  * @param dlen
3673  *   Length of previous packet in MPW descriptor.
3674  * @param olx
3675  *   Configured Tx offloads mask. It is fully defined at
3676  *   compile time and may be used for optimization.
3677  *
3678  * @return
3679  *  true - packet match with eMPW batch attributes.
3680  *  false - no match, eMPW should be restarted.
3681  */
3682 static __rte_always_inline bool
3683 mlx5_tx_match_empw(struct mlx5_txq_data *restrict txq __rte_unused,
3684                    struct mlx5_wqe_eseg *restrict es,
3685                    struct mlx5_txq_local *restrict loc,
3686                    uint32_t dlen,
3687                    unsigned int olx)
3688 {
3689         uint8_t swp_flags = 0;
3690
3691         /* Compare the checksum flags, if any. */
3692         if (MLX5_TXOFF_CONFIG(CSUM) &&
3693             txq_ol_cksum_to_cs(loc->mbuf) != es->cs_flags)
3694                 return false;
3695         /* Compare the Software Parser offsets and flags. */
3696         if (MLX5_TXOFF_CONFIG(SWP) &&
3697             (es->swp_offs != txq_mbuf_to_swp(loc, &swp_flags, olx) ||
3698              es->swp_flags != swp_flags))
3699                 return false;
3700         /* Fill metadata field if needed. */
3701         if (MLX5_TXOFF_CONFIG(METADATA) &&
3702                 es->metadata != (loc->mbuf->ol_flags & PKT_TX_DYNF_METADATA ?
3703                                  *RTE_FLOW_DYNF_METADATA(loc->mbuf) : 0))
3704                 return false;
3705         /* Legacy MPW can send packets with the same lengt only. */
3706         if (MLX5_TXOFF_CONFIG(MPW) &&
3707             dlen != rte_pktmbuf_data_len(loc->mbuf))
3708                 return false;
3709         /* There must be no VLAN packets in eMPW loop. */
3710         if (MLX5_TXOFF_CONFIG(VLAN))
3711                 assert(!(loc->mbuf->ol_flags & PKT_TX_VLAN_PKT));
3712         return true;
3713 }
3714
3715 /*
3716  * Update send loop variables and WQE for eMPW loop
3717  * without data inlining. Number of Data Segments is
3718  * equal to the number of sent packets.
3719  *
3720  * @param txq
3721  *   Pointer to TX queue structure.
3722  * @param loc
3723  *   Pointer to burst routine local context.
3724  * @param ds
3725  *   Number of packets/Data Segments/Packets.
3726  * @param slen
3727  *   Accumulated statistics, bytes sent
3728  * @param olx
3729  *   Configured Tx offloads mask. It is fully defined at
3730  *   compile time and may be used for optimization.
3731  *
3732  * @return
3733  *  true - packet match with eMPW batch attributes.
3734  *  false - no match, eMPW should be restarted.
3735  */
3736 static __rte_always_inline void
3737 mlx5_tx_sdone_empw(struct mlx5_txq_data *restrict txq,
3738                    struct mlx5_txq_local *restrict loc,
3739                    unsigned int ds,
3740                    unsigned int slen,
3741                    unsigned int olx __rte_unused)
3742 {
3743         assert(!MLX5_TXOFF_CONFIG(INLINE));
3744 #ifdef MLX5_PMD_SOFT_COUNTERS
3745         /* Update sent data bytes counter. */
3746          txq->stats.obytes += slen;
3747 #else
3748         (void)slen;
3749 #endif
3750         loc->elts_free -= ds;
3751         loc->pkts_sent += ds;
3752         ds += 2;
3753         loc->wqe_last->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | ds);
3754         txq->wqe_ci += (ds + 3) / 4;
3755         loc->wqe_free -= (ds + 3) / 4;
3756 }
3757
3758 /*
3759  * Update send loop variables and WQE for eMPW loop
3760  * with data inlining. Gets the size of pushed descriptors
3761  * and data to the WQE.
3762  *
3763  * @param txq
3764  *   Pointer to TX queue structure.
3765  * @param loc
3766  *   Pointer to burst routine local context.
3767  * @param len
3768  *   Total size of descriptor/data in bytes.
3769  * @param slen
3770  *   Accumulated statistics, data bytes sent.
3771  * @param olx
3772  *   Configured Tx offloads mask. It is fully defined at
3773  *   compile time and may be used for optimization.
3774  *
3775  * @return
3776  *  true - packet match with eMPW batch attributes.
3777  *  false - no match, eMPW should be restarted.
3778  */
3779 static __rte_always_inline void
3780 mlx5_tx_idone_empw(struct mlx5_txq_data *restrict txq,
3781                    struct mlx5_txq_local *restrict loc,
3782                    unsigned int len,
3783                    unsigned int slen,
3784                    unsigned int olx __rte_unused)
3785 {
3786         assert(MLX5_TXOFF_CONFIG(INLINE));
3787         assert((len % MLX5_WSEG_SIZE) == 0);
3788 #ifdef MLX5_PMD_SOFT_COUNTERS
3789         /* Update sent data bytes counter. */
3790          txq->stats.obytes += slen;
3791 #else
3792         (void)slen;
3793 #endif
3794         len = len / MLX5_WSEG_SIZE + 2;
3795         loc->wqe_last->cseg.sq_ds = rte_cpu_to_be_32(txq->qp_num_8s | len);
3796         txq->wqe_ci += (len + 3) / 4;
3797         loc->wqe_free -= (len + 3) / 4;
3798 }
3799
3800 /**
3801  * The set of Tx burst functions for single-segment packets
3802  * without TSO and with Multi-Packet Writing feature support.
3803  * Supports all types of Tx offloads, except multi-packets
3804  * and TSO.
3805  *
3806  * Uses MLX5_OPCODE_EMPW to build WQEs if possible and sends
3807  * as many packet per WQE as it can. If eMPW is not configured
3808  * or packet can not be sent with eMPW (VLAN insertion) the
3809  * ordinary SEND opcode is used and only one packet placed
3810  * in WQE.
3811  *
3812  * Functions stop sending if it encounters the multi-segment
3813  * packet or packet with TSO requested.
3814  *
3815  * The routines are responsible for storing processed mbuf
3816  * into elts ring buffer and update elts_head if inlining
3817  * offload is requested. Otherwise the copying mbufs to elts
3818  * can be postponed and completed at the end of burst routine.
3819  *
3820  * @param txq
3821  *   Pointer to TX queue structure.
3822  * @param[in] pkts
3823  *   Packets to transmit.
3824  * @param pkts_n
3825  *   Number of packets in array.
3826  * @param loc
3827  *   Pointer to burst routine local context.
3828  * @param olx
3829  *   Configured Tx offloads mask. It is fully defined at
3830  *   compile time and may be used for optimization.
3831  *
3832  * @return
3833  *   MLX5_TXCMP_CODE_EXIT - sending is done or impossible.
3834  *   MLX5_TXCMP_CODE_ERROR - some unrecoverable error occurred.
3835  *   MLX5_TXCMP_CODE_MULTI - multi-segment packet encountered.
3836  *   MLX5_TXCMP_CODE_TSO - TSO packet encountered.
3837  *   MLX5_TXCMP_CODE_SINGLE - used inside functions set.
3838  *   MLX5_TXCMP_CODE_EMPW - used inside functions set.
3839  *
3840  * Local context variables updated.
3841  *
3842  *
3843  * The routine sends packets with MLX5_OPCODE_EMPW
3844  * without inlining, this is dedicated optimized branch.
3845  * No VLAN insertion is supported.
3846  */
3847 static __rte_always_inline enum mlx5_txcmp_code
3848 mlx5_tx_burst_empw_simple(struct mlx5_txq_data *restrict txq,
3849                           struct rte_mbuf **restrict pkts,
3850                           unsigned int pkts_n,
3851                           struct mlx5_txq_local *restrict loc,
3852                           unsigned int olx)
3853 {
3854         /*
3855          * Subroutine is the part of mlx5_tx_burst_single()
3856          * and sends single-segment packet with eMPW opcode
3857          * without data inlining.
3858          */
3859         assert(!MLX5_TXOFF_CONFIG(INLINE));
3860         assert(MLX5_TXOFF_CONFIG(EMPW));
3861         assert(loc->elts_free && loc->wqe_free);
3862         assert(pkts_n > loc->pkts_sent);
3863         static_assert(MLX5_EMPW_MIN_PACKETS >= 2, "invalid min size");
3864         pkts += loc->pkts_sent + 1;
3865         pkts_n -= loc->pkts_sent;
3866         for (;;) {
3867                 struct mlx5_wqe_dseg *restrict dseg;
3868                 struct mlx5_wqe_eseg *restrict eseg;
3869                 enum mlx5_txcmp_code ret;
3870                 unsigned int part, loop;
3871                 unsigned int slen = 0;
3872
3873 next_empw:
3874                 assert(NB_SEGS(loc->mbuf) == 1);
3875                 part = RTE_MIN(pkts_n, MLX5_TXOFF_CONFIG(MPW) ?
3876                                        MLX5_MPW_MAX_PACKETS :
3877                                        MLX5_EMPW_MAX_PACKETS);
3878                 if (unlikely(loc->elts_free < part)) {
3879                         /* We have no enough elts to save all mbufs. */
3880                         if (unlikely(loc->elts_free < MLX5_EMPW_MIN_PACKETS))
3881                                 return MLX5_TXCMP_CODE_EXIT;
3882                         /* But we still able to send at least minimal eMPW. */
3883                         part = loc->elts_free;
3884                 }
3885                 /* Check whether we have enough WQEs */
3886                 if (unlikely(loc->wqe_free < ((2 + part + 3) / 4))) {
3887                         if (unlikely(loc->wqe_free <
3888                                 ((2 + MLX5_EMPW_MIN_PACKETS + 3) / 4)))
3889                                 return MLX5_TXCMP_CODE_EXIT;
3890                         part = (loc->wqe_free * 4) - 2;
3891                 }
3892                 if (likely(part > 1))
3893                         rte_prefetch0(*pkts);
3894                 loc->wqe_last = txq->wqes + (txq->wqe_ci & txq->wqe_m);
3895                 /*
3896                  * Build eMPW title WQEBB:
3897                  * - Control Segment, eMPW opcode
3898                  * - Ethernet Segment, no inline
3899                  */
3900                 mlx5_tx_cseg_init(txq, loc, loc->wqe_last, part + 2,
3901                                   MLX5_OPCODE_ENHANCED_MPSW, olx);
3902                 mlx5_tx_eseg_none(txq, loc, loc->wqe_last,
3903                                   olx & ~MLX5_TXOFF_CONFIG_VLAN);
3904                 eseg = &loc->wqe_last->eseg;
3905                 dseg = &loc->wqe_last->dseg[0];
3906                 loop = part;
3907                 /* Store the packet length for legacy MPW. */
3908                 if (MLX5_TXOFF_CONFIG(MPW))
3909                         eseg->mss = rte_cpu_to_be_16
3910                                         (rte_pktmbuf_data_len(loc->mbuf));
3911                 for (;;) {
3912                         uint32_t dlen = rte_pktmbuf_data_len(loc->mbuf);
3913 #ifdef MLX5_PMD_SOFT_COUNTERS
3914                         /* Update sent data bytes counter. */
3915                         slen += dlen;
3916 #endif
3917                         mlx5_tx_dseg_ptr
3918                                 (txq, loc, dseg,
3919                                  rte_pktmbuf_mtod(loc->mbuf, uint8_t *),
3920                                  dlen, olx);
3921                         if (unlikely(--loop == 0))
3922                                 break;
3923                         loc->mbuf = *pkts++;
3924                         if (likely(loop > 1))
3925                                 rte_prefetch0(*pkts);
3926                         ret = mlx5_tx_able_to_empw(txq, loc, olx, true);
3927                         /*
3928                          * Unroll the completion code to avoid
3929                          * returning variable value - it results in
3930                          * unoptimized sequent checking in caller.
3931                          */
3932                         if (ret == MLX5_TXCMP_CODE_MULTI) {
3933                                 part -= loop;
3934                                 mlx5_tx_sdone_empw(txq, loc, part, slen, olx);
3935                                 if (unlikely(!loc->elts_free ||
3936                                              !loc->wqe_free))
3937                                         return MLX5_TXCMP_CODE_EXIT;
3938                                 return MLX5_TXCMP_CODE_MULTI;
3939                         }
3940                         assert(NB_SEGS(loc->mbuf) == 1);
3941                         if (ret == MLX5_TXCMP_CODE_TSO) {
3942                                 part -= loop;
3943                                 mlx5_tx_sdone_empw(txq, loc, part, slen, olx);
3944                                 if (unlikely(!loc->elts_free ||
3945                                              !loc->wqe_free))
3946                                         return MLX5_TXCMP_CODE_EXIT;
3947                                 return MLX5_TXCMP_CODE_TSO;
3948                         }
3949                         if (ret == MLX5_TXCMP_CODE_SINGLE) {
3950                                 part -= loop;
3951                                 mlx5_tx_sdone_empw(txq, loc, part, slen, olx);
3952                                 if (unlikely(!loc->elts_free ||
3953                                              !loc->wqe_free))
3954                                         return MLX5_TXCMP_CODE_EXIT;
3955                                 return MLX5_TXCMP_CODE_SINGLE;
3956                         }
3957                         if (ret != MLX5_TXCMP_CODE_EMPW) {
3958                                 assert(false);
3959                                 part -= loop;
3960                                 mlx5_tx_sdone_empw(txq, loc, part, slen, olx);
3961                                 return MLX5_TXCMP_CODE_ERROR;
3962                         }
3963                         /*
3964                          * Check whether packet parameters coincide
3965                          * within assumed eMPW batch:
3966                          * - check sum settings
3967                          * - metadata value
3968                          * - software parser settings
3969                          * - packets length (legacy MPW only)
3970                          */
3971                         if (!mlx5_tx_match_empw(txq, eseg, loc, dlen, olx)) {
3972                                 assert(loop);
3973                                 part -= loop;
3974                                 mlx5_tx_sdone_empw(txq, loc, part, slen, olx);
3975                                 if (unlikely(!loc->elts_free ||
3976                                              !loc->wqe_free))
3977                                         return MLX5_TXCMP_CODE_EXIT;
3978                                 pkts_n -= part;
3979                                 goto next_empw;
3980                         }
3981                         /* Packet attributes match, continue the same eMPW. */
3982                         ++dseg;
3983                         if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end)
3984                                 dseg = (struct mlx5_wqe_dseg *)txq->wqes;
3985                 }
3986                 /* eMPW is built successfully, update loop parameters. */
3987                 assert(!loop);
3988                 assert(pkts_n >= part);
3989 #ifdef MLX5_PMD_SOFT_COUNTERS
3990                 /* Update sent data bytes counter. */
3991                 txq->stats.obytes += slen;
3992 #endif
3993                 loc->elts_free -= part;
3994                 loc->pkts_sent += part;
3995                 txq->wqe_ci += (2 + part + 3) / 4;
3996                 loc->wqe_free -= (2 + part + 3) / 4;
3997                 pkts_n -= part;
3998                 if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free))
3999                         return MLX5_TXCMP_CODE_EXIT;
4000                 loc->mbuf = *pkts++;
4001                 ret = mlx5_tx_able_to_empw(txq, loc, olx, true);
4002                 if (unlikely(ret != MLX5_TXCMP_CODE_EMPW))
4003                         return ret;
4004                 /* Continue sending eMPW batches. */
4005         }
4006         assert(false);
4007 }
4008
4009 /**
4010  * The routine sends packets with MLX5_OPCODE_EMPW
4011  * with inlining, optionally supports VLAN insertion.
4012  */
4013 static __rte_always_inline enum mlx5_txcmp_code
4014 mlx5_tx_burst_empw_inline(struct mlx5_txq_data *restrict txq,
4015                           struct rte_mbuf **restrict pkts,
4016                           unsigned int pkts_n,
4017                           struct mlx5_txq_local *restrict loc,
4018                           unsigned int olx)
4019 {
4020         /*
4021          * Subroutine is the part of mlx5_tx_burst_single()
4022          * and sends single-segment packet with eMPW opcode
4023          * with data inlining.
4024          */
4025         assert(MLX5_TXOFF_CONFIG(INLINE));
4026         assert(MLX5_TXOFF_CONFIG(EMPW));
4027         assert(loc->elts_free && loc->wqe_free);
4028         assert(pkts_n > loc->pkts_sent);
4029         static_assert(MLX5_EMPW_MIN_PACKETS >= 2, "invalid min size");
4030         pkts += loc->pkts_sent + 1;
4031         pkts_n -= loc->pkts_sent;
4032         for (;;) {
4033                 struct mlx5_wqe_dseg *restrict dseg;
4034                 struct mlx5_wqe_eseg *restrict eseg;
4035                 enum mlx5_txcmp_code ret;
4036                 unsigned int room, part, nlim;
4037                 unsigned int slen = 0;
4038
4039                 assert(NB_SEGS(loc->mbuf) == 1);
4040                 /*
4041                  * Limits the amount of packets in one WQE
4042                  * to improve CQE latency generation.
4043                  */
4044                 nlim = RTE_MIN(pkts_n, MLX5_TXOFF_CONFIG(MPW) ?
4045                                        MLX5_MPW_INLINE_MAX_PACKETS :
4046                                        MLX5_EMPW_MAX_PACKETS);
4047                 /* Check whether we have minimal amount WQEs */
4048                 if (unlikely(loc->wqe_free <
4049                             ((2 + MLX5_EMPW_MIN_PACKETS + 3) / 4)))
4050                         return MLX5_TXCMP_CODE_EXIT;
4051                 if (likely(pkts_n > 1))
4052                         rte_prefetch0(*pkts);
4053                 loc->wqe_last = txq->wqes + (txq->wqe_ci & txq->wqe_m);
4054                 /*
4055                  * Build eMPW title WQEBB:
4056                  * - Control Segment, eMPW opcode, zero DS
4057                  * - Ethernet Segment, no inline
4058                  */
4059                 mlx5_tx_cseg_init(txq, loc, loc->wqe_last, 0,
4060                                   MLX5_OPCODE_ENHANCED_MPSW, olx);
4061                 mlx5_tx_eseg_none(txq, loc, loc->wqe_last,
4062                                   olx & ~MLX5_TXOFF_CONFIG_VLAN);
4063                 eseg = &loc->wqe_last->eseg;
4064                 dseg = &loc->wqe_last->dseg[0];
4065                 /* Store the packet length for legacy MPW. */
4066                 if (MLX5_TXOFF_CONFIG(MPW))
4067                         eseg->mss = rte_cpu_to_be_16
4068                                         (rte_pktmbuf_data_len(loc->mbuf));
4069                 room = RTE_MIN(MLX5_WQE_SIZE_MAX / MLX5_WQE_SIZE,
4070                                loc->wqe_free) * MLX5_WQE_SIZE -
4071                                         MLX5_WQE_CSEG_SIZE -
4072                                         MLX5_WQE_ESEG_SIZE;
4073                 /* Build WQE till we have space, packets and resources. */
4074                 part = room;
4075                 for (;;) {
4076                         uint32_t dlen = rte_pktmbuf_data_len(loc->mbuf);
4077                         uint8_t *dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *);
4078                         unsigned int tlen;
4079
4080                         assert(room >= MLX5_WQE_DSEG_SIZE);
4081                         assert((room % MLX5_WQE_DSEG_SIZE) == 0);
4082                         assert((uintptr_t)dseg < (uintptr_t)txq->wqes_end);
4083                         /*
4084                          * Some Tx offloads may cause an error if
4085                          * packet is not long enough, check against
4086                          * assumed minimal length.
4087                          */
4088                         if (unlikely(dlen <= MLX5_ESEG_MIN_INLINE_SIZE)) {
4089                                 part -= room;
4090                                 if (unlikely(!part))
4091                                         return MLX5_TXCMP_CODE_ERROR;
4092                                 /*
4093                                  * We have some successfully built
4094                                  * packet Data Segments to send.
4095                                  */
4096                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4097                                 return MLX5_TXCMP_CODE_ERROR;
4098                         }
4099                         /* Inline or not inline - that's the Question. */
4100                         if (dlen > txq->inlen_empw)
4101                                 goto pointer_empw;
4102                         /* Inline entire packet, optional VLAN insertion. */
4103                         tlen = sizeof(dseg->bcount) + dlen;
4104                         if (MLX5_TXOFF_CONFIG(VLAN) &&
4105                             loc->mbuf->ol_flags & PKT_TX_VLAN_PKT) {
4106                                 /*
4107                                  * The packet length must be checked in
4108                                  * mlx5_tx_able_to_empw() and packet
4109                                  * fits into inline length guaranteed.
4110                                  */
4111                                 assert((dlen + sizeof(struct rte_vlan_hdr)) <=
4112                                         txq->inlen_empw);
4113                                 tlen += sizeof(struct rte_vlan_hdr);
4114                                 if (room < tlen)
4115                                         break;
4116                                 dseg = mlx5_tx_dseg_vlan(txq, loc, dseg,
4117                                                          dptr, dlen, olx);
4118 #ifdef MLX5_PMD_SOFT_COUNTERS
4119                                 /* Update sent data bytes counter. */
4120                                 slen += sizeof(struct rte_vlan_hdr);
4121 #endif
4122                         } else {
4123                                 if (room < tlen)
4124                                         break;
4125                                 dseg = mlx5_tx_dseg_empw(txq, loc, dseg,
4126                                                          dptr, dlen, olx);
4127                         }
4128                         tlen = RTE_ALIGN(tlen, MLX5_WSEG_SIZE);
4129                         assert(room >= tlen);
4130                         room -= tlen;
4131                         /*
4132                          * Packet data are completely inlined,
4133                          * free the packet immediately.
4134                          */
4135                         rte_pktmbuf_free_seg(loc->mbuf);
4136                         goto next_mbuf;
4137 pointer_empw:
4138                         /*
4139                          * Not inlinable VLAN packets are
4140                          * proceeded outside of this routine.
4141                          */
4142                         assert(room >= MLX5_WQE_DSEG_SIZE);
4143                         if (MLX5_TXOFF_CONFIG(VLAN))
4144                                 assert(!(loc->mbuf->ol_flags &
4145                                          PKT_TX_VLAN_PKT));
4146                         mlx5_tx_dseg_ptr(txq, loc, dseg, dptr, dlen, olx);
4147                         /* We have to store mbuf in elts.*/
4148                         txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
4149                         room -= MLX5_WQE_DSEG_SIZE;
4150                         /* Ring buffer wraparound is checked at the loop end.*/
4151                         ++dseg;
4152 next_mbuf:
4153 #ifdef MLX5_PMD_SOFT_COUNTERS
4154                         /* Update sent data bytes counter. */
4155                         slen += dlen;
4156 #endif
4157                         loc->pkts_sent++;
4158                         loc->elts_free--;
4159                         pkts_n--;
4160                         if (unlikely(!pkts_n || !loc->elts_free)) {
4161                                 /*
4162                                  * We have no resources/packets to
4163                                  * continue build descriptors.
4164                                  */
4165                                 part -= room;
4166                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4167                                 return MLX5_TXCMP_CODE_EXIT;
4168                         }
4169                         loc->mbuf = *pkts++;
4170                         if (likely(pkts_n > 1))
4171                                 rte_prefetch0(*pkts);
4172                         ret = mlx5_tx_able_to_empw(txq, loc, olx, true);
4173                         /*
4174                          * Unroll the completion code to avoid
4175                          * returning variable value - it results in
4176                          * unoptimized sequent checking in caller.
4177                          */
4178                         if (ret == MLX5_TXCMP_CODE_MULTI) {
4179                                 part -= room;
4180                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4181                                 if (unlikely(!loc->elts_free ||
4182                                              !loc->wqe_free))
4183                                         return MLX5_TXCMP_CODE_EXIT;
4184                                 return MLX5_TXCMP_CODE_MULTI;
4185                         }
4186                         assert(NB_SEGS(loc->mbuf) == 1);
4187                         if (ret == MLX5_TXCMP_CODE_TSO) {
4188                                 part -= room;
4189                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4190                                 if (unlikely(!loc->elts_free ||
4191                                              !loc->wqe_free))
4192                                         return MLX5_TXCMP_CODE_EXIT;
4193                                 return MLX5_TXCMP_CODE_TSO;
4194                         }
4195                         if (ret == MLX5_TXCMP_CODE_SINGLE) {
4196                                 part -= room;
4197                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4198                                 if (unlikely(!loc->elts_free ||
4199                                              !loc->wqe_free))
4200                                         return MLX5_TXCMP_CODE_EXIT;
4201                                 return MLX5_TXCMP_CODE_SINGLE;
4202                         }
4203                         if (ret != MLX5_TXCMP_CODE_EMPW) {
4204                                 assert(false);
4205                                 part -= room;
4206                                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4207                                 return MLX5_TXCMP_CODE_ERROR;
4208                         }
4209                         /* Check if we have minimal room left. */
4210                         nlim--;
4211                         if (unlikely(!nlim || room < MLX5_WQE_DSEG_SIZE))
4212                                 break;
4213                         /*
4214                          * Check whether packet parameters coincide
4215                          * within assumed eMPW batch:
4216                          * - check sum settings
4217                          * - metadata value
4218                          * - software parser settings
4219                          * - packets length (legacy MPW only)
4220                          */
4221                         if (!mlx5_tx_match_empw(txq, eseg, loc, dlen, olx))
4222                                 break;
4223                         /* Packet attributes match, continue the same eMPW. */
4224                         if ((uintptr_t)dseg >= (uintptr_t)txq->wqes_end)
4225                                 dseg = (struct mlx5_wqe_dseg *)txq->wqes;
4226                 }
4227                 /*
4228                  * We get here to close an existing eMPW
4229                  * session and start the new one.
4230                  */
4231                 assert(pkts_n);
4232                 part -= room;
4233                 if (unlikely(!part))
4234                         return MLX5_TXCMP_CODE_EXIT;
4235                 mlx5_tx_idone_empw(txq, loc, part, slen, olx);
4236                 if (unlikely(!loc->elts_free ||
4237                              !loc->wqe_free))
4238                         return MLX5_TXCMP_CODE_EXIT;
4239                 /* Continue the loop with new eMPW session. */
4240         }
4241         assert(false);
4242 }
4243
4244 /**
4245  * The routine sends packets with ordinary MLX5_OPCODE_SEND.
4246  * Data inlining and VLAN insertion are supported.
4247  */
4248 static __rte_always_inline enum mlx5_txcmp_code
4249 mlx5_tx_burst_single_send(struct mlx5_txq_data *restrict txq,
4250                           struct rte_mbuf **restrict pkts,
4251                           unsigned int pkts_n,
4252                           struct mlx5_txq_local *restrict loc,
4253                           unsigned int olx)
4254 {
4255         /*
4256          * Subroutine is the part of mlx5_tx_burst_single()
4257          * and sends single-segment packet with SEND opcode.
4258          */
4259         assert(loc->elts_free && loc->wqe_free);
4260         assert(pkts_n > loc->pkts_sent);
4261         pkts += loc->pkts_sent + 1;
4262         pkts_n -= loc->pkts_sent;
4263         for (;;) {
4264                 struct mlx5_wqe *restrict wqe;
4265                 enum mlx5_txcmp_code ret;
4266
4267                 assert(NB_SEGS(loc->mbuf) == 1);
4268                 if (MLX5_TXOFF_CONFIG(INLINE)) {
4269                         unsigned int inlen, vlan = 0;
4270
4271                         inlen = rte_pktmbuf_data_len(loc->mbuf);
4272                         if (MLX5_TXOFF_CONFIG(VLAN) &&
4273                             loc->mbuf->ol_flags & PKT_TX_VLAN_PKT) {
4274                                 vlan = sizeof(struct rte_vlan_hdr);
4275                                 inlen += vlan;
4276                                 static_assert((sizeof(struct rte_vlan_hdr) +
4277                                                sizeof(struct rte_ether_hdr)) ==
4278                                                MLX5_ESEG_MIN_INLINE_SIZE,
4279                                                "invalid min inline data size");
4280                         }
4281                         /*
4282                          * If inlining is enabled at configuration time
4283                          * the limit must be not less than minimal size.
4284                          * Otherwise we would do extra check for data
4285                          * size to avoid crashes due to length overflow.
4286                          */
4287                         assert(txq->inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE);
4288                         if (inlen <= txq->inlen_send) {
4289                                 unsigned int seg_n, wqe_n;
4290
4291                                 rte_prefetch0(rte_pktmbuf_mtod
4292                                                 (loc->mbuf, uint8_t *));
4293                                 /* Check against minimal length. */
4294                                 if (inlen <= MLX5_ESEG_MIN_INLINE_SIZE)
4295                                         return MLX5_TXCMP_CODE_ERROR;
4296                                 /*
4297                                  * Completely inlined packet data WQE:
4298                                  * - Control Segment, SEND opcode
4299                                  * - Ethernet Segment, no VLAN insertion
4300                                  * - Data inlined, VLAN optionally inserted
4301                                  * - Alignment to MLX5_WSEG_SIZE
4302                                  * Have to estimate amount of WQEBBs
4303                                  */
4304                                 seg_n = (inlen + 3 * MLX5_WSEG_SIZE -
4305                                          MLX5_ESEG_MIN_INLINE_SIZE +
4306                                          MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE;
4307                                 /* Check if there are enough WQEBBs. */
4308                                 wqe_n = (seg_n + 3) / 4;
4309                                 if (wqe_n > loc->wqe_free)
4310                                         return MLX5_TXCMP_CODE_EXIT;
4311                                 wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
4312                                 loc->wqe_last = wqe;
4313                                 mlx5_tx_cseg_init(txq, loc, wqe, seg_n,
4314                                                   MLX5_OPCODE_SEND, olx);
4315                                 mlx5_tx_eseg_data(txq, loc, wqe,
4316                                                   vlan, inlen, 0, olx);
4317                                 txq->wqe_ci += wqe_n;
4318                                 loc->wqe_free -= wqe_n;
4319                                 /*
4320                                  * Packet data are completely inlined,
4321                                  * free the packet immediately.
4322                                  */
4323                                 rte_pktmbuf_free_seg(loc->mbuf);
4324                         } else if ((!MLX5_TXOFF_CONFIG(EMPW) ||
4325                                      MLX5_TXOFF_CONFIG(MPW)) &&
4326                                         txq->inlen_mode) {
4327                                 /*
4328                                  * If minimal inlining is requested the eMPW
4329                                  * feature should be disabled due to data is
4330                                  * inlined into Ethernet Segment, which can
4331                                  * not contain inlined data for eMPW due to
4332                                  * segment shared for all packets.
4333                                  */
4334                                 struct mlx5_wqe_dseg *restrict dseg;
4335                                 unsigned int ds;
4336                                 uint8_t *dptr;
4337
4338                                 /*
4339                                  * The inline-mode settings require
4340                                  * to inline the specified amount of
4341                                  * data bytes to the Ethernet Segment.
4342                                  * We should check the free space in
4343                                  * WQE ring buffer to inline partially.
4344                                  */
4345                                 assert(txq->inlen_send >= txq->inlen_mode);
4346                                 assert(inlen > txq->inlen_mode);
4347                                 assert(txq->inlen_mode >=
4348                                                 MLX5_ESEG_MIN_INLINE_SIZE);
4349                                 /*
4350                                  * Check whether there are enough free WQEBBs:
4351                                  * - Control Segment
4352                                  * - Ethernet Segment
4353                                  * - First Segment of inlined Ethernet data
4354                                  * - ... data continued ...
4355                                  * - Finishing Data Segment of pointer type
4356                                  */
4357                                 ds = (MLX5_WQE_CSEG_SIZE +
4358                                       MLX5_WQE_ESEG_SIZE +
4359                                       MLX5_WQE_DSEG_SIZE +
4360                                       txq->inlen_mode -
4361                                       MLX5_ESEG_MIN_INLINE_SIZE +
4362                                       MLX5_WQE_DSEG_SIZE +
4363                                       MLX5_WSEG_SIZE - 1) / MLX5_WSEG_SIZE;
4364                                 if (loc->wqe_free < ((ds + 3) / 4))
4365                                         return MLX5_TXCMP_CODE_EXIT;
4366                                 /*
4367                                  * Build the ordinary SEND WQE:
4368                                  * - Control Segment
4369                                  * - Ethernet Segment, inline inlen_mode bytes
4370                                  * - Data Segment of pointer type
4371                                  */
4372                                 wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
4373                                 loc->wqe_last = wqe;
4374                                 mlx5_tx_cseg_init(txq, loc, wqe, ds,
4375                                                   MLX5_OPCODE_SEND, olx);
4376                                 dseg = mlx5_tx_eseg_data(txq, loc, wqe, vlan,
4377                                                          txq->inlen_mode,
4378                                                          0, olx);
4379                                 dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) +
4380                                        txq->inlen_mode - vlan;
4381                                 inlen -= txq->inlen_mode;
4382                                 mlx5_tx_dseg_ptr(txq, loc, dseg,
4383                                                  dptr, inlen, olx);
4384                                 /*
4385                                  * WQE is built, update the loop parameters
4386                                  * and got to the next packet.
4387                                  */
4388                                 txq->wqe_ci += (ds + 3) / 4;
4389                                 loc->wqe_free -= (ds + 3) / 4;
4390                                 /* We have to store mbuf in elts.*/
4391                                 assert(MLX5_TXOFF_CONFIG(INLINE));
4392                                 txq->elts[txq->elts_head++ & txq->elts_m] =
4393                                                 loc->mbuf;
4394                                 --loc->elts_free;
4395                         } else {
4396                                 uint8_t *dptr;
4397                                 unsigned int dlen;
4398
4399                                 /*
4400                                  * Partially inlined packet data WQE, we have
4401                                  * some space in title WQEBB, we can fill it
4402                                  * with some packet data. It takes one WQEBB,
4403                                  * it is available, no extra space check:
4404                                  * - Control Segment, SEND opcode
4405                                  * - Ethernet Segment, no VLAN insertion
4406                                  * - MLX5_ESEG_MIN_INLINE_SIZE bytes of Data
4407                                  * - Data Segment, pointer type
4408                                  *
4409                                  * We also get here if VLAN insertion is not
4410                                  * supported by HW, the inline is enabled.
4411                                  */
4412                                 wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
4413                                 loc->wqe_last = wqe;
4414                                 mlx5_tx_cseg_init(txq, loc, wqe, 4,
4415                                                   MLX5_OPCODE_SEND, olx);
4416                                 mlx5_tx_eseg_dmin(txq, loc, wqe, vlan, olx);
4417                                 dptr = rte_pktmbuf_mtod(loc->mbuf, uint8_t *) +
4418                                        MLX5_ESEG_MIN_INLINE_SIZE - vlan;
4419                                 /*
4420                                  * The length check is performed above, by
4421                                  * comparing with txq->inlen_send. We should
4422                                  * not get overflow here.
4423                                  */
4424                                 assert(inlen > MLX5_ESEG_MIN_INLINE_SIZE);
4425                                 dlen = inlen - MLX5_ESEG_MIN_INLINE_SIZE;
4426                                 mlx5_tx_dseg_ptr(txq, loc, &wqe->dseg[1],
4427                                                  dptr, dlen, olx);
4428                                 ++txq->wqe_ci;
4429                                 --loc->wqe_free;
4430                                 /* We have to store mbuf in elts.*/
4431                                 assert(MLX5_TXOFF_CONFIG(INLINE));
4432                                 txq->elts[txq->elts_head++ & txq->elts_m] =
4433                                                 loc->mbuf;
4434                                 --loc->elts_free;
4435                         }
4436 #ifdef MLX5_PMD_SOFT_COUNTERS
4437                         /* Update sent data bytes counter. */
4438                         txq->stats.obytes += vlan +
4439                                         rte_pktmbuf_data_len(loc->mbuf);
4440 #endif
4441                 } else {
4442                         /*
4443                          * No inline at all, it means the CPU cycles saving
4444                          * is prioritized at configuration, we should not
4445                          * copy any packet data to WQE.
4446                          *
4447                          * SEND WQE, one WQEBB:
4448                          * - Control Segment, SEND opcode
4449                          * - Ethernet Segment, optional VLAN, no inline
4450                          * - Data Segment, pointer type
4451                          */
4452                         wqe = txq->wqes + (txq->wqe_ci & txq->wqe_m);
4453                         loc->wqe_last = wqe;
4454                         mlx5_tx_cseg_init(txq, loc, wqe, 3,
4455                                           MLX5_OPCODE_SEND, olx);
4456                         mlx5_tx_eseg_none(txq, loc, wqe, olx);
4457                         mlx5_tx_dseg_ptr
4458                                 (txq, loc, &wqe->dseg[0],
4459                                  rte_pktmbuf_mtod(loc->mbuf, uint8_t *),
4460                                  rte_pktmbuf_data_len(loc->mbuf), olx);
4461                         ++txq->wqe_ci;
4462                         --loc->wqe_free;
4463                         /*
4464                          * We should not store mbuf pointer in elts
4465                          * if no inlining is configured, this is done
4466                          * by calling routine in a batch copy.
4467                          */
4468                         assert(!MLX5_TXOFF_CONFIG(INLINE));
4469                         --loc->elts_free;
4470 #ifdef MLX5_PMD_SOFT_COUNTERS
4471                         /* Update sent data bytes counter. */
4472                         txq->stats.obytes += rte_pktmbuf_data_len(loc->mbuf);
4473                         if (MLX5_TXOFF_CONFIG(VLAN) &&
4474                             loc->mbuf->ol_flags & PKT_TX_VLAN_PKT)
4475                                 txq->stats.obytes +=
4476                                         sizeof(struct rte_vlan_hdr);
4477 #endif
4478                 }
4479                 ++loc->pkts_sent;
4480                 --pkts_n;
4481                 if (unlikely(!pkts_n || !loc->elts_free || !loc->wqe_free))
4482                         return MLX5_TXCMP_CODE_EXIT;
4483                 loc->mbuf = *pkts++;
4484                 if (pkts_n > 1)
4485                         rte_prefetch0(*pkts);
4486                 ret = mlx5_tx_able_to_empw(txq, loc, olx, true);
4487                 if (unlikely(ret != MLX5_TXCMP_CODE_SINGLE))
4488                         return ret;
4489         }
4490         assert(false);
4491 }
4492
4493 static __rte_always_inline enum mlx5_txcmp_code
4494 mlx5_tx_burst_single(struct mlx5_txq_data *restrict txq,
4495                      struct rte_mbuf **restrict pkts,
4496                      unsigned int pkts_n,
4497                      struct mlx5_txq_local *restrict loc,
4498                      unsigned int olx)
4499 {
4500         enum mlx5_txcmp_code ret;
4501
4502         ret = mlx5_tx_able_to_empw(txq, loc, olx, false);
4503         if (ret == MLX5_TXCMP_CODE_SINGLE)
4504                 goto ordinary_send;
4505         assert(ret == MLX5_TXCMP_CODE_EMPW);
4506         for (;;) {
4507                 /* Optimize for inline/no inline eMPW send. */
4508                 ret = (MLX5_TXOFF_CONFIG(INLINE)) ?
4509                         mlx5_tx_burst_empw_inline
4510                                 (txq, pkts, pkts_n, loc, olx) :
4511                         mlx5_tx_burst_empw_simple
4512                                 (txq, pkts, pkts_n, loc, olx);
4513                 if (ret != MLX5_TXCMP_CODE_SINGLE)
4514                         return ret;
4515                 /* The resources to send one packet should remain. */
4516                 assert(loc->elts_free && loc->wqe_free);
4517 ordinary_send:
4518                 ret = mlx5_tx_burst_single_send(txq, pkts, pkts_n, loc, olx);
4519                 assert(ret != MLX5_TXCMP_CODE_SINGLE);
4520                 if (ret != MLX5_TXCMP_CODE_EMPW)
4521                         return ret;
4522                 /* The resources to send one packet should remain. */
4523                 assert(loc->elts_free && loc->wqe_free);
4524         }
4525 }
4526
4527 /**
4528  * DPDK Tx callback template. This is configured template
4529  * used to generate routines optimized for specified offload setup.
4530  * One of this generated functions is chosen at SQ configuration
4531  * time.
4532  *
4533  * @param txq
4534  *   Generic pointer to TX queue structure.
4535  * @param[in] pkts
4536  *   Packets to transmit.
4537  * @param pkts_n
4538  *   Number of packets in array.
4539  * @param olx
4540  *   Configured offloads mask, presents the bits of MLX5_TXOFF_CONFIG_xxx
4541  *   values. Should be static to take compile time static configuration
4542  *   advantages.
4543  *
4544  * @return
4545  *   Number of packets successfully transmitted (<= pkts_n).
4546  */
4547 static __rte_always_inline uint16_t
4548 mlx5_tx_burst_tmpl(struct mlx5_txq_data *restrict txq,
4549                    struct rte_mbuf **restrict pkts,
4550                    uint16_t pkts_n,
4551                    unsigned int olx)
4552 {
4553         struct mlx5_txq_local loc;
4554         enum mlx5_txcmp_code ret;
4555         unsigned int part;
4556
4557         assert(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail));
4558         assert(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi));
4559         if (unlikely(!pkts_n))
4560                 return 0;
4561         loc.pkts_sent = 0;
4562         loc.pkts_copy = 0;
4563         loc.wqe_last = NULL;
4564
4565 send_loop:
4566         loc.pkts_loop = loc.pkts_sent;
4567         /*
4568          * Check if there are some CQEs, if any:
4569          * - process an encountered errors
4570          * - process the completed WQEs
4571          * - free related mbufs
4572          * - doorbell the NIC about processed CQEs
4573          */
4574         rte_prefetch0(*(pkts + loc.pkts_sent));
4575         mlx5_tx_handle_completion(txq, olx);
4576         /*
4577          * Calculate the number of available resources - elts and WQEs.
4578          * There are two possible different scenarios:
4579          * - no data inlining into WQEs, one WQEBB may contains upto
4580          *   four packets, in this case elts become scarce resource
4581          * - data inlining into WQEs, one packet may require multiple
4582          *   WQEBBs, the WQEs become the limiting factor.
4583          */
4584         assert(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail));
4585         loc.elts_free = txq->elts_s -
4586                                 (uint16_t)(txq->elts_head - txq->elts_tail);
4587         assert(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi));
4588         loc.wqe_free = txq->wqe_s -
4589                                 (uint16_t)(txq->wqe_ci - txq->wqe_pi);
4590         if (unlikely(!loc.elts_free || !loc.wqe_free))
4591                 goto burst_exit;
4592         for (;;) {
4593                 /*
4594                  * Fetch the packet from array. Usually this is
4595                  * the first packet in series of multi/single
4596                  * segment packets.
4597                  */
4598                 loc.mbuf = *(pkts + loc.pkts_sent);
4599                 /* Dedicated branch for multi-segment packets. */
4600                 if (MLX5_TXOFF_CONFIG(MULTI) &&
4601                     unlikely(NB_SEGS(loc.mbuf) > 1)) {
4602                         /*
4603                          * Multi-segment packet encountered.
4604                          * Hardware is able to process it only
4605                          * with SEND/TSO opcodes, one packet
4606                          * per WQE, do it in dedicated routine.
4607                          */
4608 enter_send_multi:
4609                         assert(loc.pkts_sent >= loc.pkts_copy);
4610                         part = loc.pkts_sent - loc.pkts_copy;
4611                         if (!MLX5_TXOFF_CONFIG(INLINE) && part) {
4612                                 /*
4613                                  * There are some single-segment mbufs not
4614                                  * stored in elts. The mbufs must be in the
4615                                  * same order as WQEs, so we must copy the
4616                                  * mbufs to elts here, before the coming
4617                                  * multi-segment packet mbufs is appended.
4618                                  */
4619                                 mlx5_tx_copy_elts(txq, pkts + loc.pkts_copy,
4620                                                   part, olx);
4621                                 loc.pkts_copy = loc.pkts_sent;
4622                         }
4623                         assert(pkts_n > loc.pkts_sent);
4624                         ret = mlx5_tx_burst_mseg(txq, pkts, pkts_n, &loc, olx);
4625                         if (!MLX5_TXOFF_CONFIG(INLINE))
4626                                 loc.pkts_copy = loc.pkts_sent;
4627                         /*
4628                          * These returned code checks are supposed
4629                          * to be optimized out due to routine inlining.
4630                          */
4631                         if (ret == MLX5_TXCMP_CODE_EXIT) {
4632                                 /*
4633                                  * The routine returns this code when
4634                                  * all packets are sent or there is no
4635                                  * enough resources to complete request.
4636                                  */
4637                                 break;
4638                         }
4639                         if (ret == MLX5_TXCMP_CODE_ERROR) {
4640                                 /*
4641                                  * The routine returns this code when
4642                                  * some error in the incoming packets
4643                                  * format occurred.
4644                                  */
4645                                 txq->stats.oerrors++;
4646                                 break;
4647                         }
4648                         if (ret == MLX5_TXCMP_CODE_SINGLE) {
4649                                 /*
4650                                  * The single-segment packet was encountered
4651                                  * in the array, try to send it with the
4652                                  * best optimized way, possible engaging eMPW.
4653                                  */
4654                                 goto enter_send_single;
4655                         }
4656                         if (MLX5_TXOFF_CONFIG(TSO) &&
4657                             ret == MLX5_TXCMP_CODE_TSO) {
4658                                 /*
4659                                  * The single-segment TSO packet was
4660                                  * encountered in the array.
4661                                  */
4662                                 goto enter_send_tso;
4663                         }
4664                         /* We must not get here. Something is going wrong. */
4665                         assert(false);
4666                         txq->stats.oerrors++;
4667                         break;
4668                 }
4669                 /* Dedicated branch for single-segment TSO packets. */
4670                 if (MLX5_TXOFF_CONFIG(TSO) &&
4671                     unlikely(loc.mbuf->ol_flags & PKT_TX_TCP_SEG)) {
4672                         /*
4673                          * TSO might require special way for inlining
4674                          * (dedicated parameters) and is sent with
4675                          * MLX5_OPCODE_TSO opcode only, provide this
4676                          * in dedicated branch.
4677                          */
4678 enter_send_tso:
4679                         assert(NB_SEGS(loc.mbuf) == 1);
4680                         assert(pkts_n > loc.pkts_sent);
4681                         ret = mlx5_tx_burst_tso(txq, pkts, pkts_n, &loc, olx);
4682                         /*
4683                          * These returned code checks are supposed
4684                          * to be optimized out due to routine inlining.
4685                          */
4686                         if (ret == MLX5_TXCMP_CODE_EXIT)
4687                                 break;
4688                         if (ret == MLX5_TXCMP_CODE_ERROR) {
4689                                 txq->stats.oerrors++;
4690                                 break;
4691                         }
4692                         if (ret == MLX5_TXCMP_CODE_SINGLE)
4693                                 goto enter_send_single;
4694                         if (MLX5_TXOFF_CONFIG(MULTI) &&
4695                             ret == MLX5_TXCMP_CODE_MULTI) {
4696                                 /*
4697                                  * The multi-segment packet was
4698                                  * encountered in the array.
4699                                  */
4700                                 goto enter_send_multi;
4701                         }
4702                         /* We must not get here. Something is going wrong. */
4703                         assert(false);
4704                         txq->stats.oerrors++;
4705                         break;
4706                 }
4707                 /*
4708                  * The dedicated branch for the single-segment packets
4709                  * without TSO. Often these ones can be sent using
4710                  * MLX5_OPCODE_EMPW with multiple packets in one WQE.
4711                  * The routine builds the WQEs till it encounters
4712                  * the TSO or multi-segment packet (in case if these
4713                  * offloads are requested at SQ configuration time).
4714                  */
4715 enter_send_single:
4716                 assert(pkts_n > loc.pkts_sent);
4717                 ret = mlx5_tx_burst_single(txq, pkts, pkts_n, &loc, olx);
4718                 /*
4719                  * These returned code checks are supposed
4720                  * to be optimized out due to routine inlining.
4721                  */
4722                 if (ret == MLX5_TXCMP_CODE_EXIT)
4723                         break;
4724                 if (ret == MLX5_TXCMP_CODE_ERROR) {
4725                         txq->stats.oerrors++;
4726                         break;
4727                 }
4728                 if (MLX5_TXOFF_CONFIG(MULTI) &&
4729                     ret == MLX5_TXCMP_CODE_MULTI) {
4730                         /*
4731                          * The multi-segment packet was
4732                          * encountered in the array.
4733                          */
4734                         goto enter_send_multi;
4735                 }
4736                 if (MLX5_TXOFF_CONFIG(TSO) &&
4737                     ret == MLX5_TXCMP_CODE_TSO) {
4738                         /*
4739                          * The single-segment TSO packet was
4740                          * encountered in the array.
4741                          */
4742                         goto enter_send_tso;
4743                 }
4744                 /* We must not get here. Something is going wrong. */
4745                 assert(false);
4746                 txq->stats.oerrors++;
4747                 break;
4748         }
4749         /*
4750          * Main Tx loop is completed, do the rest:
4751          * - set completion request if thresholds are reached
4752          * - doorbell the hardware
4753          * - copy the rest of mbufs to elts (if any)
4754          */
4755         assert(MLX5_TXOFF_CONFIG(INLINE) || loc.pkts_sent >= loc.pkts_copy);
4756         /* Take a shortcut if nothing is sent. */
4757         if (unlikely(loc.pkts_sent == loc.pkts_loop))
4758                 goto burst_exit;
4759         /* Request CQE generation if limits are reached. */
4760         mlx5_tx_request_completion(txq, &loc, olx);
4761         /*
4762          * Ring QP doorbell immediately after WQE building completion
4763          * to improve latencies. The pure software related data treatment
4764          * can be completed after doorbell. Tx CQEs for this SQ are
4765          * processed in this thread only by the polling.
4766          *
4767          * The rdma core library can map doorbell register in two ways,
4768          * depending on the environment variable "MLX5_SHUT_UP_BF":
4769          *
4770          * - as regular cached memory, the variable is either missing or
4771          *   set to zero. This type of mapping may cause the significant
4772          *   doorbell register writing latency and requires explicit
4773          *   memory write barrier to mitigate this issue and prevent
4774          *   write combining.
4775          *
4776          * - as non-cached memory, the variable is present and set to
4777          *   not "0" value. This type of mapping may cause performance
4778          *   impact under heavy loading conditions but the explicit write
4779          *   memory barrier is not required and it may improve core
4780          *   performance.
4781          *
4782          * - the legacy behaviour (prior 19.08 release) was to use some
4783          *   heuristics to decide whether write memory barrier should
4784          *   be performed. This behavior is supported with specifying
4785          *   tx_db_nc=2, write barrier is skipped if application
4786          *   provides the full recommended burst of packets, it
4787          *   supposes the next packets are coming and the write barrier
4788          *   will be issued on the next burst (after descriptor writing,
4789          *   at least).
4790          */
4791         mlx5_tx_dbrec_cond_wmb(txq, loc.wqe_last, !txq->db_nc &&
4792                         (!txq->db_heu || pkts_n % MLX5_TX_DEFAULT_BURST));
4793         /* Not all of the mbufs may be stored into elts yet. */
4794         part = MLX5_TXOFF_CONFIG(INLINE) ? 0 : loc.pkts_sent - loc.pkts_copy;
4795         if (!MLX5_TXOFF_CONFIG(INLINE) && part) {
4796                 /*
4797                  * There are some single-segment mbufs not stored in elts.
4798                  * It can be only if the last packet was single-segment.
4799                  * The copying is gathered into one place due to it is
4800                  * a good opportunity to optimize that with SIMD.
4801                  * Unfortunately if inlining is enabled the gaps in
4802                  * pointer array may happen due to early freeing of the
4803                  * inlined mbufs.
4804                  */
4805                 mlx5_tx_copy_elts(txq, pkts + loc.pkts_copy, part, olx);
4806                 loc.pkts_copy = loc.pkts_sent;
4807         }
4808         assert(txq->elts_s >= (uint16_t)(txq->elts_head - txq->elts_tail));
4809         assert(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi));
4810         if (pkts_n > loc.pkts_sent) {
4811                 /*
4812                  * If burst size is large there might be no enough CQE
4813                  * fetched from completion queue and no enough resources
4814                  * freed to send all the packets.
4815                  */
4816                 goto send_loop;
4817         }
4818 burst_exit:
4819 #ifdef MLX5_PMD_SOFT_COUNTERS
4820         /* Increment sent packets counter. */
4821         txq->stats.opackets += loc.pkts_sent;
4822 #endif
4823         return loc.pkts_sent;
4824 }
4825
4826 /* Generate routines with Enhanced Multi-Packet Write support. */
4827 MLX5_TXOFF_DECL(full_empw,
4828                 MLX5_TXOFF_CONFIG_FULL | MLX5_TXOFF_CONFIG_EMPW)
4829
4830 MLX5_TXOFF_DECL(none_empw,
4831                 MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW)
4832
4833 MLX5_TXOFF_DECL(md_empw,
4834                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4835
4836 MLX5_TXOFF_DECL(mt_empw,
4837                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4838                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4839
4840 MLX5_TXOFF_DECL(mtsc_empw,
4841                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4842                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4843                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4844
4845 MLX5_TXOFF_DECL(mti_empw,
4846                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4847                 MLX5_TXOFF_CONFIG_INLINE |
4848                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4849
4850 MLX5_TXOFF_DECL(mtv_empw,
4851                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4852                 MLX5_TXOFF_CONFIG_VLAN |
4853                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4854
4855 MLX5_TXOFF_DECL(mtiv_empw,
4856                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4857                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4858                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4859
4860 MLX5_TXOFF_DECL(sc_empw,
4861                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4862                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4863
4864 MLX5_TXOFF_DECL(sci_empw,
4865                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4866                 MLX5_TXOFF_CONFIG_INLINE |
4867                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4868
4869 MLX5_TXOFF_DECL(scv_empw,
4870                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4871                 MLX5_TXOFF_CONFIG_VLAN |
4872                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4873
4874 MLX5_TXOFF_DECL(sciv_empw,
4875                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4876                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4877                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4878
4879 MLX5_TXOFF_DECL(i_empw,
4880                 MLX5_TXOFF_CONFIG_INLINE |
4881                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4882
4883 MLX5_TXOFF_DECL(v_empw,
4884                 MLX5_TXOFF_CONFIG_VLAN |
4885                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4886
4887 MLX5_TXOFF_DECL(iv_empw,
4888                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4889                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
4890
4891 /* Generate routines without Enhanced Multi-Packet Write support. */
4892 MLX5_TXOFF_DECL(full,
4893                 MLX5_TXOFF_CONFIG_FULL)
4894
4895 MLX5_TXOFF_DECL(none,
4896                 MLX5_TXOFF_CONFIG_NONE)
4897
4898 MLX5_TXOFF_DECL(md,
4899                 MLX5_TXOFF_CONFIG_METADATA)
4900
4901 MLX5_TXOFF_DECL(mt,
4902                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4903                 MLX5_TXOFF_CONFIG_METADATA)
4904
4905 MLX5_TXOFF_DECL(mtsc,
4906                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4907                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4908                 MLX5_TXOFF_CONFIG_METADATA)
4909
4910 MLX5_TXOFF_DECL(mti,
4911                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4912                 MLX5_TXOFF_CONFIG_INLINE |
4913                 MLX5_TXOFF_CONFIG_METADATA)
4914
4915
4916 MLX5_TXOFF_DECL(mtv,
4917                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4918                 MLX5_TXOFF_CONFIG_VLAN |
4919                 MLX5_TXOFF_CONFIG_METADATA)
4920
4921
4922 MLX5_TXOFF_DECL(mtiv,
4923                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4924                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4925                 MLX5_TXOFF_CONFIG_METADATA)
4926
4927 MLX5_TXOFF_DECL(sc,
4928                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4929                 MLX5_TXOFF_CONFIG_METADATA)
4930
4931 MLX5_TXOFF_DECL(sci,
4932                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4933                 MLX5_TXOFF_CONFIG_INLINE |
4934                 MLX5_TXOFF_CONFIG_METADATA)
4935
4936
4937 MLX5_TXOFF_DECL(scv,
4938                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4939                 MLX5_TXOFF_CONFIG_VLAN |
4940                 MLX5_TXOFF_CONFIG_METADATA)
4941
4942
4943 MLX5_TXOFF_DECL(sciv,
4944                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
4945                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4946                 MLX5_TXOFF_CONFIG_METADATA)
4947
4948 MLX5_TXOFF_DECL(i,
4949                 MLX5_TXOFF_CONFIG_INLINE |
4950                 MLX5_TXOFF_CONFIG_METADATA)
4951
4952 MLX5_TXOFF_DECL(v,
4953                 MLX5_TXOFF_CONFIG_VLAN |
4954                 MLX5_TXOFF_CONFIG_METADATA)
4955
4956 MLX5_TXOFF_DECL(iv,
4957                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
4958                 MLX5_TXOFF_CONFIG_METADATA)
4959
4960 /*
4961  * Generate routines with Legacy Multi-Packet Write support.
4962  * This mode is supported by ConnectX-4LX only and imposes
4963  * offload limitations, not supported:
4964  *   - ACL/Flows (metadata are becoming meaningless)
4965  *   - WQE Inline headers
4966  *   - SRIOV (E-Switch offloads)
4967  *   - VLAN insertion
4968  *   - tunnel encapsulation/decapsulation
4969  *   - TSO
4970  */
4971 MLX5_TXOFF_DECL(none_mpw,
4972                 MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW |
4973                 MLX5_TXOFF_CONFIG_MPW)
4974
4975 MLX5_TXOFF_DECL(mci_mpw,
4976                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
4977                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
4978                 MLX5_TXOFF_CONFIG_MPW)
4979
4980 MLX5_TXOFF_DECL(mc_mpw,
4981                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
4982                 MLX5_TXOFF_CONFIG_EMPW | MLX5_TXOFF_CONFIG_MPW)
4983
4984 MLX5_TXOFF_DECL(i_mpw,
4985                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
4986                 MLX5_TXOFF_CONFIG_MPW)
4987
4988 /*
4989  * Array of declared and compiled Tx burst function and corresponding
4990  * supported offloads set. The array is used to select the Tx burst
4991  * function for specified offloads set at Tx queue configuration time.
4992  */
4993 const struct {
4994         eth_tx_burst_t func;
4995         unsigned int olx;
4996 } txoff_func[] = {
4997 MLX5_TXOFF_INFO(full_empw,
4998                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
4999                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5000                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5001                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5002
5003 MLX5_TXOFF_INFO(none_empw,
5004                 MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW)
5005
5006 MLX5_TXOFF_INFO(md_empw,
5007                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5008
5009 MLX5_TXOFF_INFO(mt_empw,
5010                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5011                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5012
5013 MLX5_TXOFF_INFO(mtsc_empw,
5014                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5015                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5016                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5017
5018 MLX5_TXOFF_INFO(mti_empw,
5019                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5020                 MLX5_TXOFF_CONFIG_INLINE |
5021                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5022
5023 MLX5_TXOFF_INFO(mtv_empw,
5024                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5025                 MLX5_TXOFF_CONFIG_VLAN |
5026                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5027
5028 MLX5_TXOFF_INFO(mtiv_empw,
5029                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5030                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5031                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5032
5033 MLX5_TXOFF_INFO(sc_empw,
5034                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5035                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5036
5037 MLX5_TXOFF_INFO(sci_empw,
5038                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5039                 MLX5_TXOFF_CONFIG_INLINE |
5040                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5041
5042 MLX5_TXOFF_INFO(scv_empw,
5043                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5044                 MLX5_TXOFF_CONFIG_VLAN |
5045                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5046
5047 MLX5_TXOFF_INFO(sciv_empw,
5048                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5049                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5050                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5051
5052 MLX5_TXOFF_INFO(i_empw,
5053                 MLX5_TXOFF_CONFIG_INLINE |
5054                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5055
5056 MLX5_TXOFF_INFO(v_empw,
5057                 MLX5_TXOFF_CONFIG_VLAN |
5058                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5059
5060 MLX5_TXOFF_INFO(iv_empw,
5061                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5062                 MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
5063
5064 MLX5_TXOFF_INFO(full,
5065                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5066                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5067                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5068                 MLX5_TXOFF_CONFIG_METADATA)
5069
5070 MLX5_TXOFF_INFO(none,
5071                 MLX5_TXOFF_CONFIG_NONE)
5072
5073 MLX5_TXOFF_INFO(md,
5074                 MLX5_TXOFF_CONFIG_METADATA)
5075
5076 MLX5_TXOFF_INFO(mt,
5077                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5078                 MLX5_TXOFF_CONFIG_METADATA)
5079
5080 MLX5_TXOFF_INFO(mtsc,
5081                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5082                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5083                 MLX5_TXOFF_CONFIG_METADATA)
5084
5085 MLX5_TXOFF_INFO(mti,
5086                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5087                 MLX5_TXOFF_CONFIG_INLINE |
5088                 MLX5_TXOFF_CONFIG_METADATA)
5089
5090 MLX5_TXOFF_INFO(mtv,
5091                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5092                 MLX5_TXOFF_CONFIG_VLAN |
5093                 MLX5_TXOFF_CONFIG_METADATA)
5094
5095 MLX5_TXOFF_INFO(mtiv,
5096                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
5097                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5098                 MLX5_TXOFF_CONFIG_METADATA)
5099
5100 MLX5_TXOFF_INFO(sc,
5101                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5102                 MLX5_TXOFF_CONFIG_METADATA)
5103
5104 MLX5_TXOFF_INFO(sci,
5105                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5106                 MLX5_TXOFF_CONFIG_INLINE |
5107                 MLX5_TXOFF_CONFIG_METADATA)
5108
5109 MLX5_TXOFF_INFO(scv,
5110                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5111                 MLX5_TXOFF_CONFIG_VLAN |
5112                 MLX5_TXOFF_CONFIG_METADATA)
5113
5114 MLX5_TXOFF_INFO(sciv,
5115                 MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
5116                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5117                 MLX5_TXOFF_CONFIG_METADATA)
5118
5119 MLX5_TXOFF_INFO(i,
5120                 MLX5_TXOFF_CONFIG_INLINE |
5121                 MLX5_TXOFF_CONFIG_METADATA)
5122
5123 MLX5_TXOFF_INFO(v,
5124                 MLX5_TXOFF_CONFIG_VLAN |
5125                 MLX5_TXOFF_CONFIG_METADATA)
5126
5127 MLX5_TXOFF_INFO(iv,
5128                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
5129                 MLX5_TXOFF_CONFIG_METADATA)
5130
5131 MLX5_TXOFF_INFO(none_mpw,
5132                 MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW |
5133                 MLX5_TXOFF_CONFIG_MPW)
5134
5135 MLX5_TXOFF_INFO(mci_mpw,
5136                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
5137                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
5138                 MLX5_TXOFF_CONFIG_MPW)
5139
5140 MLX5_TXOFF_INFO(mc_mpw,
5141                 MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
5142                 MLX5_TXOFF_CONFIG_EMPW | MLX5_TXOFF_CONFIG_MPW)
5143
5144 MLX5_TXOFF_INFO(i_mpw,
5145                 MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
5146                 MLX5_TXOFF_CONFIG_MPW)
5147 };
5148
5149 /**
5150  * Configure the Tx function to use. The routine checks configured
5151  * Tx offloads for the device and selects appropriate Tx burst
5152  * routine. There are multiple Tx burst routines compiled from
5153  * the same template in the most optimal way for the dedicated
5154  * Tx offloads set.
5155  *
5156  * @param dev
5157  *   Pointer to private data structure.
5158  *
5159  * @return
5160  *   Pointer to selected Tx burst function.
5161  */
5162 eth_tx_burst_t
5163 mlx5_select_tx_function(struct rte_eth_dev *dev)
5164 {
5165         struct mlx5_priv *priv = dev->data->dev_private;
5166         struct mlx5_dev_config *config = &priv->config;
5167         uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads;
5168         unsigned int diff = 0, olx = 0, i, m;
5169
5170         static_assert(MLX5_WQE_SIZE_MAX / MLX5_WSEG_SIZE <=
5171                       MLX5_DSEG_MAX, "invalid WQE max size");
5172         static_assert(MLX5_WQE_CSEG_SIZE == MLX5_WSEG_SIZE,
5173                       "invalid WQE Control Segment size");
5174         static_assert(MLX5_WQE_ESEG_SIZE == MLX5_WSEG_SIZE,
5175                       "invalid WQE Ethernet Segment size");
5176         static_assert(MLX5_WQE_DSEG_SIZE == MLX5_WSEG_SIZE,
5177                       "invalid WQE Data Segment size");
5178         static_assert(MLX5_WQE_SIZE == 4 * MLX5_WSEG_SIZE,
5179                       "invalid WQE size");
5180         assert(priv);
5181         if (tx_offloads & DEV_TX_OFFLOAD_MULTI_SEGS) {
5182                 /* We should support Multi-Segment Packets. */
5183                 olx |= MLX5_TXOFF_CONFIG_MULTI;
5184         }
5185         if (tx_offloads & (DEV_TX_OFFLOAD_TCP_TSO |
5186                            DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
5187                            DEV_TX_OFFLOAD_GRE_TNL_TSO |
5188                            DEV_TX_OFFLOAD_IP_TNL_TSO |
5189                            DEV_TX_OFFLOAD_UDP_TNL_TSO)) {
5190                 /* We should support TCP Send Offload. */
5191                 olx |= MLX5_TXOFF_CONFIG_TSO;
5192         }
5193         if (tx_offloads & (DEV_TX_OFFLOAD_IP_TNL_TSO |
5194                            DEV_TX_OFFLOAD_UDP_TNL_TSO |
5195                            DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
5196                 /* We should support Software Parser for Tunnels. */
5197                 olx |= MLX5_TXOFF_CONFIG_SWP;
5198         }
5199         if (tx_offloads & (DEV_TX_OFFLOAD_IPV4_CKSUM |
5200                            DEV_TX_OFFLOAD_UDP_CKSUM |
5201                            DEV_TX_OFFLOAD_TCP_CKSUM |
5202                            DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
5203                 /* We should support IP/TCP/UDP Checksums. */
5204                 olx |= MLX5_TXOFF_CONFIG_CSUM;
5205         }
5206         if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT) {
5207                 /* We should support VLAN insertion. */
5208                 olx |= MLX5_TXOFF_CONFIG_VLAN;
5209         }
5210         if (priv->txqs_n && (*priv->txqs)[0]) {
5211                 struct mlx5_txq_data *txd = (*priv->txqs)[0];
5212
5213                 if (txd->inlen_send) {
5214                         /*
5215                          * Check the data inline requirements. Data inline
5216                          * is enabled on per device basis, we can check
5217                          * the first Tx queue only.
5218                          *
5219                          * If device does not support VLAN insertion in WQE
5220                          * and some queues are requested to perform VLAN
5221                          * insertion offload than inline must be enabled.
5222                          */
5223                         olx |= MLX5_TXOFF_CONFIG_INLINE;
5224                 }
5225         }
5226         if (config->mps == MLX5_MPW_ENHANCED &&
5227             config->txq_inline_min <= 0) {
5228                 /*
5229                  * The NIC supports Enhanced Multi-Packet Write
5230                  * and does not require minimal inline data.
5231                  */
5232                 olx |= MLX5_TXOFF_CONFIG_EMPW;
5233         }
5234         if (rte_flow_dynf_metadata_avail()) {
5235                 /* We should support Flow metadata. */
5236                 olx |= MLX5_TXOFF_CONFIG_METADATA;
5237         }
5238         if (config->mps == MLX5_MPW) {
5239                 /*
5240                  * The NIC supports Legacy Multi-Packet Write.
5241                  * The MLX5_TXOFF_CONFIG_MPW controls the
5242                  * descriptor building method in combination
5243                  * with MLX5_TXOFF_CONFIG_EMPW.
5244                  */
5245                 if (!(olx & (MLX5_TXOFF_CONFIG_TSO |
5246                              MLX5_TXOFF_CONFIG_SWP |
5247                              MLX5_TXOFF_CONFIG_VLAN |
5248                              MLX5_TXOFF_CONFIG_METADATA)))
5249                         olx |= MLX5_TXOFF_CONFIG_EMPW |
5250                                MLX5_TXOFF_CONFIG_MPW;
5251         }
5252         /*
5253          * Scan the routines table to find the minimal
5254          * satisfying routine with requested offloads.
5255          */
5256         m = RTE_DIM(txoff_func);
5257         for (i = 0; i < RTE_DIM(txoff_func); i++) {
5258                 unsigned int tmp;
5259
5260                 tmp = txoff_func[i].olx;
5261                 if (tmp == olx) {
5262                         /* Meets requested offloads exactly.*/
5263                         m = i;
5264                         break;
5265                 }
5266                 if ((tmp & olx) != olx) {
5267                         /* Does not meet requested offloads at all. */
5268                         continue;
5269                 }
5270                 if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_EMPW)
5271                         /* Do not enable eMPW if not configured. */
5272                         continue;
5273                 if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_INLINE)
5274                         /* Do not enable inlining if not configured. */
5275                         continue;
5276                 /*
5277                  * Some routine meets the requirements.
5278                  * Check whether it has minimal amount
5279                  * of not requested offloads.
5280                  */
5281                 tmp = __builtin_popcountl(tmp & ~olx);
5282                 if (m >= RTE_DIM(txoff_func) || tmp < diff) {
5283                         /* First or better match, save and continue. */
5284                         m = i;
5285                         diff = tmp;
5286                         continue;
5287                 }
5288                 if (tmp == diff) {
5289                         tmp = txoff_func[i].olx ^ txoff_func[m].olx;
5290                         if (__builtin_ffsl(txoff_func[i].olx & ~tmp) <
5291                             __builtin_ffsl(txoff_func[m].olx & ~tmp)) {
5292                                 /* Lighter not requested offload. */
5293                                 m = i;
5294                         }
5295                 }
5296         }
5297         if (m >= RTE_DIM(txoff_func)) {
5298                 DRV_LOG(DEBUG, "port %u has no selected Tx function"
5299                                " for requested offloads %04X",
5300                                 dev->data->port_id, olx);
5301                 return NULL;
5302         }
5303         DRV_LOG(DEBUG, "port %u has selected Tx function"
5304                        " supporting offloads %04X/%04X",
5305                         dev->data->port_id, olx, txoff_func[m].olx);
5306         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MULTI)
5307                 DRV_LOG(DEBUG, "\tMULTI (multi segment)");
5308         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_TSO)
5309                 DRV_LOG(DEBUG, "\tTSO   (TCP send offload)");
5310         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_SWP)
5311                 DRV_LOG(DEBUG, "\tSWP   (software parser)");
5312         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_CSUM)
5313                 DRV_LOG(DEBUG, "\tCSUM  (checksum offload)");
5314         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_INLINE)
5315                 DRV_LOG(DEBUG, "\tINLIN (inline data)");
5316         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_VLAN)
5317                 DRV_LOG(DEBUG, "\tVLANI (VLAN insertion)");
5318         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_METADATA)
5319                 DRV_LOG(DEBUG, "\tMETAD (tx Flow metadata)");
5320         if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_EMPW) {
5321                 if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MPW)
5322                         DRV_LOG(DEBUG, "\tMPW   (Legacy MPW)");
5323                 else
5324                         DRV_LOG(DEBUG, "\tEMPW  (Enhanced MPW)");
5325         }
5326         return txoff_func[m].func;
5327 }