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