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