xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 6bb506cc2c2d877a10275c223e94e8cf99d24872)
18fd92a66SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
22e22920bSAdrien Mazarguil  * Copyright 2015 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2015 Mellanox Technologies, Ltd
42e22920bSAdrien Mazarguil  */
52e22920bSAdrien Mazarguil 
62e22920bSAdrien Mazarguil #include <assert.h>
72e22920bSAdrien Mazarguil #include <stdint.h>
82e22920bSAdrien Mazarguil #include <string.h>
92e22920bSAdrien Mazarguil #include <stdlib.h>
102e22920bSAdrien Mazarguil 
112e22920bSAdrien Mazarguil /* Verbs header. */
122e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
132e22920bSAdrien Mazarguil #ifdef PEDANTIC
14fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic"
152e22920bSAdrien Mazarguil #endif
162e22920bSAdrien Mazarguil #include <infiniband/verbs.h>
1743e9d979SShachar Beiser #include <infiniband/mlx5dv.h>
182e22920bSAdrien Mazarguil #ifdef PEDANTIC
19fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
202e22920bSAdrien Mazarguil #endif
212e22920bSAdrien Mazarguil 
222e22920bSAdrien Mazarguil #include <rte_mbuf.h>
232e22920bSAdrien Mazarguil #include <rte_mempool.h>
242e22920bSAdrien Mazarguil #include <rte_prefetch.h>
252e22920bSAdrien Mazarguil #include <rte_common.h>
262e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
276218063bSNélio Laranjeiro #include <rte_ether.h>
282e22920bSAdrien Mazarguil 
292e22920bSAdrien Mazarguil #include "mlx5.h"
302e22920bSAdrien Mazarguil #include "mlx5_utils.h"
312e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
32f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
332e22920bSAdrien Mazarguil #include "mlx5_defs.h"
346218063bSNélio Laranjeiro #include "mlx5_prm.h"
356218063bSNélio Laranjeiro 
36c0583d98SJerin Jacob static __rte_always_inline uint32_t
373cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe);
38ff1807a3SNélio Laranjeiro 
39c0583d98SJerin Jacob static __rte_always_inline int
4078142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
412e633f1fSYongseok Koh 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe);
42ff1807a3SNélio Laranjeiro 
43c0583d98SJerin Jacob static __rte_always_inline uint32_t
446ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
45ff1807a3SNélio Laranjeiro 
463e1f82a1SYongseok Koh static __rte_always_inline void
473e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
483e1f82a1SYongseok Koh 	       volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res);
493e1f82a1SYongseok Koh 
507d6bf6b8SYongseok Koh static __rte_always_inline void
517d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx);
527d6bf6b8SYongseok Koh 
53ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
54ea16068cSYongseok Koh 	[0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
55ea16068cSYongseok Koh };
56ea16068cSYongseok Koh 
575f8ba81cSXueming Li uint8_t mlx5_cksum_table[1 << 10] __rte_cache_aligned;
585f8ba81cSXueming Li uint8_t mlx5_swp_types_table[1 << 10] __rte_cache_aligned;
595f8ba81cSXueming Li 
60ea16068cSYongseok Koh /**
61ea16068cSYongseok Koh  * Build a table to translate Rx completion flags to packet type.
62ea16068cSYongseok Koh  *
63ea16068cSYongseok Koh  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
64ea16068cSYongseok Koh  */
65ea16068cSYongseok Koh void
66ea16068cSYongseok Koh mlx5_set_ptype_table(void)
67ea16068cSYongseok Koh {
68ea16068cSYongseok Koh 	unsigned int i;
69ea16068cSYongseok Koh 	uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
70ea16068cSYongseok Koh 
719807f113SYongseok Koh 	/* Last entry must not be overwritten, reserved for errored packet. */
729807f113SYongseok Koh 	for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
73ea16068cSYongseok Koh 		(*p)[i] = RTE_PTYPE_UNKNOWN;
746cb559d6SYongseok Koh 	/*
756cb559d6SYongseok Koh 	 * The index to the array should have:
76ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
77ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
78ea16068cSYongseok Koh 	 * bit[5] = ip_frag
79ea16068cSYongseok Koh 	 * bit[6] = tunneled
80ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
8199c12dccSNélio Laranjeiro 	 */
823ca63b88SShahaf Shuler 	/* L2 */
833ca63b88SShahaf Shuler 	(*p)[0x00] = RTE_PTYPE_L2_ETHER;
84ea16068cSYongseok Koh 	/* L3 */
85ea16068cSYongseok Koh 	(*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
86ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
87ea16068cSYongseok Koh 	(*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
88ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
89ea16068cSYongseok Koh 	/* Fragmented */
90ea16068cSYongseok Koh 	(*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
91ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
92ea16068cSYongseok Koh 	(*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
93ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
94ea16068cSYongseok Koh 	/* TCP */
95ea16068cSYongseok Koh 	(*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
96ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
97ea16068cSYongseok Koh 	(*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
98ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
990915e287SBin Huang 	(*p)[0x0d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1000915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1010915e287SBin Huang 	(*p)[0x0e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1020915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1030915e287SBin Huang 	(*p)[0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1040915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1050915e287SBin Huang 	(*p)[0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1060915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
107ea16068cSYongseok Koh 	/* UDP */
108ea16068cSYongseok Koh 	(*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
109ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
110ea16068cSYongseok Koh 	(*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
111ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
112ea16068cSYongseok Koh 	/* Repeat with outer_l3_type being set. Just in case. */
113ea16068cSYongseok Koh 	(*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
114ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
115ea16068cSYongseok Koh 	(*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
116ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
117ea16068cSYongseok Koh 	(*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
118ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
119ea16068cSYongseok Koh 	(*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
120ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
121ea16068cSYongseok Koh 	(*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
122ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
123ea16068cSYongseok Koh 	(*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
124ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
1250915e287SBin Huang 	(*p)[0x8d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1260915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1270915e287SBin Huang 	(*p)[0x8e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1280915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1290915e287SBin Huang 	(*p)[0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1300915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1310915e287SBin Huang 	(*p)[0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1320915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
133ea16068cSYongseok Koh 	(*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
134ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
135ea16068cSYongseok Koh 	(*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
136ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
137ea16068cSYongseok Koh 	/* Tunneled - L3 */
1383cc08bc6SXueming Li 	(*p)[0x40] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
139ea16068cSYongseok Koh 	(*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
140ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
141ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
142ea16068cSYongseok Koh 	(*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
143ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
144ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
1453cc08bc6SXueming Li 	(*p)[0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
146ea16068cSYongseok Koh 	(*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
147ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
148ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
149ea16068cSYongseok Koh 	(*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
150ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
151ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
152ea16068cSYongseok Koh 	/* Tunneled - Fragmented */
153ea16068cSYongseok Koh 	(*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
154ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
155ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
156ea16068cSYongseok Koh 	(*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
157ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
158ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
159ea16068cSYongseok Koh 	(*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
160ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
161ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
162ea16068cSYongseok Koh 	(*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
163ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
164ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
165ea16068cSYongseok Koh 	/* Tunneled - TCP */
166ea16068cSYongseok Koh 	(*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
167ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1686c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
169ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
170ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1716c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
1720915e287SBin Huang 	(*p)[0x4d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1730915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1740915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1750915e287SBin Huang 	(*p)[0x4e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1760915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1770915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1780915e287SBin Huang 	(*p)[0x51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1790915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1800915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1810915e287SBin Huang 	(*p)[0x52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1820915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1830915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
184ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
185ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1866c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
187ea16068cSYongseok Koh 	(*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
188ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1896c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
1900915e287SBin Huang 	(*p)[0xcd] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1910915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1920915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1930915e287SBin Huang 	(*p)[0xce] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1940915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1950915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1960915e287SBin Huang 	(*p)[0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1970915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1980915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1990915e287SBin Huang 	(*p)[0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
2000915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2010915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
202ea16068cSYongseok Koh 	/* Tunneled - UDP */
203ea16068cSYongseok Koh 	(*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
204ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
2056c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
206ea16068cSYongseok Koh 	(*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
207ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2086c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
209ea16068cSYongseok Koh 	(*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
210ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
2116c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
212ea16068cSYongseok Koh 	(*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
213ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2146c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
215ea16068cSYongseok Koh }
216fdcb0f53SNélio Laranjeiro 
2172e22920bSAdrien Mazarguil /**
2185f8ba81cSXueming Li  * Build a table to translate packet to checksum type of Verbs.
2195f8ba81cSXueming Li  */
2205f8ba81cSXueming Li void
2215f8ba81cSXueming Li mlx5_set_cksum_table(void)
2225f8ba81cSXueming Li {
2235f8ba81cSXueming Li 	unsigned int i;
2245f8ba81cSXueming Li 	uint8_t v;
2255f8ba81cSXueming Li 
2265f8ba81cSXueming Li 	/*
2275f8ba81cSXueming Li 	 * The index should have:
2285f8ba81cSXueming Li 	 * bit[0] = PKT_TX_TCP_SEG
2295f8ba81cSXueming Li 	 * bit[2:3] = PKT_TX_UDP_CKSUM, PKT_TX_TCP_CKSUM
2305f8ba81cSXueming Li 	 * bit[4] = PKT_TX_IP_CKSUM
2315f8ba81cSXueming Li 	 * bit[8] = PKT_TX_OUTER_IP_CKSUM
2325f8ba81cSXueming Li 	 * bit[9] = tunnel
2335f8ba81cSXueming Li 	 */
2345f8ba81cSXueming Li 	for (i = 0; i < RTE_DIM(mlx5_cksum_table); ++i) {
2355f8ba81cSXueming Li 		v = 0;
2365f8ba81cSXueming Li 		if (i & (1 << 9)) {
2375f8ba81cSXueming Li 			/* Tunneled packet. */
2385f8ba81cSXueming Li 			if (i & (1 << 8)) /* Outer IP. */
2395f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_CSUM;
2405f8ba81cSXueming Li 			if (i & (1 << 4)) /* Inner IP. */
2415f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_INNER_CSUM;
2425f8ba81cSXueming Li 			if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
2435f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L4_INNER_CSUM;
2445f8ba81cSXueming Li 		} else {
2455f8ba81cSXueming Li 			/* No tunnel. */
2465f8ba81cSXueming Li 			if (i & (1 << 4)) /* IP. */
2475f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_CSUM;
2485f8ba81cSXueming Li 			if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
2495f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L4_CSUM;
2505f8ba81cSXueming Li 		}
2515f8ba81cSXueming Li 		mlx5_cksum_table[i] = v;
2525f8ba81cSXueming Li 	}
2535f8ba81cSXueming Li }
2545f8ba81cSXueming Li 
2555f8ba81cSXueming Li /**
2565f8ba81cSXueming Li  * Build a table to translate packet type of mbuf to SWP type of Verbs.
2575f8ba81cSXueming Li  */
2585f8ba81cSXueming Li void
2595f8ba81cSXueming Li mlx5_set_swp_types_table(void)
2605f8ba81cSXueming Li {
2615f8ba81cSXueming Li 	unsigned int i;
2625f8ba81cSXueming Li 	uint8_t v;
2635f8ba81cSXueming Li 
2645f8ba81cSXueming Li 	/*
2655f8ba81cSXueming Li 	 * The index should have:
2665f8ba81cSXueming Li 	 * bit[0:1] = PKT_TX_L4_MASK
2675f8ba81cSXueming Li 	 * bit[4] = PKT_TX_IPV6
2685f8ba81cSXueming Li 	 * bit[8] = PKT_TX_OUTER_IPV6
2695f8ba81cSXueming Li 	 * bit[9] = PKT_TX_OUTER_UDP
2705f8ba81cSXueming Li 	 */
2715f8ba81cSXueming Li 	for (i = 0; i < RTE_DIM(mlx5_swp_types_table); ++i) {
2725f8ba81cSXueming Li 		v = 0;
2735f8ba81cSXueming Li 		if (i & (1 << 8))
2745f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L3_OUTER_IPV6;
2755f8ba81cSXueming Li 		if (i & (1 << 9))
2765f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L4_OUTER_UDP;
2775f8ba81cSXueming Li 		if (i & (1 << 4))
2785f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L3_INNER_IPV6;
2795f8ba81cSXueming Li 		if ((i & 3) == (PKT_TX_UDP_CKSUM >> 52))
2805f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L4_INNER_UDP;
2815f8ba81cSXueming Li 		mlx5_swp_types_table[i] = v;
2825f8ba81cSXueming Li 	}
2835f8ba81cSXueming Li }
2845f8ba81cSXueming Li 
2855f8ba81cSXueming Li /**
2866ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
2876ce84bd8SYongseok Koh  *
2886ce84bd8SYongseok Koh  * @param txq
2896ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
2906ce84bd8SYongseok Koh  * @param addr
2916ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
2926ce84bd8SYongseok Koh  *
2936ce84bd8SYongseok Koh  * @return
2946ce84bd8SYongseok Koh  *   Size of tailroom.
2956ce84bd8SYongseok Koh  */
2966ce84bd8SYongseok Koh static inline size_t
297991b04f6SNélio Laranjeiro tx_mlx5_wq_tailroom(struct mlx5_txq_data *txq, void *addr)
2986ce84bd8SYongseok Koh {
2996ce84bd8SYongseok Koh 	size_t tailroom;
3006ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
3016ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
3026ce84bd8SYongseok Koh 		   (uintptr_t)addr;
3036ce84bd8SYongseok Koh 	return tailroom;
3046ce84bd8SYongseok Koh }
3056ce84bd8SYongseok Koh 
3066ce84bd8SYongseok Koh /**
3076ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
3086ce84bd8SYongseok Koh  *
3096ce84bd8SYongseok Koh  * @param dst
3106ce84bd8SYongseok Koh  *   Pointer to destination.
3116ce84bd8SYongseok Koh  * @param src
3126ce84bd8SYongseok Koh  *   Pointer to source.
3136ce84bd8SYongseok Koh  * @param n
3146ce84bd8SYongseok Koh  *   Number of bytes to copy.
3156ce84bd8SYongseok Koh  * @param base
3166ce84bd8SYongseok Koh  *   Pointer to head of queue.
3176ce84bd8SYongseok Koh  * @param tailroom
3186ce84bd8SYongseok Koh  *   Size of tailroom from dst.
3196ce84bd8SYongseok Koh  *
3206ce84bd8SYongseok Koh  * @return
3216ce84bd8SYongseok Koh  *   Pointer after copied data.
3226ce84bd8SYongseok Koh  */
3236ce84bd8SYongseok Koh static inline void *
3246ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
3256ce84bd8SYongseok Koh 		void *base, size_t tailroom)
3266ce84bd8SYongseok Koh {
3276ce84bd8SYongseok Koh 	void *ret;
3286ce84bd8SYongseok Koh 
3296ce84bd8SYongseok Koh 	if (n > tailroom) {
3306ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
3316ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
3326ce84bd8SYongseok Koh 			   n - tailroom);
3336ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
3346ce84bd8SYongseok Koh 	} else {
3356ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
3366ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
3376ce84bd8SYongseok Koh 	}
3386ce84bd8SYongseok Koh 	return ret;
3396ce84bd8SYongseok Koh }
3406ce84bd8SYongseok Koh 
3416ce84bd8SYongseok Koh /**
342593f472cSXueming Li  * Inline TSO headers into WQE.
343593f472cSXueming Li  *
344593f472cSXueming Li  * @return
345593f472cSXueming Li  *   0 on success, negative errno value on failure.
346593f472cSXueming Li  */
347593f472cSXueming Li static int
348593f472cSXueming Li inline_tso(struct mlx5_txq_data *txq, struct rte_mbuf *buf,
349593f472cSXueming Li 	   uint32_t *length,
350593f472cSXueming Li 	   uintptr_t *addr,
351593f472cSXueming Li 	   uint16_t *pkt_inline_sz,
352593f472cSXueming Li 	   uint8_t **raw,
353593f472cSXueming Li 	   uint16_t *max_wqe,
354593f472cSXueming Li 	   uint16_t *tso_segsz,
355593f472cSXueming Li 	   uint16_t *tso_header_sz)
356593f472cSXueming Li {
357593f472cSXueming Li 	uintptr_t end = (uintptr_t)(((uintptr_t)txq->wqes) +
358593f472cSXueming Li 				    (1 << txq->wqe_n) * MLX5_WQE_SIZE);
359593f472cSXueming Li 	unsigned int copy_b;
360593f472cSXueming Li 	uint8_t vlan_sz = (buf->ol_flags & PKT_TX_VLAN_PKT) ? 4 : 0;
3615f8ba81cSXueming Li 	const uint8_t tunneled = txq->tunnel_en && (buf->ol_flags &
3625f8ba81cSXueming Li 				 PKT_TX_TUNNEL_MASK);
363593f472cSXueming Li 	uint16_t n_wqe;
364593f472cSXueming Li 
365593f472cSXueming Li 	*tso_segsz = buf->tso_segsz;
366593f472cSXueming Li 	*tso_header_sz = buf->l2_len + vlan_sz + buf->l3_len + buf->l4_len;
367593f472cSXueming Li 	if (unlikely(*tso_segsz == 0 || *tso_header_sz == 0)) {
368593f472cSXueming Li 		txq->stats.oerrors++;
369593f472cSXueming Li 		return -EINVAL;
370593f472cSXueming Li 	}
3715f8ba81cSXueming Li 	if (tunneled)
372593f472cSXueming Li 		*tso_header_sz += buf->outer_l2_len + buf->outer_l3_len;
3735f8ba81cSXueming Li 	/* First seg must contain all TSO headers. */
3745f8ba81cSXueming Li 	if (unlikely(*tso_header_sz > MLX5_MAX_TSO_HEADER) ||
3755f8ba81cSXueming Li 		     *tso_header_sz > DATA_LEN(buf)) {
376593f472cSXueming Li 		txq->stats.oerrors++;
377593f472cSXueming Li 		return -EINVAL;
378593f472cSXueming Li 	}
379593f472cSXueming Li 	copy_b = *tso_header_sz - *pkt_inline_sz;
380593f472cSXueming Li 	if (!copy_b || ((end - (uintptr_t)*raw) < copy_b))
381593f472cSXueming Li 		return -EAGAIN;
382593f472cSXueming Li 	n_wqe = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
383593f472cSXueming Li 	if (unlikely(*max_wqe < n_wqe))
384593f472cSXueming Li 		return -EINVAL;
385593f472cSXueming Li 	*max_wqe -= n_wqe;
386593f472cSXueming Li 	rte_memcpy((void *)*raw, (void *)*addr, copy_b);
387593f472cSXueming Li 	*length -= copy_b;
388593f472cSXueming Li 	*addr += copy_b;
389593f472cSXueming Li 	copy_b = MLX5_WQE_DS(copy_b) * MLX5_WQE_DWORD_SIZE;
390593f472cSXueming Li 	*pkt_inline_sz += copy_b;
391593f472cSXueming Li 	*raw += copy_b;
392593f472cSXueming Li 	return 0;
393593f472cSXueming Li }
394593f472cSXueming Li 
395593f472cSXueming Li /**
3968788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
3978788fec1SOlivier Matz  *
3988788fec1SOlivier Matz  * @param tx_queue
3998788fec1SOlivier Matz  *   The tx queue.
4008788fec1SOlivier Matz  * @param[in] offset
4018788fec1SOlivier Matz  *   The index of the descriptor in the ring.
4028788fec1SOlivier Matz  *
4038788fec1SOlivier Matz  * @return
4048788fec1SOlivier Matz  *   The status of the tx descriptor.
4058788fec1SOlivier Matz  */
4068788fec1SOlivier Matz int
4078788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
4088788fec1SOlivier Matz {
409991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = tx_queue;
4108c819a69SYongseok Koh 	uint16_t used;
4118788fec1SOlivier Matz 
4126cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
4138c819a69SYongseok Koh 	used = txq->elts_head - txq->elts_tail;
4148788fec1SOlivier Matz 	if (offset < used)
4158788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
4168788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
4178788fec1SOlivier Matz }
4188788fec1SOlivier Matz 
4198788fec1SOlivier Matz /**
42026f04883STom Barbette  * Internal function to compute the number of used descriptors in an RX queue
4218788fec1SOlivier Matz  *
42226f04883STom Barbette  * @param rxq
42326f04883STom Barbette  *   The Rx queue.
4248788fec1SOlivier Matz  *
4258788fec1SOlivier Matz  * @return
42626f04883STom Barbette  *   The number of used rx descriptor.
4278788fec1SOlivier Matz  */
42826f04883STom Barbette static uint32_t
42926f04883STom Barbette rx_queue_count(struct mlx5_rxq_data *rxq)
4308788fec1SOlivier Matz {
4318788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
4328788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
4338788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
4348788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
4358788fec1SOlivier Matz 	unsigned int cq_ci;
4368788fec1SOlivier Matz 	unsigned int used;
4378788fec1SOlivier Matz 
4388788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
4398788fec1SOlivier Matz 	if (zip->ai) {
4408788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
4418788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
4428788fec1SOlivier Matz 	} else {
4438788fec1SOlivier Matz 		used = 0;
4448788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
4458788fec1SOlivier Matz 	}
4468788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
4478788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
4488788fec1SOlivier Matz 		int8_t op_own;
4498788fec1SOlivier Matz 		unsigned int n;
4508788fec1SOlivier Matz 
4518788fec1SOlivier Matz 		op_own = cqe->op_own;
4528788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
4536b30a6a8SShachar Beiser 			n = rte_be_to_cpu_32(cqe->byte_cnt);
4548788fec1SOlivier Matz 		else
4558788fec1SOlivier Matz 			n = 1;
4568788fec1SOlivier Matz 		cq_ci += n;
4578788fec1SOlivier Matz 		used += n;
4588788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
4598788fec1SOlivier Matz 	}
4608788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
46126f04883STom Barbette 	return used;
46226f04883STom Barbette }
46326f04883STom Barbette 
46426f04883STom Barbette /**
46526f04883STom Barbette  * DPDK callback to check the status of a rx descriptor.
46626f04883STom Barbette  *
46726f04883STom Barbette  * @param rx_queue
46826f04883STom Barbette  *   The Rx queue.
46926f04883STom Barbette  * @param[in] offset
47026f04883STom Barbette  *   The index of the descriptor in the ring.
47126f04883STom Barbette  *
47226f04883STom Barbette  * @return
47326f04883STom Barbette  *   The status of the tx descriptor.
47426f04883STom Barbette  */
47526f04883STom Barbette int
47626f04883STom Barbette mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
47726f04883STom Barbette {
47826f04883STom Barbette 	struct mlx5_rxq_data *rxq = rx_queue;
47926f04883STom Barbette 	struct mlx5_rxq_ctrl *rxq_ctrl =
48026f04883STom Barbette 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
48126f04883STom Barbette 	struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv);
48226f04883STom Barbette 
48326f04883STom Barbette 	if (dev->rx_pkt_burst != mlx5_rx_burst) {
48426f04883STom Barbette 		rte_errno = ENOTSUP;
48526f04883STom Barbette 		return -rte_errno;
48626f04883STom Barbette 	}
48726f04883STom Barbette 	if (offset >= (1 << rxq->elts_n)) {
48826f04883STom Barbette 		rte_errno = EINVAL;
48926f04883STom Barbette 		return -rte_errno;
49026f04883STom Barbette 	}
49126f04883STom Barbette 	if (offset < rx_queue_count(rxq))
4928788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
4938788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
4948788fec1SOlivier Matz }
4958788fec1SOlivier Matz 
4968788fec1SOlivier Matz /**
49726f04883STom Barbette  * DPDK callback to get the number of used descriptors in a RX queue
49826f04883STom Barbette  *
49926f04883STom Barbette  * @param dev
50026f04883STom Barbette  *   Pointer to the device structure.
50126f04883STom Barbette  *
50226f04883STom Barbette  * @param rx_queue_id
50326f04883STom Barbette  *   The Rx queue.
50426f04883STom Barbette  *
50526f04883STom Barbette  * @return
50626f04883STom Barbette  *   The number of used rx descriptor.
50726f04883STom Barbette  *   -EINVAL if the queue is invalid
50826f04883STom Barbette  */
50926f04883STom Barbette uint32_t
51026f04883STom Barbette mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
51126f04883STom Barbette {
512dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
51326f04883STom Barbette 	struct mlx5_rxq_data *rxq;
51426f04883STom Barbette 
51526f04883STom Barbette 	if (dev->rx_pkt_burst != mlx5_rx_burst) {
51626f04883STom Barbette 		rte_errno = ENOTSUP;
51726f04883STom Barbette 		return -rte_errno;
51826f04883STom Barbette 	}
51926f04883STom Barbette 	rxq = (*priv->rxqs)[rx_queue_id];
52026f04883STom Barbette 	if (!rxq) {
52126f04883STom Barbette 		rte_errno = EINVAL;
52226f04883STom Barbette 		return -rte_errno;
52326f04883STom Barbette 	}
52426f04883STom Barbette 	return rx_queue_count(rxq);
52526f04883STom Barbette }
52626f04883STom Barbette 
527066cfecdSMatan Azrad #define MLX5_SYSTEM_LOG_DIR "/var/log"
528066cfecdSMatan Azrad /**
529066cfecdSMatan Azrad  * Dump debug information to log file.
530066cfecdSMatan Azrad  *
531066cfecdSMatan Azrad  * @param fname
532066cfecdSMatan Azrad  *   The file name.
533066cfecdSMatan Azrad  * @param hex_title
534066cfecdSMatan Azrad  *   If not NULL this string is printed as a header to the output
535066cfecdSMatan Azrad  *   and the output will be in hexadecimal view.
536066cfecdSMatan Azrad  * @param buf
537066cfecdSMatan Azrad  *   This is the buffer address to print out.
538066cfecdSMatan Azrad  * @param len
539066cfecdSMatan Azrad  *   The number of bytes to dump out.
540066cfecdSMatan Azrad  */
541066cfecdSMatan Azrad void
542066cfecdSMatan Azrad mlx5_dump_debug_information(const char *fname, const char *hex_title,
543066cfecdSMatan Azrad 			    const void *buf, unsigned int hex_len)
544066cfecdSMatan Azrad {
545066cfecdSMatan Azrad 	FILE *fd;
546066cfecdSMatan Azrad 
547066cfecdSMatan Azrad 	MKSTR(path, "%s/%s", MLX5_SYSTEM_LOG_DIR, fname);
548066cfecdSMatan Azrad 	fd = fopen(path, "a+");
549066cfecdSMatan Azrad 	if (!fd) {
550066cfecdSMatan Azrad 		DRV_LOG(WARNING, "cannot open %s for debug dump\n",
551066cfecdSMatan Azrad 			path);
552066cfecdSMatan Azrad 		MKSTR(path2, "./%s", fname);
553066cfecdSMatan Azrad 		fd = fopen(path2, "a+");
554066cfecdSMatan Azrad 		if (!fd) {
555066cfecdSMatan Azrad 			DRV_LOG(ERR, "cannot open %s for debug dump\n",
556066cfecdSMatan Azrad 				path2);
557066cfecdSMatan Azrad 			return;
558066cfecdSMatan Azrad 		}
559066cfecdSMatan Azrad 		DRV_LOG(INFO, "New debug dump in file %s\n", path2);
560066cfecdSMatan Azrad 	} else {
561066cfecdSMatan Azrad 		DRV_LOG(INFO, "New debug dump in file %s\n", path);
562066cfecdSMatan Azrad 	}
563066cfecdSMatan Azrad 	if (hex_title)
564066cfecdSMatan Azrad 		rte_hexdump(fd, hex_title, buf, hex_len);
565066cfecdSMatan Azrad 	else
566066cfecdSMatan Azrad 		fprintf(fd, "%s", (const char *)buf);
567066cfecdSMatan Azrad 	fprintf(fd, "\n\n\n");
568066cfecdSMatan Azrad 	fclose(fd);
569066cfecdSMatan Azrad }
570066cfecdSMatan Azrad 
57126f04883STom Barbette /**
5722e22920bSAdrien Mazarguil  * DPDK callback for TX.
5732e22920bSAdrien Mazarguil  *
5742e22920bSAdrien Mazarguil  * @param dpdk_txq
5752e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
5762e22920bSAdrien Mazarguil  * @param[in] pkts
5772e22920bSAdrien Mazarguil  *   Packets to transmit.
5782e22920bSAdrien Mazarguil  * @param pkts_n
5792e22920bSAdrien Mazarguil  *   Number of packets in array.
5802e22920bSAdrien Mazarguil  *
5812e22920bSAdrien Mazarguil  * @return
5822e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
5832e22920bSAdrien Mazarguil  */
5842e22920bSAdrien Mazarguil uint16_t
5852e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
5862e22920bSAdrien Mazarguil {
587991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
5881d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
5898c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
5908c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
591c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
592a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
5933f13f8c2SShahaf Shuler 	unsigned int k = 0;
5948c819a69SYongseok Koh 	uint16_t max_elts;
595f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
596c305090bSAdrien Mazarguil 	unsigned int comp;
597ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
5986579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
59927a6b2d6SNélio Laranjeiro 	const unsigned int max_inline = txq->max_inline;
6006bf10ab6SMoti Haimovsky 	uint64_t addr_64;
6012e22920bSAdrien Mazarguil 
6021d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
6031d88ba17SNélio Laranjeiro 		return 0;
6045e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
605c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
6061d88ba17SNélio Laranjeiro 	/* Start processing. */
6076cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
6088c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
609f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
610f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
611f04f1d51SNélio Laranjeiro 		return 0;
612c3d62cc9SAdrien Mazarguil 	do {
6135f8ba81cSXueming Li 		struct rte_mbuf *buf = *pkts; /* First_seg. */
6143bbae1ebSNélio Laranjeiro 		uint8_t *raw;
6153bbae1ebSNélio Laranjeiro 		volatile struct mlx5_wqe_v *wqe = NULL;
6169a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
617573f54afSNélio Laranjeiro 		uint32_t length;
6188688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
619ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
6206579c27cSNélio Laranjeiro 		uintptr_t addr;
6210d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
6223f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
623eef822ddSNélio Laranjeiro 		uint16_t ehdr;
6244aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
6255f8ba81cSXueming Li 		uint8_t tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG);
6265f8ba81cSXueming Li 		uint32_t swp_offsets = 0;
6275f8ba81cSXueming Li 		uint8_t swp_types = 0;
6286bd7fbd0SDekel Peled 		rte_be32_t metadata;
62983daf156SShahaf Shuler 		uint16_t tso_segsz = 0;
6306579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
6316579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
6326579c27cSNélio Laranjeiro #endif
633593f472cSXueming Li 		int ret;
6342e22920bSAdrien Mazarguil 
6356579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
636c3d62cc9SAdrien Mazarguil 		/*
637c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
638c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
639c3d62cc9SAdrien Mazarguil 		 */
640a5bf6af9SAdrien Mazarguil 		assert(segs_n);
6418c819a69SYongseok Koh 		if (max_elts < segs_n)
642c3d62cc9SAdrien Mazarguil 			break;
6438c819a69SYongseok Koh 		max_elts -= segs_n;
644f895536bSYongseok Koh 		sg = --segs_n;
645f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
646f04f1d51SNélio Laranjeiro 			break;
6479a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
648fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
649fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
6503730e6c6SYongseok Koh 		if (pkts_n - i > 1)
6513730e6c6SYongseok Koh 			rte_prefetch0(*(pkts + 1));
6526579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
6532e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
654eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
655eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
6566579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
6576579c27cSNélio Laranjeiro 		total_length = length;
6586579c27cSNélio Laranjeiro #endif
65924c14430SShahaf Shuler 		if (length < (MLX5_WQE_DWORD_SIZE + 2)) {
66024c14430SShahaf Shuler 			txq->stats.oerrors++;
661959be52eSNélio Laranjeiro 			break;
66224c14430SShahaf Shuler 		}
6632e22920bSAdrien Mazarguil 		/* Update element. */
6648c819a69SYongseok Koh 		(*txq->elts)[elts_head & elts_m] = buf;
6655e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
6663730e6c6SYongseok Koh 		if (pkts_n - i > 1)
6673730e6c6SYongseok Koh 			rte_prefetch0(
6683730e6c6SYongseok Koh 			    rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
6695f8ba81cSXueming Li 		cs_flags = txq_ol_cksum_to_cs(buf);
6708f6d9e13SYongseok Koh 		txq_mbuf_to_swp(txq, buf, (uint8_t *)&swp_offsets, &swp_types);
671b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
6726bd7fbd0SDekel Peled 		/* Copy metadata from mbuf if valid */
6736bd7fbd0SDekel Peled 		metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata :
6746bd7fbd0SDekel Peled 							     0;
6756579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
6768f6d9e13SYongseok Koh 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
6776b30a6a8SShachar Beiser 			uint32_t vlan = rte_cpu_to_be_32(0x81000000 |
6786b30a6a8SShachar Beiser 							 buf->vlan_tci);
67935b2d13fSOlivier Matz 			unsigned int len = 2 * RTE_ETHER_ADDR_LEN - 2;
6806579c27cSNélio Laranjeiro 
6810d637a34SNélio Laranjeiro 			addr += 2;
6820d637a34SNélio Laranjeiro 			length -= 2;
6830d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
6840d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
6850d637a34SNélio Laranjeiro 			/* Copy VLAN. */
6860d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
6870d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
6880d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
6890d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
6900d637a34SNélio Laranjeiro 			addr += len + 2;
6910d637a34SNélio Laranjeiro 			length -= (len + 2);
6920d637a34SNélio Laranjeiro 		} else {
6930d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
6940d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
6950d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
6960d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
6976579c27cSNélio Laranjeiro 		}
698d8292497SYongseok Koh 		raw += MLX5_WQE_DWORD_SIZE;
6993f13f8c2SShahaf Shuler 		if (tso) {
7005f8ba81cSXueming Li 			ret = inline_tso(txq, buf, &length,
701593f472cSXueming Li 					 &addr, &pkt_inline_sz,
702593f472cSXueming Li 					 &raw, &max_wqe,
703593f472cSXueming Li 					 &tso_segsz, &tso_header_sz);
704593f472cSXueming Li 			if (ret == -EINVAL) {
70596fc8d65SShahaf Shuler 				break;
706593f472cSXueming Li 			} else if (ret == -EAGAIN) {
7073f13f8c2SShahaf Shuler 				/* NOP WQE. */
7083f13f8c2SShahaf Shuler 				wqe->ctrl = (rte_v128u32_t){
70936aa55eaSYongseok Koh 					rte_cpu_to_be_32(txq->wqe_ci << 8),
71036aa55eaSYongseok Koh 					rte_cpu_to_be_32(txq->qp_num_8s | 1),
7113f13f8c2SShahaf Shuler 					0,
7123f13f8c2SShahaf Shuler 					0,
7133f13f8c2SShahaf Shuler 				};
7143f13f8c2SShahaf Shuler 				ds = 1;
715cb98affeSThierry Herbelot #ifdef MLX5_PMD_SOFT_COUNTERS
7163f13f8c2SShahaf Shuler 				total_length = 0;
717cb98affeSThierry Herbelot #endif
7183f13f8c2SShahaf Shuler 				k++;
7193f13f8c2SShahaf Shuler 				goto next_wqe;
7203f13f8c2SShahaf Shuler 			}
7213f13f8c2SShahaf Shuler 		}
7226579c27cSNélio Laranjeiro 		/* Inline if enough room. */
72327a6b2d6SNélio Laranjeiro 		if (max_inline || tso) {
724f895536bSYongseok Koh 			uint32_t inl = 0;
725fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
726fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
727fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
728ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
7298fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
730d8292497SYongseok Koh 						   (pkt_inline_sz - 2) -
731d8292497SYongseok Koh 						   !!tso * sizeof(inl);
732f895536bSYongseok Koh 			uintptr_t addr_end;
733f895536bSYongseok Koh 			unsigned int copy_b;
7346579c27cSNélio Laranjeiro 
735f895536bSYongseok Koh pkt_inline:
736f895536bSYongseok Koh 			addr_end = RTE_ALIGN_FLOOR(addr + inline_room,
737f895536bSYongseok Koh 						   RTE_CACHE_LINE_SIZE);
738f895536bSYongseok Koh 			copy_b = (addr_end > addr) ?
739f895536bSYongseok Koh 				 RTE_MIN((addr_end - addr), length) : 0;
74057c0e249SShahaf Shuler 			if (copy_b && ((end - (uintptr_t)raw) >
74157c0e249SShahaf Shuler 				       (copy_b + sizeof(inl)))) {
742f04f1d51SNélio Laranjeiro 				/*
743f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
744f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
745f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
746f04f1d51SNélio Laranjeiro 				 */
7478fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
7488fcd6c2cSNélio Laranjeiro 
749f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
750f04f1d51SNélio Laranjeiro 					break;
751f04f1d51SNélio Laranjeiro 				max_wqe -= n;
7525f44cfd0SYongseok Koh 				if (tso) {
7535f44cfd0SYongseok Koh 					assert(inl == 0);
7546963ae8bSYongseok Koh 					inl = rte_cpu_to_be_32(copy_b |
7556b30a6a8SShachar Beiser 							       MLX5_INLINE_SEG);
7563f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
7573f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
7583f13f8c2SShahaf Shuler 					raw += sizeof(inl);
7593f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
7603f13f8c2SShahaf Shuler 				}
7616579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
7626579c27cSNélio Laranjeiro 				addr += copy_b;
7636579c27cSNélio Laranjeiro 				length -= copy_b;
7646579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
7656579c27cSNélio Laranjeiro 			}
7666579c27cSNélio Laranjeiro 			/*
767786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
7686579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
7696579c27cSNélio Laranjeiro 			 */
7706579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
7716579c27cSNélio Laranjeiro 			if (length > 0) {
772f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
773f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
774f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
775f04f1d51SNélio Laranjeiro 						break;
776f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
777f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
778f04f1d51SNélio Laranjeiro 							   ds / 4);
779f04f1d51SNélio Laranjeiro 				} else {
7809a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
7816579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
7826579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
783f04f1d51SNélio Laranjeiro 				}
7846579c27cSNélio Laranjeiro 				goto use_dseg;
7856579c27cSNélio Laranjeiro 			} else if (!segs_n) {
7866579c27cSNélio Laranjeiro 				goto next_pkt;
7876579c27cSNélio Laranjeiro 			} else {
7885f44cfd0SYongseok Koh 				/*
7895f44cfd0SYongseok Koh 				 * Further inline the next segment only for
7905f44cfd0SYongseok Koh 				 * non-TSO packets.
7915f44cfd0SYongseok Koh 				 */
7925f44cfd0SYongseok Koh 				if (!tso) {
793f895536bSYongseok Koh 					raw += copy_b;
794f895536bSYongseok Koh 					inline_room -= copy_b;
7955f44cfd0SYongseok Koh 				} else {
7965f44cfd0SYongseok Koh 					inline_room = 0;
7975f44cfd0SYongseok Koh 				}
7985f44cfd0SYongseok Koh 				/* Move to the next segment. */
799f895536bSYongseok Koh 				--segs_n;
800f895536bSYongseok Koh 				buf = buf->next;
801f895536bSYongseok Koh 				assert(buf);
802f895536bSYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
803f895536bSYongseok Koh 				length = DATA_LEN(buf);
804f895536bSYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
805f895536bSYongseok Koh 				total_length += length;
806f895536bSYongseok Koh #endif
807f895536bSYongseok Koh 				(*txq->elts)[++elts_head & elts_m] = buf;
808f895536bSYongseok Koh 				goto pkt_inline;
8096579c27cSNélio Laranjeiro 			}
8106579c27cSNélio Laranjeiro 		} else {
8116579c27cSNélio Laranjeiro 			/*
8126579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
8136579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
8146579c27cSNélio Laranjeiro 			 */
8159a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
8166579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
8176579c27cSNélio Laranjeiro 			ds = 3;
8186579c27cSNélio Laranjeiro use_dseg:
8196579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
8206bf10ab6SMoti Haimovsky 			addr_64 = rte_cpu_to_be_64(addr);
8219a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
8226b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
8236cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
8246bf10ab6SMoti Haimovsky 				addr_64,
8256bf10ab6SMoti Haimovsky 				addr_64 >> 32,
8266579c27cSNélio Laranjeiro 			};
8276579c27cSNélio Laranjeiro 			++ds;
8286579c27cSNélio Laranjeiro 			if (!segs_n)
8296579c27cSNélio Laranjeiro 				goto next_pkt;
8306579c27cSNélio Laranjeiro 		}
8316579c27cSNélio Laranjeiro next_seg:
8326579c27cSNélio Laranjeiro 		assert(buf);
8336579c27cSNélio Laranjeiro 		assert(ds);
8346579c27cSNélio Laranjeiro 		assert(wqe);
835a5bf6af9SAdrien Mazarguil 		/*
836a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
837a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
838a5bf6af9SAdrien Mazarguil 		 * of data segment size.
839a5bf6af9SAdrien Mazarguil 		 */
8408688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
8416579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
842f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
843f04f1d51SNélio Laranjeiro 				break;
8449a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
845f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
846f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
847f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
8486579c27cSNélio Laranjeiro 		} else {
849a5bf6af9SAdrien Mazarguil 			++dseg;
8506579c27cSNélio Laranjeiro 		}
851a5bf6af9SAdrien Mazarguil 		++ds;
852a5bf6af9SAdrien Mazarguil 		buf = buf->next;
853a5bf6af9SAdrien Mazarguil 		assert(buf);
8546579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
855a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
8566579c27cSNélio Laranjeiro 		total_length += length;
857a5bf6af9SAdrien Mazarguil #endif
8586579c27cSNélio Laranjeiro 		/* Store segment information. */
8596bf10ab6SMoti Haimovsky 		addr_64 = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t));
8609a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
8616b30a6a8SShachar Beiser 			rte_cpu_to_be_32(length),
8626cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
8636bf10ab6SMoti Haimovsky 			addr_64,
8646bf10ab6SMoti Haimovsky 			addr_64 >> 32,
8656579c27cSNélio Laranjeiro 		};
8668c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
867f895536bSYongseok Koh 		if (--segs_n)
8686579c27cSNélio Laranjeiro 			goto next_seg;
8696579c27cSNélio Laranjeiro next_pkt:
870883ce172SShahaf Shuler 		if (ds > MLX5_DSEG_MAX) {
871883ce172SShahaf Shuler 			txq->stats.oerrors++;
872883ce172SShahaf Shuler 			break;
873883ce172SShahaf Shuler 		}
8748c819a69SYongseok Koh 		++elts_head;
8753730e6c6SYongseok Koh 		++pkts;
8766579c27cSNélio Laranjeiro 		++i;
877f895536bSYongseok Koh 		j += sg;
878b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
8793f13f8c2SShahaf Shuler 		if (tso) {
8803f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
8816b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
8826b30a6a8SShachar Beiser 						 MLX5_OPCODE_TSO),
8836b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
8843f13f8c2SShahaf Shuler 				0,
8853f13f8c2SShahaf Shuler 				0,
8863f13f8c2SShahaf Shuler 			};
8873f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
8885f8ba81cSXueming Li 				swp_offsets,
8895f8ba81cSXueming Li 				cs_flags | (swp_types << 8) |
8905f8ba81cSXueming Li 				(rte_cpu_to_be_16(tso_segsz) << 16),
8916bd7fbd0SDekel Peled 				metadata,
8926b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(tso_header_sz),
8933f13f8c2SShahaf Shuler 			};
8943f13f8c2SShahaf Shuler 		} else {
8959a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
8966b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
8976b30a6a8SShachar Beiser 						 MLX5_OPCODE_SEND),
8986b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
8999a7fa9f7SNélio Laranjeiro 				0,
9009a7fa9f7SNélio Laranjeiro 				0,
9019a7fa9f7SNélio Laranjeiro 			};
9029a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
9035f8ba81cSXueming Li 				swp_offsets,
9045f8ba81cSXueming Li 				cs_flags | (swp_types << 8),
9056bd7fbd0SDekel Peled 				metadata,
9066b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz),
9079a7fa9f7SNélio Laranjeiro 			};
9083f13f8c2SShahaf Shuler 		}
9093f13f8c2SShahaf Shuler next_wqe:
9106579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
911ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
912ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
91387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
914573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
9156579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
91687011737SAdrien Mazarguil #endif
9173730e6c6SYongseok Koh 	} while (i < pkts_n);
9182e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
9193f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
9202e22920bSAdrien Mazarguil 		return 0;
9218c819a69SYongseok Koh 	txq->elts_head += (i + j);
922c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
9233f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
924c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
925c618e7e8SYongseok Koh 		/* A CQE slot must always be available. */
926c618e7e8SYongseok Koh 		assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci));
927c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
9286b30a6a8SShachar Beiser 		last_wqe->ctrl2 = rte_cpu_to_be_32(8);
929c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
930ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
931c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
932c305090bSAdrien Mazarguil 	} else {
933c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
934c305090bSAdrien Mazarguil 	}
93587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
93687011737SAdrien Mazarguil 	/* Increment sent packets counter. */
93787011737SAdrien Mazarguil 	txq->stats.opackets += i;
93887011737SAdrien Mazarguil #endif
9392e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
940ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
9412e22920bSAdrien Mazarguil 	return i;
9422e22920bSAdrien Mazarguil }
9432e22920bSAdrien Mazarguil 
9442e22920bSAdrien Mazarguil /**
945230189d9SNélio Laranjeiro  * Open a MPW session.
946230189d9SNélio Laranjeiro  *
947230189d9SNélio Laranjeiro  * @param txq
948230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
949230189d9SNélio Laranjeiro  * @param mpw
950230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
951230189d9SNélio Laranjeiro  * @param length
952230189d9SNélio Laranjeiro  *   Packet length.
953230189d9SNélio Laranjeiro  */
954230189d9SNélio Laranjeiro static inline void
955991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length)
956230189d9SNélio Laranjeiro {
957a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
958230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
959230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
960fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
961230189d9SNélio Laranjeiro 
962230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
963230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
964230189d9SNélio Laranjeiro 	mpw->len = length;
965230189d9SNélio Laranjeiro 	mpw->total_len = 0;
966fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9676b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
9688688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9698688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9708688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9716bd7fbd0SDekel Peled 	mpw->wqe->eseg.flow_table_metadata = 0;
9726b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
9736b30a6a8SShachar Beiser 					     (txq->wqe_ci << 8) |
9746b30a6a8SShachar Beiser 					     MLX5_OPCODE_TSO);
9758688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9768688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9778688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
9788688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
9798688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
9808688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
981230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
982230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
983230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
984230189d9SNélio Laranjeiro }
985230189d9SNélio Laranjeiro 
986230189d9SNélio Laranjeiro /**
987230189d9SNélio Laranjeiro  * Close a MPW session.
988230189d9SNélio Laranjeiro  *
989230189d9SNélio Laranjeiro  * @param txq
990230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
991230189d9SNélio Laranjeiro  * @param mpw
992230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
993230189d9SNélio Laranjeiro  */
994230189d9SNélio Laranjeiro static inline void
995991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
996230189d9SNélio Laranjeiro {
997230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
998230189d9SNélio Laranjeiro 
999230189d9SNélio Laranjeiro 	/*
1000230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
1001230189d9SNélio Laranjeiro 	 * count as 2.
1002230189d9SNélio Laranjeiro 	 */
10036b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num));
1004230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
1005230189d9SNélio Laranjeiro 	if (num < 3)
1006230189d9SNélio Laranjeiro 		++txq->wqe_ci;
1007230189d9SNélio Laranjeiro 	else
1008230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
1009fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1010fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1011230189d9SNélio Laranjeiro }
1012230189d9SNélio Laranjeiro 
1013230189d9SNélio Laranjeiro /**
1014230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
1015230189d9SNélio Laranjeiro  *
1016230189d9SNélio Laranjeiro  * @param dpdk_txq
1017230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1018230189d9SNélio Laranjeiro  * @param[in] pkts
1019230189d9SNélio Laranjeiro  *   Packets to transmit.
1020230189d9SNélio Laranjeiro  * @param pkts_n
1021230189d9SNélio Laranjeiro  *   Number of packets in array.
1022230189d9SNélio Laranjeiro  *
1023230189d9SNélio Laranjeiro  * @return
1024230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1025230189d9SNélio Laranjeiro  */
1026230189d9SNélio Laranjeiro uint16_t
1027230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
1028230189d9SNélio Laranjeiro {
1029991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
1030230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
10318c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
10328c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1033c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1034a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
10358c819a69SYongseok Koh 	uint16_t max_elts;
1036f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1037230189d9SNélio Laranjeiro 	unsigned int comp;
1038230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1039230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1040230189d9SNélio Laranjeiro 	};
1041230189d9SNélio Laranjeiro 
1042c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1043c3d62cc9SAdrien Mazarguil 		return 0;
1044230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1045fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1046fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1047230189d9SNélio Laranjeiro 	/* Start processing. */
10486cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
10498c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
1050f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
1051f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
1052f04f1d51SNélio Laranjeiro 		return 0;
1053c3d62cc9SAdrien Mazarguil 	do {
1054a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1055230189d9SNélio Laranjeiro 		uint32_t length;
1056a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
10574aa15eb1SNélio Laranjeiro 		uint32_t cs_flags;
10586bd7fbd0SDekel Peled 		rte_be32_t metadata;
1059230189d9SNélio Laranjeiro 
1060c3d62cc9SAdrien Mazarguil 		/*
1061c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1062c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1063c3d62cc9SAdrien Mazarguil 		 */
1064a5bf6af9SAdrien Mazarguil 		assert(segs_n);
10658c819a69SYongseok Koh 		if (max_elts < segs_n)
1066c3d62cc9SAdrien Mazarguil 			break;
1067a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
106824c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
106924c14430SShahaf Shuler 			txq->stats.oerrors++;
1070a5bf6af9SAdrien Mazarguil 			break;
107124c14430SShahaf Shuler 		}
10728c819a69SYongseok Koh 		max_elts -= segs_n;
1073c3d62cc9SAdrien Mazarguil 		--pkts_n;
10745f8ba81cSXueming Li 		cs_flags = txq_ol_cksum_to_cs(buf);
10756bd7fbd0SDekel Peled 		/* Copy metadata from mbuf if valid */
10766bd7fbd0SDekel Peled 		metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata :
10776bd7fbd0SDekel Peled 							     0;
1078a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1079a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1080a5bf6af9SAdrien Mazarguil 		assert(length);
1081230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1082230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
1083230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
1084a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
10856bd7fbd0SDekel Peled 		     (mpw.wqe->eseg.flow_table_metadata != metadata) ||
10868688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
1087230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
1088230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1089f04f1d51SNélio Laranjeiro 			/*
1090f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
1091f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
1092f04f1d51SNélio Laranjeiro 			 * resources.
1093f04f1d51SNélio Laranjeiro 			 */
1094f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
1095f04f1d51SNélio Laranjeiro 				break;
1096f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
1097230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
10988688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
10996bd7fbd0SDekel Peled 			mpw.wqe->eseg.flow_table_metadata = metadata;
1100230189d9SNélio Laranjeiro 		}
1101a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1102a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1103a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1104a5bf6af9SAdrien Mazarguil 		length = 0;
1105a5bf6af9SAdrien Mazarguil #endif
1106a5bf6af9SAdrien Mazarguil 		do {
1107a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
1108a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
1109a5bf6af9SAdrien Mazarguil 
1110a5bf6af9SAdrien Mazarguil 			assert(buf);
11118c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1112230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
1113a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1114230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
11156b30a6a8SShachar Beiser 				.byte_count = rte_cpu_to_be_32(DATA_LEN(buf)),
11166cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
11176b30a6a8SShachar Beiser 				.addr = rte_cpu_to_be_64(addr),
1118230189d9SNélio Laranjeiro 			};
1119a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1120a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
1121a5bf6af9SAdrien Mazarguil #endif
1122a5bf6af9SAdrien Mazarguil 			buf = buf->next;
1123230189d9SNélio Laranjeiro 			++mpw.pkts_n;
1124a5bf6af9SAdrien Mazarguil 			++j;
1125a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
1126a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
1127230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1128230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
1129230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1130230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1131230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1132230189d9SNélio Laranjeiro #endif
1133c3d62cc9SAdrien Mazarguil 		++i;
1134c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1135230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1136230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1137230189d9SNélio Laranjeiro 		return 0;
1138230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1139a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1140a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1141230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
11428688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1143230189d9SNélio Laranjeiro 
1144c618e7e8SYongseok Koh 		/* A CQE slot must always be available. */
1145c618e7e8SYongseok Koh 		assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci));
1146230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
11476b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
1148230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
11498688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1150230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1151230189d9SNélio Laranjeiro 	} else {
1152230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1153230189d9SNélio Laranjeiro 	}
1154230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1155230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1156230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1157230189d9SNélio Laranjeiro #endif
1158230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1159230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
1160230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
116130807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1162230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1163230189d9SNélio Laranjeiro 	return i;
1164230189d9SNélio Laranjeiro }
1165230189d9SNélio Laranjeiro 
1166230189d9SNélio Laranjeiro /**
1167230189d9SNélio Laranjeiro  * Open a MPW inline session.
1168230189d9SNélio Laranjeiro  *
1169230189d9SNélio Laranjeiro  * @param txq
1170230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
1171230189d9SNélio Laranjeiro  * @param mpw
1172230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1173230189d9SNélio Laranjeiro  * @param length
1174230189d9SNélio Laranjeiro  *   Packet length.
1175230189d9SNélio Laranjeiro  */
1176230189d9SNélio Laranjeiro static inline void
1177991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw,
1178991b04f6SNélio Laranjeiro 		    uint32_t length)
1179230189d9SNélio Laranjeiro {
1180a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
11818688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
1182230189d9SNélio Laranjeiro 
1183230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
1184230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
1185230189d9SNélio Laranjeiro 	mpw->len = length;
1186230189d9SNélio Laranjeiro 	mpw->total_len = 0;
1187fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
11886b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
1189230189d9SNélio Laranjeiro 					     (txq->wqe_ci << 8) |
1190c904ae25SNélio Laranjeiro 					     MLX5_OPCODE_TSO);
11918688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
11928688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
11936b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
11948688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
11958688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
11968688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
11978688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
11986bd7fbd0SDekel Peled 	mpw->wqe->eseg.flow_table_metadata = 0;
11998688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
12008688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
12018688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
1202230189d9SNélio Laranjeiro }
1203230189d9SNélio Laranjeiro 
1204230189d9SNélio Laranjeiro /**
1205230189d9SNélio Laranjeiro  * Close a MPW inline session.
1206230189d9SNélio Laranjeiro  *
1207230189d9SNélio Laranjeiro  * @param txq
1208230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
1209230189d9SNélio Laranjeiro  * @param mpw
1210230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1211230189d9SNélio Laranjeiro  */
1212230189d9SNélio Laranjeiro static inline void
1213991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
1214230189d9SNélio Laranjeiro {
1215230189d9SNélio Laranjeiro 	unsigned int size;
12168688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
12178688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
1218230189d9SNélio Laranjeiro 
12198688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
1220230189d9SNélio Laranjeiro 	/*
1221230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
1222230189d9SNélio Laranjeiro 	 * count as 2.
1223230189d9SNélio Laranjeiro 	 */
12246b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
12256b30a6a8SShachar Beiser 					     MLX5_WQE_DS(size));
1226230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
12276b30a6a8SShachar Beiser 	inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG);
12288688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1229230189d9SNélio Laranjeiro }
1230230189d9SNélio Laranjeiro 
1231230189d9SNélio Laranjeiro /**
1232230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1233230189d9SNélio Laranjeiro  *
1234230189d9SNélio Laranjeiro  * @param dpdk_txq
1235230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1236230189d9SNélio Laranjeiro  * @param[in] pkts
1237230189d9SNélio Laranjeiro  *   Packets to transmit.
1238230189d9SNélio Laranjeiro  * @param pkts_n
1239230189d9SNélio Laranjeiro  *   Number of packets in array.
1240230189d9SNélio Laranjeiro  *
1241230189d9SNélio Laranjeiro  * @return
1242230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1243230189d9SNélio Laranjeiro  */
1244230189d9SNélio Laranjeiro uint16_t
1245230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1246230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1247230189d9SNélio Laranjeiro {
1248991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
1249230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
12508c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
12518c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1252c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1253a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
12548c819a69SYongseok Koh 	uint16_t max_elts;
1255f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1256230189d9SNélio Laranjeiro 	unsigned int comp;
12570e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1258230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1259230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1260230189d9SNélio Laranjeiro 	};
1261f04f1d51SNélio Laranjeiro 	/*
1262f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1263f04f1d51SNélio Laranjeiro 	 * code.
1264f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1265f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1266f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1267f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1268f04f1d51SNélio Laranjeiro 	 */
1269f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1270f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1271f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1272f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1273230189d9SNélio Laranjeiro 
1274c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1275c3d62cc9SAdrien Mazarguil 		return 0;
1276230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1277fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1278fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1279230189d9SNélio Laranjeiro 	/* Start processing. */
12806cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
12818c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
1282c3d62cc9SAdrien Mazarguil 	do {
1283a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1284230189d9SNélio Laranjeiro 		uintptr_t addr;
1285230189d9SNélio Laranjeiro 		uint32_t length;
1286a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
12874aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
12886bd7fbd0SDekel Peled 		rte_be32_t metadata;
1289230189d9SNélio Laranjeiro 
1290c3d62cc9SAdrien Mazarguil 		/*
1291c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1292c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1293c3d62cc9SAdrien Mazarguil 		 */
1294a5bf6af9SAdrien Mazarguil 		assert(segs_n);
12958c819a69SYongseok Koh 		if (max_elts < segs_n)
1296c3d62cc9SAdrien Mazarguil 			break;
1297a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
129824c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
129924c14430SShahaf Shuler 			txq->stats.oerrors++;
1300a5bf6af9SAdrien Mazarguil 			break;
130124c14430SShahaf Shuler 		}
13028c819a69SYongseok Koh 		max_elts -= segs_n;
1303c3d62cc9SAdrien Mazarguil 		--pkts_n;
1304f04f1d51SNélio Laranjeiro 		/*
1305f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1306f04f1d51SNélio Laranjeiro 		 * iteration.
1307f04f1d51SNélio Laranjeiro 		 */
1308f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
13095f8ba81cSXueming Li 		cs_flags = txq_ol_cksum_to_cs(buf);
13106bd7fbd0SDekel Peled 		/* Copy metadata from mbuf if valid */
13116bd7fbd0SDekel Peled 		metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata :
13126bd7fbd0SDekel Peled 							     0;
1313a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1314a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1315230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1316230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1317230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1318a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
13196bd7fbd0SDekel Peled 			    (mpw.wqe->eseg.flow_table_metadata != metadata) ||
13208688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1321230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1322230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1323230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1324a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1325230189d9SNélio Laranjeiro 			    (length > inline_room) ||
13266bd7fbd0SDekel Peled 			    (mpw.wqe->eseg.flow_table_metadata != metadata) ||
13278688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1328230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
13290e8679fcSNélio Laranjeiro 				inline_room =
13300e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1331230189d9SNélio Laranjeiro 			}
1332230189d9SNélio Laranjeiro 		}
1333230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1334a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1335a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1336f04f1d51SNélio Laranjeiro 				/*
1337f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1338f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1339f04f1d51SNélio Laranjeiro 				 * such resources.
1340f04f1d51SNélio Laranjeiro 				 */
1341f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1342f04f1d51SNélio Laranjeiro 					break;
1343f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1344230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
13458688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
13466bd7fbd0SDekel Peled 				mpw.wqe->eseg.flow_table_metadata = metadata;
1347230189d9SNélio Laranjeiro 			} else {
1348f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1349f04f1d51SNélio Laranjeiro 					break;
1350f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1351230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
13528688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
13536bd7fbd0SDekel Peled 				mpw.wqe->eseg.flow_table_metadata = metadata;
1354230189d9SNélio Laranjeiro 			}
1355230189d9SNélio Laranjeiro 		}
1356a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1357a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1358230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
13590e8679fcSNélio Laranjeiro 			assert(inline_room ==
13600e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1361a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1362a5bf6af9SAdrien Mazarguil 			length = 0;
1363a5bf6af9SAdrien Mazarguil #endif
1364a5bf6af9SAdrien Mazarguil 			do {
1365230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1366230189d9SNélio Laranjeiro 
1367a5bf6af9SAdrien Mazarguil 				assert(buf);
13688c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1369230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1370a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1371230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
13726b30a6a8SShachar Beiser 					.byte_count =
13736b30a6a8SShachar Beiser 					       rte_cpu_to_be_32(DATA_LEN(buf)),
13746cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
13756b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
1376230189d9SNélio Laranjeiro 				};
1377a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1378a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1379a5bf6af9SAdrien Mazarguil #endif
1380a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1381230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1382a5bf6af9SAdrien Mazarguil 				++j;
1383a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1384a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1385230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1386230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1387230189d9SNélio Laranjeiro 		} else {
1388230189d9SNélio Laranjeiro 			unsigned int max;
1389230189d9SNélio Laranjeiro 
1390230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1391230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1392a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1393a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
13948c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1395230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1396fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1397fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1398fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1399230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1400230189d9SNélio Laranjeiro 			if (length > max) {
1401230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1402230189d9SNélio Laranjeiro 					   (void *)addr,
1403230189d9SNélio Laranjeiro 					   max);
1404fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1405230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1406230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1407230189d9SNélio Laranjeiro 					   length - max);
1408230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1409230189d9SNélio Laranjeiro 			} else {
1410230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1411230189d9SNélio Laranjeiro 					   (void *)addr,
1412230189d9SNélio Laranjeiro 					   length);
141316c64768SYongseok Koh 
141416c64768SYongseok Koh 				if (length == max)
141516c64768SYongseok Koh 					mpw.data.raw =
141616c64768SYongseok Koh 						(volatile void *)txq->wqes;
141716c64768SYongseok Koh 				else
1418230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1419230189d9SNélio Laranjeiro 			}
1420230189d9SNélio Laranjeiro 			++mpw.pkts_n;
142176bf1574SYongseok Koh 			mpw.total_len += length;
1422a5bf6af9SAdrien Mazarguil 			++j;
1423230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1424230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
14250e8679fcSNélio Laranjeiro 				inline_room =
14260e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1427230189d9SNélio Laranjeiro 			} else {
1428230189d9SNélio Laranjeiro 				inline_room -= length;
1429230189d9SNélio Laranjeiro 			}
1430230189d9SNélio Laranjeiro 		}
1431230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1432230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1433230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1434230189d9SNélio Laranjeiro #endif
1435c3d62cc9SAdrien Mazarguil 		++i;
1436c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1437230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1438230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1439230189d9SNélio Laranjeiro 		return 0;
1440230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1441a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1442a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1443230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
14448688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1445230189d9SNélio Laranjeiro 
1446c618e7e8SYongseok Koh 		/* A CQE slot must always be available. */
1447c618e7e8SYongseok Koh 		assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci));
1448230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
14496b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
1450230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
14518688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1452230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1453230189d9SNélio Laranjeiro 	} else {
1454230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1455230189d9SNélio Laranjeiro 	}
1456230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1457230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1458230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1459230189d9SNélio Laranjeiro #endif
1460230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1461230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1462230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1463230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1464230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
146530807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1466230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1467230189d9SNélio Laranjeiro 	return i;
1468230189d9SNélio Laranjeiro }
1469230189d9SNélio Laranjeiro 
1470230189d9SNélio Laranjeiro /**
14716ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
14726ce84bd8SYongseok Koh  *
14736ce84bd8SYongseok Koh  * @param txq
14746ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
14756ce84bd8SYongseok Koh  * @param mpw
14766ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
14776ce84bd8SYongseok Koh  * @param length
14786ce84bd8SYongseok Koh  *   Packet length.
14796ce84bd8SYongseok Koh  */
14806ce84bd8SYongseok Koh static inline void
1481991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding)
14826ce84bd8SYongseok Koh {
14836ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
14846ce84bd8SYongseok Koh 
14856ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
14866ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
14876ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
14886ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
14896b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] =
14906b30a6a8SShachar Beiser 		rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
14916ce84bd8SYongseok Koh 				 (txq->wqe_ci << 8) |
14926ce84bd8SYongseok Koh 				 MLX5_OPCODE_ENHANCED_MPSW);
14936ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
14946ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
14956ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
14966ce84bd8SYongseok Koh 	if (unlikely(padding)) {
14976ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
14986ce84bd8SYongseok Koh 
14996ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
15006b30a6a8SShachar Beiser 		*(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG);
15016ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
15026b30a6a8SShachar Beiser 			rte_cpu_to_be_32(MLX5_INLINE_SEG);
15036ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
15046ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
15056ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
15066ce84bd8SYongseok Koh 	} else {
15076ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
15086ce84bd8SYongseok Koh 	}
15096ce84bd8SYongseok Koh }
15106ce84bd8SYongseok Koh 
15116ce84bd8SYongseok Koh /**
15126ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
15136ce84bd8SYongseok Koh  *
15146ce84bd8SYongseok Koh  * @param txq
15156ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
15166ce84bd8SYongseok Koh  * @param mpw
15176ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
15186ce84bd8SYongseok Koh  *
15196ce84bd8SYongseok Koh  * @return
15206ce84bd8SYongseok Koh  *   Number of consumed WQEs.
15216ce84bd8SYongseok Koh  */
15226ce84bd8SYongseok Koh static inline uint16_t
1523991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
15246ce84bd8SYongseok Koh {
15256ce84bd8SYongseok Koh 	uint16_t ret;
15266ce84bd8SYongseok Koh 
15276ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
15286ce84bd8SYongseok Koh 	 * count as 2.
15296ce84bd8SYongseok Koh 	 */
15306b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
15316b30a6a8SShachar Beiser 					     MLX5_WQE_DS(mpw->total_len));
15326ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
15336ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
15346ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
15356ce84bd8SYongseok Koh 	return ret;
15366ce84bd8SYongseok Koh }
15376ce84bd8SYongseok Koh 
15386ce84bd8SYongseok Koh /**
15394b0d7b7fSYongseok Koh  * TX with Enhanced MPW support.
15406ce84bd8SYongseok Koh  *
15414b0d7b7fSYongseok Koh  * @param txq
15424b0d7b7fSYongseok Koh  *   Pointer to TX queue structure.
15436ce84bd8SYongseok Koh  * @param[in] pkts
15446ce84bd8SYongseok Koh  *   Packets to transmit.
15456ce84bd8SYongseok Koh  * @param pkts_n
15466ce84bd8SYongseok Koh  *   Number of packets in array.
15476ce84bd8SYongseok Koh  *
15486ce84bd8SYongseok Koh  * @return
15496ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
15506ce84bd8SYongseok Koh  */
15514b0d7b7fSYongseok Koh static inline uint16_t
15524b0d7b7fSYongseok Koh txq_burst_empw(struct mlx5_txq_data *txq, struct rte_mbuf **pkts,
15534b0d7b7fSYongseok Koh 	       uint16_t pkts_n)
15546ce84bd8SYongseok Koh {
15556ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
15568c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
15578c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
15586ce84bd8SYongseok Koh 	unsigned int i = 0;
15596ce84bd8SYongseok Koh 	unsigned int j = 0;
15608c819a69SYongseok Koh 	uint16_t max_elts;
15616ce84bd8SYongseok Koh 	uint16_t max_wqe;
15626ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
15636ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
15646ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
15656ce84bd8SYongseok Koh 	uint32_t inl_hdr;
15666bf10ab6SMoti Haimovsky 	uint64_t addr_64;
15676ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
15686ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
15696ce84bd8SYongseok Koh 	};
15706ce84bd8SYongseok Koh 
15716ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
15726ce84bd8SYongseok Koh 		return 0;
15736ce84bd8SYongseok Koh 	/* Start processing. */
15746cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
15756ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
15766ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
15776ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
15786ce84bd8SYongseok Koh 		return 0;
15796ce84bd8SYongseok Koh 	do {
15806ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
15816ce84bd8SYongseok Koh 		uintptr_t addr;
15826ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
15836ce84bd8SYongseok Koh 		uint32_t length;
15844aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
15856bd7fbd0SDekel Peled 		rte_be32_t metadata;
15866ce84bd8SYongseok Koh 
158748642ec5SYongseok Koh 		/* Multi-segmented packet is handled in slow-path outside. */
158848642ec5SYongseok Koh 		assert(NB_SEGS(buf) == 1);
158948642ec5SYongseok Koh 		/* Make sure there is enough room to store this packet. */
159048642ec5SYongseok Koh 		if (max_elts - j == 0)
15916ce84bd8SYongseok Koh 			break;
15925f8ba81cSXueming Li 		cs_flags = txq_ol_cksum_to_cs(buf);
15936bd7fbd0SDekel Peled 		/* Copy metadata from mbuf if valid */
15946bd7fbd0SDekel Peled 		metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata :
15956bd7fbd0SDekel Peled 							     0;
15966ce84bd8SYongseok Koh 		/* Retrieve packet information. */
15976ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
15986ce84bd8SYongseok Koh 		/* Start new session if:
15996ce84bd8SYongseok Koh 		 * - multi-segment packet
16006ce84bd8SYongseok Koh 		 * - no space left even for a dseg
16016ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
16026ce84bd8SYongseok Koh 		 * - cs_flag differs
16036ce84bd8SYongseok Koh 		 */
16046ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
160548642ec5SYongseok Koh 			if ((inl_pad + sizeof(struct mlx5_wqe_data_seg) >
16066ce84bd8SYongseok Koh 			     mpw_room) ||
16076ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
16086ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
16096ce84bd8SYongseok Koh 			     mpw_room) ||
16106bd7fbd0SDekel Peled 			     (mpw.wqe->eseg.flow_table_metadata != metadata) ||
16116ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
16126ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
16136ce84bd8SYongseok Koh 		}
16146ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
161548642ec5SYongseok Koh 			/* In Enhanced MPW, inline as much as the budget is
161648642ec5SYongseok Koh 			 * allowed. The remaining space is to be filled with
161748642ec5SYongseok Koh 			 * dsegs. If the title WQEBB isn't padded, it will have
161848642ec5SYongseok Koh 			 * 2 dsegs there.
16196ce84bd8SYongseok Koh 			 */
16206ce84bd8SYongseok Koh 			mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
16216ce84bd8SYongseok Koh 					   (max_inline ? max_inline :
16226ce84bd8SYongseok Koh 					    pkts_n * MLX5_WQE_DWORD_SIZE) +
16236ce84bd8SYongseok Koh 					   MLX5_WQE_SIZE);
162448642ec5SYongseok Koh 			if (unlikely(max_wqe * MLX5_WQE_SIZE < mpw_room))
16256ce84bd8SYongseok Koh 				break;
16266ce84bd8SYongseok Koh 			/* Don't pad the title WQEBB to not waste WQ. */
16276ce84bd8SYongseok Koh 			mlx5_empw_new(txq, &mpw, 0);
16286ce84bd8SYongseok Koh 			mpw_room -= mpw.total_len;
16296ce84bd8SYongseok Koh 			inl_pad = 0;
163048642ec5SYongseok Koh 			do_inline = length <= txq->inline_max_packet_sz &&
16316ce84bd8SYongseok Koh 				    sizeof(inl_hdr) + length <= mpw_room &&
16326ce84bd8SYongseok Koh 				    !txq->mpw_hdr_dseg;
16336ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
16346bd7fbd0SDekel Peled 			mpw.wqe->eseg.flow_table_metadata = metadata;
16356ce84bd8SYongseok Koh 		} else {
16366ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
16376ce84bd8SYongseok Koh 			 * Inlininig is possible when:
16386ce84bd8SYongseok Koh 			 * - length is less than configured value
16396ce84bd8SYongseok Koh 			 * - length fits for remaining space
16406ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
16416ce84bd8SYongseok Koh 			 */
16426ce84bd8SYongseok Koh 			do_inline =
16436ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
16446ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
16456ce84bd8SYongseok Koh 				 mpw_room &&
16466ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
16476ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
16486ce84bd8SYongseok Koh 		}
164924a8f524SYongseok Koh 		if (max_inline && do_inline) {
16506ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
16516ce84bd8SYongseok Koh 			unsigned int max;
16526ce84bd8SYongseok Koh 
16536ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
16546ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
16556b30a6a8SShachar Beiser 			inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG);
16566ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
16576ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16586ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
16596ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
16606ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
16616ce84bd8SYongseok Koh 			/* Copy inline header. */
16626ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16636ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
16646ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
16656ce84bd8SYongseok Koh 					  &inl_hdr,
16666ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
16676ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
16686ce84bd8SYongseok Koh 					  max);
16696ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
16706ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
16716ce84bd8SYongseok Koh 			/* Copy packet data. */
16726ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16736ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
16746ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
16756ce84bd8SYongseok Koh 					  (void *)addr,
16766ce84bd8SYongseok Koh 					  length,
16776ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
16786ce84bd8SYongseok Koh 					  max);
16796ce84bd8SYongseok Koh 			++mpw.pkts_n;
16806ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
16816ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
16826ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
16836ce84bd8SYongseok Koh 			 */
16846ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
16856ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
16866ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
16876ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
16886ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
16896ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
16906ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
16916ce84bd8SYongseok Koh 		} else {
16926ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
16936ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
16946ce84bd8SYongseok Koh 
16956ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
16966ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
16976ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
16986ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
16996ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
17006ce84bd8SYongseok Koh 						+ inl_pad)))
17016ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
17026ce84bd8SYongseok Koh 			else
17036ce84bd8SYongseok Koh 				dseg = (volatile void *)
17046ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
17056ce84bd8SYongseok Koh 					 inl_pad);
17068c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
17076bf10ab6SMoti Haimovsky 			addr_64 = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf,
1708f84411beSYongseok Koh 								    uintptr_t));
17096ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
17106b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
17116cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
17126bf10ab6SMoti Haimovsky 				addr_64,
17136bf10ab6SMoti Haimovsky 				addr_64 >> 32,
17146ce84bd8SYongseok Koh 			};
17156ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
17166ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
17176ce84bd8SYongseok Koh 			++j;
17186ce84bd8SYongseok Koh 			++mpw.pkts_n;
17196ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
17206ce84bd8SYongseok Koh 			inl_pad = 0;
17216ce84bd8SYongseok Koh 		}
17226ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
17236ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
17246ce84bd8SYongseok Koh 		txq->stats.obytes += length;
17256ce84bd8SYongseok Koh #endif
17266ce84bd8SYongseok Koh 		++i;
17276ce84bd8SYongseok Koh 	} while (i < pkts_n);
17286ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
17296ce84bd8SYongseok Koh 	if (unlikely(i == 0))
17306ce84bd8SYongseok Koh 		return 0;
17316ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
17326ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
17336ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
17346ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
17356ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
17366ce84bd8SYongseok Koh 
1737c618e7e8SYongseok Koh 		/* A CQE slot must always be available. */
1738c618e7e8SYongseok Koh 		assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci));
17396ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
17406b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
17416ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
17426ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
17436ce84bd8SYongseok Koh 		txq->elts_comp = 0;
17446ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
17456ce84bd8SYongseok Koh 	} else {
17466ce84bd8SYongseok Koh 		txq->elts_comp += j;
17476ce84bd8SYongseok Koh 	}
17486ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
17496ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
17506ce84bd8SYongseok Koh 	txq->stats.opackets += i;
17516ce84bd8SYongseok Koh #endif
17526ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
17536ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
17546ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
17556ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
17566ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
17576ce84bd8SYongseok Koh 	return i;
17586ce84bd8SYongseok Koh }
17596ce84bd8SYongseok Koh 
17606ce84bd8SYongseok Koh /**
17614b0d7b7fSYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
17624b0d7b7fSYongseok Koh  *
17634b0d7b7fSYongseok Koh  * @param dpdk_txq
17644b0d7b7fSYongseok Koh  *   Generic pointer to TX queue structure.
17654b0d7b7fSYongseok Koh  * @param[in] pkts
17664b0d7b7fSYongseok Koh  *   Packets to transmit.
17674b0d7b7fSYongseok Koh  * @param pkts_n
17684b0d7b7fSYongseok Koh  *   Number of packets in array.
17694b0d7b7fSYongseok Koh  *
17704b0d7b7fSYongseok Koh  * @return
17714b0d7b7fSYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
17724b0d7b7fSYongseok Koh  */
17734b0d7b7fSYongseok Koh uint16_t
17744b0d7b7fSYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
17754b0d7b7fSYongseok Koh {
17764b0d7b7fSYongseok Koh 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
17774b0d7b7fSYongseok Koh 	uint16_t nb_tx = 0;
17784b0d7b7fSYongseok Koh 
17794b0d7b7fSYongseok Koh 	while (pkts_n > nb_tx) {
17804b0d7b7fSYongseok Koh 		uint16_t n;
17814b0d7b7fSYongseok Koh 		uint16_t ret;
17824b0d7b7fSYongseok Koh 
17834b0d7b7fSYongseok Koh 		n = txq_count_contig_multi_seg(&pkts[nb_tx], pkts_n - nb_tx);
17844b0d7b7fSYongseok Koh 		if (n) {
17854b0d7b7fSYongseok Koh 			ret = mlx5_tx_burst(dpdk_txq, &pkts[nb_tx], n);
17864b0d7b7fSYongseok Koh 			if (!ret)
17874b0d7b7fSYongseok Koh 				break;
17884b0d7b7fSYongseok Koh 			nb_tx += ret;
17894b0d7b7fSYongseok Koh 		}
17904b0d7b7fSYongseok Koh 		n = txq_count_contig_single_seg(&pkts[nb_tx], pkts_n - nb_tx);
17914b0d7b7fSYongseok Koh 		if (n) {
17924b0d7b7fSYongseok Koh 			ret = txq_burst_empw(txq, &pkts[nb_tx], n);
17934b0d7b7fSYongseok Koh 			if (!ret)
17944b0d7b7fSYongseok Koh 				break;
17954b0d7b7fSYongseok Koh 			nb_tx += ret;
17964b0d7b7fSYongseok Koh 		}
17974b0d7b7fSYongseok Koh 	}
17984b0d7b7fSYongseok Koh 	return nb_tx;
17994b0d7b7fSYongseok Koh }
18004b0d7b7fSYongseok Koh 
18014b0d7b7fSYongseok Koh /**
180267fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
180367fa62bcSAdrien Mazarguil  *
18043cc08bc6SXueming Li  * @param[in] rxq
18053cc08bc6SXueming Li  *   Pointer to RX queue structure.
18066218063bSNélio Laranjeiro  * @param[in] cqe
18076218063bSNélio Laranjeiro  *   Pointer to CQE.
180867fa62bcSAdrien Mazarguil  *
180978a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
181078a38edfSJianfeng Tan  *
181167fa62bcSAdrien Mazarguil  * @return
181267fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
181367fa62bcSAdrien Mazarguil  */
181467fa62bcSAdrien Mazarguil static inline uint32_t
18153cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe)
181667fa62bcSAdrien Mazarguil {
1817ea16068cSYongseok Koh 	uint8_t idx;
1818ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
1819ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
182067fa62bcSAdrien Mazarguil 
1821ea16068cSYongseok Koh 	/*
1822ea16068cSYongseok Koh 	 * The index to the array should have:
1823ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
1824ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
1825ea16068cSYongseok Koh 	 * bit[5] = ip_frag
1826ea16068cSYongseok Koh 	 * bit[6] = tunneled
1827ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
1828ea16068cSYongseok Koh 	 */
1829ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
18303cc08bc6SXueming Li 	return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
183167fa62bcSAdrien Mazarguil }
183267fa62bcSAdrien Mazarguil 
183367fa62bcSAdrien Mazarguil /**
1834*6bb506ccSMatan Azrad  * Initialize Rx WQ and indexes.
1835*6bb506ccSMatan Azrad  *
1836*6bb506ccSMatan Azrad  * @param[in] rxq
1837*6bb506ccSMatan Azrad  *   Pointer to RX queue structure.
1838*6bb506ccSMatan Azrad  */
1839*6bb506ccSMatan Azrad void
1840*6bb506ccSMatan Azrad mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
1841*6bb506ccSMatan Azrad {
1842*6bb506ccSMatan Azrad 	const unsigned int wqe_n = 1 << rxq->elts_n;
1843*6bb506ccSMatan Azrad 	unsigned int i;
1844*6bb506ccSMatan Azrad 
1845*6bb506ccSMatan Azrad 	for (i = 0; (i != wqe_n); ++i) {
1846*6bb506ccSMatan Azrad 		volatile struct mlx5_wqe_data_seg *scat;
1847*6bb506ccSMatan Azrad 		uintptr_t addr;
1848*6bb506ccSMatan Azrad 		uint32_t byte_count;
1849*6bb506ccSMatan Azrad 
1850*6bb506ccSMatan Azrad 		if (mlx5_rxq_mprq_enabled(rxq)) {
1851*6bb506ccSMatan Azrad 			struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
1852*6bb506ccSMatan Azrad 
1853*6bb506ccSMatan Azrad 			scat = &((volatile struct mlx5_wqe_mprq *)
1854*6bb506ccSMatan Azrad 				rxq->wqes)[i].dseg;
1855*6bb506ccSMatan Azrad 			addr = (uintptr_t)mlx5_mprq_buf_addr(buf);
1856*6bb506ccSMatan Azrad 			byte_count = (1 << rxq->strd_sz_n) *
1857*6bb506ccSMatan Azrad 					(1 << rxq->strd_num_n);
1858*6bb506ccSMatan Azrad 		} else {
1859*6bb506ccSMatan Azrad 			struct rte_mbuf *buf = (*rxq->elts)[i];
1860*6bb506ccSMatan Azrad 
1861*6bb506ccSMatan Azrad 			scat = &((volatile struct mlx5_wqe_data_seg *)
1862*6bb506ccSMatan Azrad 					rxq->wqes)[i];
1863*6bb506ccSMatan Azrad 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1864*6bb506ccSMatan Azrad 			byte_count = DATA_LEN(buf);
1865*6bb506ccSMatan Azrad 		}
1866*6bb506ccSMatan Azrad 		/* scat->addr must be able to store a pointer. */
1867*6bb506ccSMatan Azrad 		assert(sizeof(scat->addr) >= sizeof(uintptr_t));
1868*6bb506ccSMatan Azrad 		*scat = (struct mlx5_wqe_data_seg){
1869*6bb506ccSMatan Azrad 			.addr = rte_cpu_to_be_64(addr),
1870*6bb506ccSMatan Azrad 			.byte_count = rte_cpu_to_be_32(byte_count),
1871*6bb506ccSMatan Azrad 			.lkey = mlx5_rx_addr2mr(rxq, addr),
1872*6bb506ccSMatan Azrad 		};
1873*6bb506ccSMatan Azrad 	}
1874*6bb506ccSMatan Azrad 	rxq->consumed_strd = 0;
1875*6bb506ccSMatan Azrad 	rxq->decompressed = 0;
1876*6bb506ccSMatan Azrad 	rxq->rq_pi = 0;
1877*6bb506ccSMatan Azrad 	rxq->zip = (struct rxq_zip){
1878*6bb506ccSMatan Azrad 		.ai = 0,
1879*6bb506ccSMatan Azrad 	};
1880*6bb506ccSMatan Azrad 	/* Update doorbell counter. */
1881*6bb506ccSMatan Azrad 	rxq->rq_ci = wqe_n >> rxq->sges_n;
1882*6bb506ccSMatan Azrad 	rte_cio_wmb();
1883*6bb506ccSMatan Azrad 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1884*6bb506ccSMatan Azrad }
1885*6bb506ccSMatan Azrad 
1886*6bb506ccSMatan Azrad /**
188799c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
188899c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
188999c12dccSNélio Laranjeiro  * been processed.
189099c12dccSNélio Laranjeiro  *
189199c12dccSNélio Laranjeiro  * @param rxq
189299c12dccSNélio Laranjeiro  *   Pointer to RX queue.
189399c12dccSNélio Laranjeiro  * @param cqe
189499c12dccSNélio Laranjeiro  *   CQE to process.
18952e633f1fSYongseok Koh  * @param[out] mcqe
18962e633f1fSYongseok Koh  *   Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
18972e633f1fSYongseok Koh  *   written.
189899c12dccSNélio Laranjeiro  *
189999c12dccSNélio Laranjeiro  * @return
190099c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
190199c12dccSNélio Laranjeiro  *   with error.
190299c12dccSNélio Laranjeiro  */
190399c12dccSNélio Laranjeiro static inline int
190478142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
19052e633f1fSYongseok Koh 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe)
190699c12dccSNélio Laranjeiro {
190799c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
190899c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
190999c12dccSNélio Laranjeiro 	int len = 0;
1910d2e842d0SYongseok Koh 	uint16_t idx, end;
191199c12dccSNélio Laranjeiro 
191299c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
191399c12dccSNélio Laranjeiro 	if (zip->ai) {
191499c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
191599c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
19164aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
191799c12dccSNélio Laranjeiro 
19186b30a6a8SShachar Beiser 		len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
19192e633f1fSYongseok Koh 		*mcqe = &(*mc)[zip->ai & 7];
192099c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1921d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1922d2e842d0SYongseok Koh 			idx = zip->ca;
1923d2e842d0SYongseok Koh 			end = zip->na;
1924d2e842d0SYongseok Koh 			while (idx != end) {
1925d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1926d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1927d2e842d0SYongseok Koh 				++idx;
1928d2e842d0SYongseok Koh 			}
192999c12dccSNélio Laranjeiro 			/*
193099c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
193199c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
193299c12dccSNélio Laranjeiro 			 * ring for software use.
193399c12dccSNélio Laranjeiro 			 */
193499c12dccSNélio Laranjeiro 			zip->ca = zip->na;
193599c12dccSNélio Laranjeiro 			zip->na += 8;
193699c12dccSNélio Laranjeiro 		}
193799c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1938d2e842d0SYongseok Koh 			/* Invalidate the rest */
1939d2e842d0SYongseok Koh 			idx = zip->ca;
1940d2e842d0SYongseok Koh 			end = zip->cq_ci;
194199c12dccSNélio Laranjeiro 
194299c12dccSNélio Laranjeiro 			while (idx != end) {
194397267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
194499c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
194599c12dccSNélio Laranjeiro 				++idx;
194699c12dccSNélio Laranjeiro 			}
194799c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
194899c12dccSNélio Laranjeiro 			zip->ai = 0;
194999c12dccSNélio Laranjeiro 		}
195099c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
195199c12dccSNélio Laranjeiro 	} else {
195299c12dccSNélio Laranjeiro 		int ret;
195399c12dccSNélio Laranjeiro 		int8_t op_own;
195499c12dccSNélio Laranjeiro 
195597267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
195699c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
195799c12dccSNélio Laranjeiro 			return 0;
195899c12dccSNélio Laranjeiro 		++rxq->cq_ci;
195999c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
19601742c2d9SYongseok Koh 		rte_cio_rmb();
196199c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
196299c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
196399c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
196499c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
19654aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
196699c12dccSNélio Laranjeiro 
196799c12dccSNélio Laranjeiro 			/* Fix endianness. */
19686b30a6a8SShachar Beiser 			zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
196999c12dccSNélio Laranjeiro 			/*
197099c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
197199c12dccSNélio Laranjeiro 			 * check_cqe64().
197299c12dccSNélio Laranjeiro 			 *
197399c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
197499c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
197599c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
197699c12dccSNélio Laranjeiro 			 */
1977d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
197899c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
197999c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
198099c12dccSNélio Laranjeiro 			--rxq->cq_ci;
198199c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
198299c12dccSNélio Laranjeiro 			/* Get packet size to return. */
19836b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
19842e633f1fSYongseok Koh 			*mcqe = &(*mc)[0];
198599c12dccSNélio Laranjeiro 			zip->ai = 1;
1986d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1987d2e842d0SYongseok Koh 			idx = zip->ca;
1988d2e842d0SYongseok Koh 			end = zip->cq_ci;
1989d2e842d0SYongseok Koh 			while (idx != end) {
1990d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1991d2e842d0SYongseok Koh 				++idx;
1992d2e842d0SYongseok Koh 			}
199399c12dccSNélio Laranjeiro 		} else {
19946b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32(cqe->byte_cnt);
199599c12dccSNélio Laranjeiro 		}
199699c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
199799c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
199899c12dccSNélio Laranjeiro 			return -1;
199999c12dccSNélio Laranjeiro 	}
200099c12dccSNélio Laranjeiro 	return len;
200199c12dccSNélio Laranjeiro }
200299c12dccSNélio Laranjeiro 
200399c12dccSNélio Laranjeiro /**
200467fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
200567fa62bcSAdrien Mazarguil  *
20066218063bSNélio Laranjeiro  * @param[in] cqe
20076218063bSNélio Laranjeiro  *   Pointer to CQE.
200867fa62bcSAdrien Mazarguil  *
200967fa62bcSAdrien Mazarguil  * @return
201067fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
201167fa62bcSAdrien Mazarguil  */
201267fa62bcSAdrien Mazarguil static inline uint32_t
20136ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
201467fa62bcSAdrien Mazarguil {
201567fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
20166b30a6a8SShachar Beiser 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
201767fa62bcSAdrien Mazarguil 
20180603df73SNélio Laranjeiro 	ol_flags =
20190603df73SNélio Laranjeiro 		TRANSPOSE(flags,
20200603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
20210603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
20220603df73SNélio Laranjeiro 		TRANSPOSE(flags,
20230603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
202483e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
202567fa62bcSAdrien Mazarguil 	return ol_flags;
202667fa62bcSAdrien Mazarguil }
202767fa62bcSAdrien Mazarguil 
202867fa62bcSAdrien Mazarguil /**
20293e1f82a1SYongseok Koh  * Fill in mbuf fields from RX completion flags.
20303e1f82a1SYongseok Koh  * Note that pkt->ol_flags should be initialized outside of this function.
20313e1f82a1SYongseok Koh  *
20323e1f82a1SYongseok Koh  * @param rxq
20333e1f82a1SYongseok Koh  *   Pointer to RX queue.
20343e1f82a1SYongseok Koh  * @param pkt
20353e1f82a1SYongseok Koh  *   mbuf to fill.
20363e1f82a1SYongseok Koh  * @param cqe
20373e1f82a1SYongseok Koh  *   CQE to process.
20383e1f82a1SYongseok Koh  * @param rss_hash_res
20393e1f82a1SYongseok Koh  *   Packet RSS Hash result.
20403e1f82a1SYongseok Koh  */
20413e1f82a1SYongseok Koh static inline void
20423e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
20433e1f82a1SYongseok Koh 	       volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res)
20443e1f82a1SYongseok Koh {
20453e1f82a1SYongseok Koh 	/* Update packet information. */
20463e1f82a1SYongseok Koh 	pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe);
20473e1f82a1SYongseok Koh 	if (rss_hash_res && rxq->rss_hash) {
20483e1f82a1SYongseok Koh 		pkt->hash.rss = rss_hash_res;
20493e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_RSS_HASH;
20503e1f82a1SYongseok Koh 	}
20513e1f82a1SYongseok Koh 	if (rxq->mark && MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
20523e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_FDIR;
20533e1f82a1SYongseok Koh 		if (cqe->sop_drop_qpn !=
20543e1f82a1SYongseok Koh 		    rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
20553e1f82a1SYongseok Koh 			uint32_t mark = cqe->sop_drop_qpn;
20563e1f82a1SYongseok Koh 
20573e1f82a1SYongseok Koh 			pkt->ol_flags |= PKT_RX_FDIR_ID;
20583e1f82a1SYongseok Koh 			pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
20593e1f82a1SYongseok Koh 		}
20603e1f82a1SYongseok Koh 	}
20613e1f82a1SYongseok Koh 	if (rxq->csum)
20623e1f82a1SYongseok Koh 		pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
20633e1f82a1SYongseok Koh 	if (rxq->vlan_strip &&
20643e1f82a1SYongseok Koh 	    (cqe->hdr_type_etc & rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
20653e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
20663e1f82a1SYongseok Koh 		pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
20673e1f82a1SYongseok Koh 	}
20683e1f82a1SYongseok Koh 	if (rxq->hw_timestamp) {
20693e1f82a1SYongseok Koh 		pkt->timestamp = rte_be_to_cpu_64(cqe->timestamp);
20703e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_TIMESTAMP;
20713e1f82a1SYongseok Koh 	}
20723e1f82a1SYongseok Koh }
20733e1f82a1SYongseok Koh 
20743e1f82a1SYongseok Koh /**
20752e22920bSAdrien Mazarguil  * DPDK callback for RX.
20762e22920bSAdrien Mazarguil  *
20772e22920bSAdrien Mazarguil  * @param dpdk_rxq
20782e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
20792e22920bSAdrien Mazarguil  * @param[out] pkts
20802e22920bSAdrien Mazarguil  *   Array to store received packets.
20812e22920bSAdrien Mazarguil  * @param pkts_n
20822e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
20832e22920bSAdrien Mazarguil  *
20842e22920bSAdrien Mazarguil  * @return
20852e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
20862e22920bSAdrien Mazarguil  */
20872e22920bSAdrien Mazarguil uint16_t
20882e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
20892e22920bSAdrien Mazarguil {
209078142aacSNélio Laranjeiro 	struct mlx5_rxq_data *rxq = dpdk_rxq;
2091b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
2092e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
20939964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
20949964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
20959964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
209697267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
209797267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
20989964b965SNélio Laranjeiro 	unsigned int i = 0;
20999964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
21004e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
21012e22920bSAdrien Mazarguil 
21029964b965SNélio Laranjeiro 	while (pkts_n) {
21039964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
21047d6bf6b8SYongseok Koh 		volatile struct mlx5_wqe_data_seg *wqe =
21057d6bf6b8SYongseok Koh 			&((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
21069964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
21072e633f1fSYongseok Koh 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
21082e633f1fSYongseok Koh 		uint32_t rss_hash_res;
21099964b965SNélio Laranjeiro 
21109964b965SNélio Laranjeiro 		if (pkt)
21119964b965SNélio Laranjeiro 			NEXT(seg) = rep;
21129964b965SNélio Laranjeiro 		seg = rep;
21139964b965SNélio Laranjeiro 		rte_prefetch0(seg);
21146218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
21159964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
2116fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
21172e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
211815a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
211915a756b6SSagi Grimberg 			if (!pkt) {
212015a756b6SSagi Grimberg 				/*
212115a756b6SSagi Grimberg 				 * no buffers before we even started,
212215a756b6SSagi Grimberg 				 * bail out silently.
212315a756b6SSagi Grimberg 				 */
212415a756b6SSagi Grimberg 				break;
212515a756b6SSagi Grimberg 			}
2126a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
2127a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
2128fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
21298f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
21308f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
21311f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
2132fe5fe382SNélio Laranjeiro 				pkt = rep;
21339964b965SNélio Laranjeiro 			}
21346218063bSNélio Laranjeiro 			break;
21352e22920bSAdrien Mazarguil 		}
21369964b965SNélio Laranjeiro 		if (!pkt) {
213797267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
21382e633f1fSYongseok Koh 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe);
2139ecf60761SNélio Laranjeiro 			if (!len) {
21401f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
21416218063bSNélio Laranjeiro 				break;
21426218063bSNélio Laranjeiro 			}
214399c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
214499c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
21451f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
214699c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
214799c12dccSNélio Laranjeiro 				goto skip;
214899c12dccSNélio Laranjeiro 			}
21499964b965SNélio Laranjeiro 			pkt = seg;
21509964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
21510ac64846SMaxime Leroy 			pkt->ol_flags = 0;
21522e633f1fSYongseok Koh 			/* If compressed, take hash result from mini-CQE. */
21532e633f1fSYongseok Koh 			rss_hash_res = rte_be_to_cpu_32(mcqe == NULL ?
21542e633f1fSYongseok Koh 							cqe->rx_hash_res :
21552e633f1fSYongseok Koh 							mcqe->rx_hash_result);
21563e1f82a1SYongseok Koh 			rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
21576218063bSNélio Laranjeiro 			if (rxq->crc_present)
215835b2d13fSOlivier Matz 				len -= RTE_ETHER_CRC_LEN;
21596218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
21609964b965SNélio Laranjeiro 		}
21619964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
21629964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
21639964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
21649964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
21659964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
21669964b965SNélio Laranjeiro 		/*
21679964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
21689964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
21699964b965SNélio Laranjeiro 		 * changes.
21709964b965SNélio Laranjeiro 		 */
21716b30a6a8SShachar Beiser 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
2172974f1e7eSYongseok Koh 		/* If there's only one MR, no need to replace LKey in WQE. */
2173974f1e7eSYongseok Koh 		if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
2174974f1e7eSYongseok Koh 			wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
21759964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
21769964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
21779964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
21789964b965SNélio Laranjeiro 			++rq_ci;
21799964b965SNélio Laranjeiro 			continue;
21809964b965SNélio Laranjeiro 		}
21819964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
218287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
218387011737SAdrien Mazarguil 		/* Increment bytes counter. */
21849964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
218587011737SAdrien Mazarguil #endif
21866218063bSNélio Laranjeiro 		/* Return packet. */
21876218063bSNélio Laranjeiro 		*(pkts++) = pkt;
21889964b965SNélio Laranjeiro 		pkt = NULL;
21899964b965SNélio Laranjeiro 		--pkts_n;
21909964b965SNélio Laranjeiro 		++i;
219199c12dccSNélio Laranjeiro skip:
21929964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
21939964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
21946218063bSNélio Laranjeiro 		++rq_ci;
21959964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
21962e22920bSAdrien Mazarguil 	}
21979964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
21982e22920bSAdrien Mazarguil 		return 0;
21996218063bSNélio Laranjeiro 	/* Update the consumer index. */
22009964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
22014fe7f662SYongseok Koh 	rte_cio_wmb();
22026b30a6a8SShachar Beiser 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
22034fe7f662SYongseok Koh 	rte_cio_wmb();
22046b30a6a8SShachar Beiser 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
220587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
220687011737SAdrien Mazarguil 	/* Increment packets counter. */
22079964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
220887011737SAdrien Mazarguil #endif
22099964b965SNélio Laranjeiro 	return i;
22102e22920bSAdrien Mazarguil }
22112e22920bSAdrien Mazarguil 
22127d6bf6b8SYongseok Koh void
22137d6bf6b8SYongseok Koh mlx5_mprq_buf_free_cb(void *addr __rte_unused, void *opaque)
22147d6bf6b8SYongseok Koh {
22157d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *buf = opaque;
22167d6bf6b8SYongseok Koh 
22177d6bf6b8SYongseok Koh 	if (rte_atomic16_read(&buf->refcnt) == 1) {
22187d6bf6b8SYongseok Koh 		rte_mempool_put(buf->mp, buf);
22197d6bf6b8SYongseok Koh 	} else if (rte_atomic16_add_return(&buf->refcnt, -1) == 0) {
22207d6bf6b8SYongseok Koh 		rte_atomic16_set(&buf->refcnt, 1);
22217d6bf6b8SYongseok Koh 		rte_mempool_put(buf->mp, buf);
22227d6bf6b8SYongseok Koh 	}
22237d6bf6b8SYongseok Koh }
22247d6bf6b8SYongseok Koh 
22257d6bf6b8SYongseok Koh void
22267d6bf6b8SYongseok Koh mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
22277d6bf6b8SYongseok Koh {
22287d6bf6b8SYongseok Koh 	mlx5_mprq_buf_free_cb(NULL, buf);
22297d6bf6b8SYongseok Koh }
22307d6bf6b8SYongseok Koh 
22317d6bf6b8SYongseok Koh static inline void
22327d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx)
22337d6bf6b8SYongseok Koh {
22347d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *rep = rxq->mprq_repl;
22357d6bf6b8SYongseok Koh 	volatile struct mlx5_wqe_data_seg *wqe =
22367d6bf6b8SYongseok Koh 		&((volatile struct mlx5_wqe_mprq *)rxq->wqes)[rq_idx].dseg;
22377d6bf6b8SYongseok Koh 	void *addr;
22387d6bf6b8SYongseok Koh 
22397d6bf6b8SYongseok Koh 	assert(rep != NULL);
22407d6bf6b8SYongseok Koh 	/* Replace MPRQ buf. */
22417d6bf6b8SYongseok Koh 	(*rxq->mprq_bufs)[rq_idx] = rep;
22427d6bf6b8SYongseok Koh 	/* Replace WQE. */
22437d6bf6b8SYongseok Koh 	addr = mlx5_mprq_buf_addr(rep);
22447d6bf6b8SYongseok Koh 	wqe->addr = rte_cpu_to_be_64((uintptr_t)addr);
22457d6bf6b8SYongseok Koh 	/* If there's only one MR, no need to replace LKey in WQE. */
22467d6bf6b8SYongseok Koh 	if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
22477d6bf6b8SYongseok Koh 		wqe->lkey = mlx5_rx_addr2mr(rxq, (uintptr_t)addr);
22487d6bf6b8SYongseok Koh 	/* Stash a mbuf for next replacement. */
22497d6bf6b8SYongseok Koh 	if (likely(!rte_mempool_get(rxq->mprq_mp, (void **)&rep)))
22507d6bf6b8SYongseok Koh 		rxq->mprq_repl = rep;
22517d6bf6b8SYongseok Koh 	else
22527d6bf6b8SYongseok Koh 		rxq->mprq_repl = NULL;
22537d6bf6b8SYongseok Koh }
22547d6bf6b8SYongseok Koh 
22557d6bf6b8SYongseok Koh /**
22567d6bf6b8SYongseok Koh  * DPDK callback for RX with Multi-Packet RQ support.
22577d6bf6b8SYongseok Koh  *
22587d6bf6b8SYongseok Koh  * @param dpdk_rxq
22597d6bf6b8SYongseok Koh  *   Generic pointer to RX queue structure.
22607d6bf6b8SYongseok Koh  * @param[out] pkts
22617d6bf6b8SYongseok Koh  *   Array to store received packets.
22627d6bf6b8SYongseok Koh  * @param pkts_n
22637d6bf6b8SYongseok Koh  *   Maximum number of packets in array.
22647d6bf6b8SYongseok Koh  *
22657d6bf6b8SYongseok Koh  * @return
22667d6bf6b8SYongseok Koh  *   Number of packets successfully received (<= pkts_n).
22677d6bf6b8SYongseok Koh  */
22687d6bf6b8SYongseok Koh uint16_t
22697d6bf6b8SYongseok Koh mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
22707d6bf6b8SYongseok Koh {
22717d6bf6b8SYongseok Koh 	struct mlx5_rxq_data *rxq = dpdk_rxq;
22727d6bf6b8SYongseok Koh 	const unsigned int strd_n = 1 << rxq->strd_num_n;
22737d6bf6b8SYongseok Koh 	const unsigned int strd_sz = 1 << rxq->strd_sz_n;
22747d6bf6b8SYongseok Koh 	const unsigned int strd_shift =
22757d6bf6b8SYongseok Koh 		MLX5_MPRQ_STRIDE_SHIFT_BYTE * rxq->strd_shift_en;
22767d6bf6b8SYongseok Koh 	const unsigned int cq_mask = (1 << rxq->cqe_n) - 1;
22777d6bf6b8SYongseok Koh 	const unsigned int wq_mask = (1 << rxq->elts_n) - 1;
22787d6bf6b8SYongseok Koh 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
22797d6bf6b8SYongseok Koh 	unsigned int i = 0;
22803afdf157SXueming Li 	uint32_t rq_ci = rxq->rq_ci;
22811787eb7bSYongseok Koh 	uint16_t consumed_strd = rxq->consumed_strd;
22827d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
22837d6bf6b8SYongseok Koh 
22847d6bf6b8SYongseok Koh 	while (i < pkts_n) {
22857d6bf6b8SYongseok Koh 		struct rte_mbuf *pkt;
22867d6bf6b8SYongseok Koh 		void *addr;
22877d6bf6b8SYongseok Koh 		int ret;
22887d6bf6b8SYongseok Koh 		unsigned int len;
22891787eb7bSYongseok Koh 		uint16_t strd_cnt;
22901787eb7bSYongseok Koh 		uint16_t strd_idx;
22917d6bf6b8SYongseok Koh 		uint32_t offset;
22927d6bf6b8SYongseok Koh 		uint32_t byte_cnt;
22932e633f1fSYongseok Koh 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
22941787eb7bSYongseok Koh 		uint32_t rss_hash_res = 0;
22957d6bf6b8SYongseok Koh 
22961787eb7bSYongseok Koh 		if (consumed_strd == strd_n) {
22977d6bf6b8SYongseok Koh 			/* Replace WQE only if the buffer is still in use. */
22987d6bf6b8SYongseok Koh 			if (rte_atomic16_read(&buf->refcnt) > 1) {
22997d6bf6b8SYongseok Koh 				mprq_buf_replace(rxq, rq_ci & wq_mask);
23007d6bf6b8SYongseok Koh 				/* Release the old buffer. */
23017d6bf6b8SYongseok Koh 				mlx5_mprq_buf_free(buf);
23027d6bf6b8SYongseok Koh 			} else if (unlikely(rxq->mprq_repl == NULL)) {
23037d6bf6b8SYongseok Koh 				struct mlx5_mprq_buf *rep;
23047d6bf6b8SYongseok Koh 
23057d6bf6b8SYongseok Koh 				/*
23067d6bf6b8SYongseok Koh 				 * Currently, the MPRQ mempool is out of buffer
23077d6bf6b8SYongseok Koh 				 * and doing memcpy regardless of the size of Rx
23087d6bf6b8SYongseok Koh 				 * packet. Retry allocation to get back to
23097d6bf6b8SYongseok Koh 				 * normal.
23107d6bf6b8SYongseok Koh 				 */
23117d6bf6b8SYongseok Koh 				if (!rte_mempool_get(rxq->mprq_mp,
23127d6bf6b8SYongseok Koh 						     (void **)&rep))
23137d6bf6b8SYongseok Koh 					rxq->mprq_repl = rep;
23147d6bf6b8SYongseok Koh 			}
23157d6bf6b8SYongseok Koh 			/* Advance to the next WQE. */
23161787eb7bSYongseok Koh 			consumed_strd = 0;
23177d6bf6b8SYongseok Koh 			++rq_ci;
23187d6bf6b8SYongseok Koh 			buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
23197d6bf6b8SYongseok Koh 		}
23207d6bf6b8SYongseok Koh 		cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
23212e633f1fSYongseok Koh 		ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe);
23227d6bf6b8SYongseok Koh 		if (!ret)
23237d6bf6b8SYongseok Koh 			break;
23247d6bf6b8SYongseok Koh 		if (unlikely(ret == -1)) {
23257d6bf6b8SYongseok Koh 			/* RX error, packet is likely too large. */
23267d6bf6b8SYongseok Koh 			++rxq->stats.idropped;
23277d6bf6b8SYongseok Koh 			continue;
23287d6bf6b8SYongseok Koh 		}
23297d6bf6b8SYongseok Koh 		byte_cnt = ret;
23301787eb7bSYongseok Koh 		strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
23317d6bf6b8SYongseok Koh 			   MLX5_MPRQ_STRIDE_NUM_SHIFT;
23321787eb7bSYongseok Koh 		assert(strd_cnt);
23331787eb7bSYongseok Koh 		consumed_strd += strd_cnt;
23347d6bf6b8SYongseok Koh 		if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
23357d6bf6b8SYongseok Koh 			continue;
23361787eb7bSYongseok Koh 		if (mcqe == NULL) {
23371787eb7bSYongseok Koh 			rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
23381787eb7bSYongseok Koh 			strd_idx = rte_be_to_cpu_16(cqe->wqe_counter);
23391787eb7bSYongseok Koh 		} else {
23401787eb7bSYongseok Koh 			/* mini-CQE for MPRQ doesn't have hash result. */
23411787eb7bSYongseok Koh 			strd_idx = rte_be_to_cpu_16(mcqe->stride_idx);
23421787eb7bSYongseok Koh 		}
23431787eb7bSYongseok Koh 		assert(strd_idx < strd_n);
23441787eb7bSYongseok Koh 		assert(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & wq_mask));
23457d6bf6b8SYongseok Koh 		/*
23467d6bf6b8SYongseok Koh 		 * Currently configured to receive a packet per a stride. But if
23477d6bf6b8SYongseok Koh 		 * MTU is adjusted through kernel interface, device could
23487d6bf6b8SYongseok Koh 		 * consume multiple strides without raising an error. In this
23497d6bf6b8SYongseok Koh 		 * case, the packet should be dropped because it is bigger than
23507d6bf6b8SYongseok Koh 		 * the max_rx_pkt_len.
23517d6bf6b8SYongseok Koh 		 */
23521787eb7bSYongseok Koh 		if (unlikely(strd_cnt > 1)) {
23537d6bf6b8SYongseok Koh 			++rxq->stats.idropped;
23547d6bf6b8SYongseok Koh 			continue;
23557d6bf6b8SYongseok Koh 		}
23567d6bf6b8SYongseok Koh 		pkt = rte_pktmbuf_alloc(rxq->mp);
23577d6bf6b8SYongseok Koh 		if (unlikely(pkt == NULL)) {
23587d6bf6b8SYongseok Koh 			++rxq->stats.rx_nombuf;
23597d6bf6b8SYongseok Koh 			break;
23607d6bf6b8SYongseok Koh 		}
23617d6bf6b8SYongseok Koh 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
23627d6bf6b8SYongseok Koh 		assert((int)len >= (rxq->crc_present << 2));
23637d6bf6b8SYongseok Koh 		if (rxq->crc_present)
236435b2d13fSOlivier Matz 			len -= RTE_ETHER_CRC_LEN;
23651787eb7bSYongseok Koh 		offset = strd_idx * strd_sz + strd_shift;
23667d6bf6b8SYongseok Koh 		addr = RTE_PTR_ADD(mlx5_mprq_buf_addr(buf), offset);
23677d6bf6b8SYongseok Koh 		/* Initialize the offload flag. */
23687d6bf6b8SYongseok Koh 		pkt->ol_flags = 0;
23697d6bf6b8SYongseok Koh 		/*
23707d6bf6b8SYongseok Koh 		 * Memcpy packets to the target mbuf if:
23717d6bf6b8SYongseok Koh 		 * - The size of packet is smaller than mprq_max_memcpy_len.
23727d6bf6b8SYongseok Koh 		 * - Out of buffer in the Mempool for Multi-Packet RQ.
23737d6bf6b8SYongseok Koh 		 */
23747d6bf6b8SYongseok Koh 		if (len <= rxq->mprq_max_memcpy_len || rxq->mprq_repl == NULL) {
23757d6bf6b8SYongseok Koh 			/*
23767d6bf6b8SYongseok Koh 			 * When memcpy'ing packet due to out-of-buffer, the
23777d6bf6b8SYongseok Koh 			 * packet must be smaller than the target mbuf.
23787d6bf6b8SYongseok Koh 			 */
23797d6bf6b8SYongseok Koh 			if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
23807d6bf6b8SYongseok Koh 				rte_pktmbuf_free_seg(pkt);
23817d6bf6b8SYongseok Koh 				++rxq->stats.idropped;
23827d6bf6b8SYongseok Koh 				continue;
23837d6bf6b8SYongseok Koh 			}
23847d6bf6b8SYongseok Koh 			rte_memcpy(rte_pktmbuf_mtod(pkt, void *), addr, len);
23857d6bf6b8SYongseok Koh 		} else {
23867d6bf6b8SYongseok Koh 			rte_iova_t buf_iova;
23877d6bf6b8SYongseok Koh 			struct rte_mbuf_ext_shared_info *shinfo;
23881787eb7bSYongseok Koh 			uint16_t buf_len = strd_cnt * strd_sz;
23897d6bf6b8SYongseok Koh 
23907d6bf6b8SYongseok Koh 			/* Increment the refcnt of the whole chunk. */
23917d6bf6b8SYongseok Koh 			rte_atomic16_add_return(&buf->refcnt, 1);
23927d6bf6b8SYongseok Koh 			assert((uint16_t)rte_atomic16_read(&buf->refcnt) <=
23937d6bf6b8SYongseok Koh 			       strd_n + 1);
23947d6bf6b8SYongseok Koh 			addr = RTE_PTR_SUB(addr, RTE_PKTMBUF_HEADROOM);
23957d6bf6b8SYongseok Koh 			/*
23967d6bf6b8SYongseok Koh 			 * MLX5 device doesn't use iova but it is necessary in a
23977d6bf6b8SYongseok Koh 			 * case where the Rx packet is transmitted via a
23987d6bf6b8SYongseok Koh 			 * different PMD.
23997d6bf6b8SYongseok Koh 			 */
24007d6bf6b8SYongseok Koh 			buf_iova = rte_mempool_virt2iova(buf) +
24017d6bf6b8SYongseok Koh 				   RTE_PTR_DIFF(addr, buf);
24027d6bf6b8SYongseok Koh 			shinfo = rte_pktmbuf_ext_shinfo_init_helper(addr,
24037d6bf6b8SYongseok Koh 					&buf_len, mlx5_mprq_buf_free_cb, buf);
24047d6bf6b8SYongseok Koh 			/*
24057d6bf6b8SYongseok Koh 			 * EXT_ATTACHED_MBUF will be set to pkt->ol_flags when
24067d6bf6b8SYongseok Koh 			 * attaching the stride to mbuf and more offload flags
24077d6bf6b8SYongseok Koh 			 * will be added below by calling rxq_cq_to_mbuf().
24087d6bf6b8SYongseok Koh 			 * Other fields will be overwritten.
24097d6bf6b8SYongseok Koh 			 */
24107d6bf6b8SYongseok Koh 			rte_pktmbuf_attach_extbuf(pkt, addr, buf_iova, buf_len,
24117d6bf6b8SYongseok Koh 						  shinfo);
24127d6bf6b8SYongseok Koh 			rte_pktmbuf_reset_headroom(pkt);
24137d6bf6b8SYongseok Koh 			assert(pkt->ol_flags == EXT_ATTACHED_MBUF);
24147d6bf6b8SYongseok Koh 			/*
24157d6bf6b8SYongseok Koh 			 * Prevent potential overflow due to MTU change through
24167d6bf6b8SYongseok Koh 			 * kernel interface.
24177d6bf6b8SYongseok Koh 			 */
24187d6bf6b8SYongseok Koh 			if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
24197d6bf6b8SYongseok Koh 				rte_pktmbuf_free_seg(pkt);
24207d6bf6b8SYongseok Koh 				++rxq->stats.idropped;
24217d6bf6b8SYongseok Koh 				continue;
24227d6bf6b8SYongseok Koh 			}
24237d6bf6b8SYongseok Koh 		}
24247d6bf6b8SYongseok Koh 		rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
24257d6bf6b8SYongseok Koh 		PKT_LEN(pkt) = len;
24267d6bf6b8SYongseok Koh 		DATA_LEN(pkt) = len;
24277d6bf6b8SYongseok Koh 		PORT(pkt) = rxq->port_id;
24287d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
24297d6bf6b8SYongseok Koh 		/* Increment bytes counter. */
24307d6bf6b8SYongseok Koh 		rxq->stats.ibytes += PKT_LEN(pkt);
24317d6bf6b8SYongseok Koh #endif
24327d6bf6b8SYongseok Koh 		/* Return packet. */
24337d6bf6b8SYongseok Koh 		*(pkts++) = pkt;
24347d6bf6b8SYongseok Koh 		++i;
24357d6bf6b8SYongseok Koh 	}
24367d6bf6b8SYongseok Koh 	/* Update the consumer indexes. */
24371787eb7bSYongseok Koh 	rxq->consumed_strd = consumed_strd;
24380cfdc180SYongseok Koh 	rte_cio_wmb();
24397d6bf6b8SYongseok Koh 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
24407d6bf6b8SYongseok Koh 	if (rq_ci != rxq->rq_ci) {
24417d6bf6b8SYongseok Koh 		rxq->rq_ci = rq_ci;
24420cfdc180SYongseok Koh 		rte_cio_wmb();
24437d6bf6b8SYongseok Koh 		*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
24447d6bf6b8SYongseok Koh 	}
24457d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
24467d6bf6b8SYongseok Koh 	/* Increment packets counter. */
24477d6bf6b8SYongseok Koh 	rxq->stats.ipackets += i;
24487d6bf6b8SYongseok Koh #endif
24497d6bf6b8SYongseok Koh 	return i;
24507d6bf6b8SYongseok Koh }
24517d6bf6b8SYongseok Koh 
24522e22920bSAdrien Mazarguil /**
24532e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
24542e22920bSAdrien Mazarguil  *
24552e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
24562e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
24572e22920bSAdrien Mazarguil  *
24582e22920bSAdrien Mazarguil  * @param dpdk_txq
24592e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
24602e22920bSAdrien Mazarguil  * @param[in] pkts
24612e22920bSAdrien Mazarguil  *   Packets to transmit.
24622e22920bSAdrien Mazarguil  * @param pkts_n
24632e22920bSAdrien Mazarguil  *   Number of packets in array.
24642e22920bSAdrien Mazarguil  *
24652e22920bSAdrien Mazarguil  * @return
24662e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
24672e22920bSAdrien Mazarguil  */
24682e22920bSAdrien Mazarguil uint16_t
246956f08e16SNélio Laranjeiro removed_tx_burst(void *dpdk_txq __rte_unused,
247056f08e16SNélio Laranjeiro 		 struct rte_mbuf **pkts __rte_unused,
247156f08e16SNélio Laranjeiro 		 uint16_t pkts_n __rte_unused)
24722e22920bSAdrien Mazarguil {
24732aac5b5dSYongseok Koh 	rte_mb();
24742e22920bSAdrien Mazarguil 	return 0;
24752e22920bSAdrien Mazarguil }
24762e22920bSAdrien Mazarguil 
24772e22920bSAdrien Mazarguil /**
24782e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
24792e22920bSAdrien Mazarguil  *
24802e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
24812e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
24822e22920bSAdrien Mazarguil  *
24832e22920bSAdrien Mazarguil  * @param dpdk_rxq
24842e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
24852e22920bSAdrien Mazarguil  * @param[out] pkts
24862e22920bSAdrien Mazarguil  *   Array to store received packets.
24872e22920bSAdrien Mazarguil  * @param pkts_n
24882e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
24892e22920bSAdrien Mazarguil  *
24902e22920bSAdrien Mazarguil  * @return
24912e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
24922e22920bSAdrien Mazarguil  */
24932e22920bSAdrien Mazarguil uint16_t
249456f08e16SNélio Laranjeiro removed_rx_burst(void *dpdk_txq __rte_unused,
249556f08e16SNélio Laranjeiro 		 struct rte_mbuf **pkts __rte_unused,
249656f08e16SNélio Laranjeiro 		 uint16_t pkts_n __rte_unused)
24972e22920bSAdrien Mazarguil {
24982aac5b5dSYongseok Koh 	rte_mb();
24992e22920bSAdrien Mazarguil 	return 0;
25002e22920bSAdrien Mazarguil }
25016cb559d6SYongseok Koh 
25026cb559d6SYongseok Koh /*
25036cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
25046cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
25056cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
25066cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
25076cb559d6SYongseok Koh  */
25086cb559d6SYongseok Koh 
250981bede55SKeith Wiles __rte_weak uint16_t
251056f08e16SNélio Laranjeiro mlx5_tx_burst_raw_vec(void *dpdk_txq __rte_unused,
251156f08e16SNélio Laranjeiro 		      struct rte_mbuf **pkts __rte_unused,
251256f08e16SNélio Laranjeiro 		      uint16_t pkts_n __rte_unused)
25136cb559d6SYongseok Koh {
25146cb559d6SYongseok Koh 	return 0;
25156cb559d6SYongseok Koh }
25166cb559d6SYongseok Koh 
251781bede55SKeith Wiles __rte_weak uint16_t
251856f08e16SNélio Laranjeiro mlx5_tx_burst_vec(void *dpdk_txq __rte_unused,
251956f08e16SNélio Laranjeiro 		  struct rte_mbuf **pkts __rte_unused,
252056f08e16SNélio Laranjeiro 		  uint16_t pkts_n __rte_unused)
25216cb559d6SYongseok Koh {
25226cb559d6SYongseok Koh 	return 0;
25236cb559d6SYongseok Koh }
25246cb559d6SYongseok Koh 
252581bede55SKeith Wiles __rte_weak uint16_t
252656f08e16SNélio Laranjeiro mlx5_rx_burst_vec(void *dpdk_txq __rte_unused,
252756f08e16SNélio Laranjeiro 		  struct rte_mbuf **pkts __rte_unused,
252856f08e16SNélio Laranjeiro 		  uint16_t pkts_n __rte_unused)
25296cb559d6SYongseok Koh {
25306cb559d6SYongseok Koh 	return 0;
25316cb559d6SYongseok Koh }
25326cb559d6SYongseok Koh 
253381bede55SKeith Wiles __rte_weak int
2534af4f09f2SNélio Laranjeiro mlx5_check_raw_vec_tx_support(struct rte_eth_dev *dev __rte_unused)
25356cb559d6SYongseok Koh {
25366cb559d6SYongseok Koh 	return -ENOTSUP;
25376cb559d6SYongseok Koh }
25386cb559d6SYongseok Koh 
253981bede55SKeith Wiles __rte_weak int
2540af4f09f2SNélio Laranjeiro mlx5_check_vec_tx_support(struct rte_eth_dev *dev __rte_unused)
25416cb559d6SYongseok Koh {
25426cb559d6SYongseok Koh 	return -ENOTSUP;
25436cb559d6SYongseok Koh }
25446cb559d6SYongseok Koh 
254581bede55SKeith Wiles __rte_weak int
2546af4f09f2SNélio Laranjeiro mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused)
25476cb559d6SYongseok Koh {
25486cb559d6SYongseok Koh 	return -ENOTSUP;
25496cb559d6SYongseok Koh }
25506cb559d6SYongseok Koh 
255181bede55SKeith Wiles __rte_weak int
2552af4f09f2SNélio Laranjeiro mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused)
25536cb559d6SYongseok Koh {
25546cb559d6SYongseok Koh 	return -ENOTSUP;
25556cb559d6SYongseok Koh }
2556