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