xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 43e9d9794cde875e697f29e4586b3dcab797fa4f)
12e22920bSAdrien Mazarguil /*-
22e22920bSAdrien Mazarguil  *   BSD LICENSE
32e22920bSAdrien Mazarguil  *
42e22920bSAdrien Mazarguil  *   Copyright 2015 6WIND S.A.
52e22920bSAdrien Mazarguil  *   Copyright 2015 Mellanox.
62e22920bSAdrien Mazarguil  *
72e22920bSAdrien Mazarguil  *   Redistribution and use in source and binary forms, with or without
82e22920bSAdrien Mazarguil  *   modification, are permitted provided that the following conditions
92e22920bSAdrien Mazarguil  *   are met:
102e22920bSAdrien Mazarguil  *
112e22920bSAdrien Mazarguil  *     * Redistributions of source code must retain the above copyright
122e22920bSAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer.
132e22920bSAdrien Mazarguil  *     * Redistributions in binary form must reproduce the above copyright
142e22920bSAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer in
152e22920bSAdrien Mazarguil  *       the documentation and/or other materials provided with the
162e22920bSAdrien Mazarguil  *       distribution.
172e22920bSAdrien Mazarguil  *     * Neither the name of 6WIND S.A. nor the names of its
182e22920bSAdrien Mazarguil  *       contributors may be used to endorse or promote products derived
192e22920bSAdrien Mazarguil  *       from this software without specific prior written permission.
202e22920bSAdrien Mazarguil  *
212e22920bSAdrien Mazarguil  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
222e22920bSAdrien Mazarguil  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
232e22920bSAdrien Mazarguil  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
242e22920bSAdrien Mazarguil  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
252e22920bSAdrien Mazarguil  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
262e22920bSAdrien Mazarguil  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
272e22920bSAdrien Mazarguil  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
282e22920bSAdrien Mazarguil  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
292e22920bSAdrien Mazarguil  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
302e22920bSAdrien Mazarguil  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
312e22920bSAdrien Mazarguil  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322e22920bSAdrien Mazarguil  */
332e22920bSAdrien Mazarguil 
342e22920bSAdrien Mazarguil #include <assert.h>
352e22920bSAdrien Mazarguil #include <stdint.h>
362e22920bSAdrien Mazarguil #include <string.h>
372e22920bSAdrien Mazarguil #include <stdlib.h>
382e22920bSAdrien Mazarguil 
392e22920bSAdrien Mazarguil /* Verbs header. */
402e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
412e22920bSAdrien Mazarguil #ifdef PEDANTIC
42fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic"
432e22920bSAdrien Mazarguil #endif
442e22920bSAdrien Mazarguil #include <infiniband/verbs.h>
45*43e9d979SShachar Beiser #include <infiniband/mlx5dv.h>
462e22920bSAdrien Mazarguil #ifdef PEDANTIC
47fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
482e22920bSAdrien Mazarguil #endif
492e22920bSAdrien Mazarguil 
502e22920bSAdrien Mazarguil #include <rte_mbuf.h>
512e22920bSAdrien Mazarguil #include <rte_mempool.h>
522e22920bSAdrien Mazarguil #include <rte_prefetch.h>
532e22920bSAdrien Mazarguil #include <rte_common.h>
542e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
556218063bSNélio Laranjeiro #include <rte_ether.h>
562e22920bSAdrien Mazarguil 
572e22920bSAdrien Mazarguil #include "mlx5.h"
582e22920bSAdrien Mazarguil #include "mlx5_utils.h"
592e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
60f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
612e22920bSAdrien Mazarguil #include "mlx5_defs.h"
626218063bSNélio Laranjeiro #include "mlx5_prm.h"
636218063bSNélio Laranjeiro 
64c0583d98SJerin Jacob static __rte_always_inline uint32_t
65c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe);
66ff1807a3SNélio Laranjeiro 
67c0583d98SJerin Jacob static __rte_always_inline int
68ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
69c0583d98SJerin Jacob 		 uint16_t cqe_cnt, uint32_t *rss_hash);
70ff1807a3SNélio Laranjeiro 
71c0583d98SJerin Jacob static __rte_always_inline uint32_t
72c0583d98SJerin Jacob rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe);
73ff1807a3SNélio Laranjeiro 
74ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
75ea16068cSYongseok Koh 	[0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
76ea16068cSYongseok Koh };
77ea16068cSYongseok Koh 
78ea16068cSYongseok Koh /**
79ea16068cSYongseok Koh  * Build a table to translate Rx completion flags to packet type.
80ea16068cSYongseok Koh  *
81ea16068cSYongseok Koh  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
82ea16068cSYongseok Koh  */
83ea16068cSYongseok Koh void
84ea16068cSYongseok Koh mlx5_set_ptype_table(void)
85ea16068cSYongseok Koh {
86ea16068cSYongseok Koh 	unsigned int i;
87ea16068cSYongseok Koh 	uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
88ea16068cSYongseok Koh 
899807f113SYongseok Koh 	/* Last entry must not be overwritten, reserved for errored packet. */
909807f113SYongseok Koh 	for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
91ea16068cSYongseok Koh 		(*p)[i] = RTE_PTYPE_UNKNOWN;
926cb559d6SYongseok Koh 	/*
936cb559d6SYongseok Koh 	 * The index to the array should have:
94ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
95ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
96ea16068cSYongseok Koh 	 * bit[5] = ip_frag
97ea16068cSYongseok Koh 	 * bit[6] = tunneled
98ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
9999c12dccSNélio Laranjeiro 	 */
100ea16068cSYongseok Koh 	/* L3 */
101ea16068cSYongseok Koh 	(*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
102ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
103ea16068cSYongseok Koh 	(*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
104ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
105ea16068cSYongseok Koh 	/* Fragmented */
106ea16068cSYongseok Koh 	(*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
107ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
108ea16068cSYongseok Koh 	(*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
109ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
110ea16068cSYongseok Koh 	/* TCP */
111ea16068cSYongseok Koh 	(*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
112ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
113ea16068cSYongseok Koh 	(*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
114ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
115ea16068cSYongseok Koh 	/* UDP */
116ea16068cSYongseok Koh 	(*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
117ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
118ea16068cSYongseok Koh 	(*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
119ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
120ea16068cSYongseok Koh 	/* Repeat with outer_l3_type being set. Just in case. */
121ea16068cSYongseok Koh 	(*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
122ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
123ea16068cSYongseok Koh 	(*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
124ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
125ea16068cSYongseok Koh 	(*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
126ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
127ea16068cSYongseok Koh 	(*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
128ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
129ea16068cSYongseok Koh 	(*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
130ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
131ea16068cSYongseok Koh 	(*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
132ea16068cSYongseok Koh 		     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 */
138ea16068cSYongseok Koh 	(*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
139ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
140ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
141ea16068cSYongseok Koh 	(*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
142ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
143ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
144ea16068cSYongseok Koh 	(*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
145ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
146ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
147ea16068cSYongseok Koh 	(*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
148ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
149ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
150ea16068cSYongseok Koh 	/* Tunneled - Fragmented */
151ea16068cSYongseok Koh 	(*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
152ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
153ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
154ea16068cSYongseok Koh 	(*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
155ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
156ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
157ea16068cSYongseok Koh 	(*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
158ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
159ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
160ea16068cSYongseok Koh 	(*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
161ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
162ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
163ea16068cSYongseok Koh 	/* Tunneled - TCP */
164ea16068cSYongseok Koh 	(*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
165ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
166ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
167ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
168ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
169ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
170ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
171ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
172ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
173ea16068cSYongseok Koh 	(*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
174ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
175ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
176ea16068cSYongseok Koh 	/* Tunneled - UDP */
177ea16068cSYongseok Koh 	(*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
178ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
179ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
180ea16068cSYongseok Koh 	(*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
181ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
182ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
183ea16068cSYongseok Koh 	(*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
184ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
185ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
186ea16068cSYongseok Koh 	(*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
187ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
188ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
189ea16068cSYongseok Koh }
190fdcb0f53SNélio Laranjeiro 
1912e22920bSAdrien Mazarguil /**
1926ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
1936ce84bd8SYongseok Koh  *
1946ce84bd8SYongseok Koh  * @param txq
1956ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
1966ce84bd8SYongseok Koh  * @param addr
1976ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
1986ce84bd8SYongseok Koh  *
1996ce84bd8SYongseok Koh  * @return
2006ce84bd8SYongseok Koh  *   Size of tailroom.
2016ce84bd8SYongseok Koh  */
2026ce84bd8SYongseok Koh static inline size_t
2036ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr)
2046ce84bd8SYongseok Koh {
2056ce84bd8SYongseok Koh 	size_t tailroom;
2066ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
2076ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
2086ce84bd8SYongseok Koh 		   (uintptr_t)addr;
2096ce84bd8SYongseok Koh 	return tailroom;
2106ce84bd8SYongseok Koh }
2116ce84bd8SYongseok Koh 
2126ce84bd8SYongseok Koh /**
2136ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
2146ce84bd8SYongseok Koh  *
2156ce84bd8SYongseok Koh  * @param dst
2166ce84bd8SYongseok Koh  *   Pointer to destination.
2176ce84bd8SYongseok Koh  * @param src
2186ce84bd8SYongseok Koh  *   Pointer to source.
2196ce84bd8SYongseok Koh  * @param n
2206ce84bd8SYongseok Koh  *   Number of bytes to copy.
2216ce84bd8SYongseok Koh  * @param base
2226ce84bd8SYongseok Koh  *   Pointer to head of queue.
2236ce84bd8SYongseok Koh  * @param tailroom
2246ce84bd8SYongseok Koh  *   Size of tailroom from dst.
2256ce84bd8SYongseok Koh  *
2266ce84bd8SYongseok Koh  * @return
2276ce84bd8SYongseok Koh  *   Pointer after copied data.
2286ce84bd8SYongseok Koh  */
2296ce84bd8SYongseok Koh static inline void *
2306ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
2316ce84bd8SYongseok Koh 		void *base, size_t tailroom)
2326ce84bd8SYongseok Koh {
2336ce84bd8SYongseok Koh 	void *ret;
2346ce84bd8SYongseok Koh 
2356ce84bd8SYongseok Koh 	if (n > tailroom) {
2366ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
2376ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
2386ce84bd8SYongseok Koh 			   n - tailroom);
2396ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
2406ce84bd8SYongseok Koh 	} else {
2416ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
2426ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
2436ce84bd8SYongseok Koh 	}
2446ce84bd8SYongseok Koh 	return ret;
2456ce84bd8SYongseok Koh }
2466ce84bd8SYongseok Koh 
2476ce84bd8SYongseok Koh /**
2488788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
2498788fec1SOlivier Matz  *
2508788fec1SOlivier Matz  * @param tx_queue
2518788fec1SOlivier Matz  *   The tx queue.
2528788fec1SOlivier Matz  * @param[in] offset
2538788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2548788fec1SOlivier Matz  *
2558788fec1SOlivier Matz  * @return
2568788fec1SOlivier Matz  *   The status of the tx descriptor.
2578788fec1SOlivier Matz  */
2588788fec1SOlivier Matz int
2598788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
2608788fec1SOlivier Matz {
2618788fec1SOlivier Matz 	struct txq *txq = tx_queue;
2628c819a69SYongseok Koh 	uint16_t used;
2638788fec1SOlivier Matz 
2646cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
2658c819a69SYongseok Koh 	used = txq->elts_head - txq->elts_tail;
2668788fec1SOlivier Matz 	if (offset < used)
2678788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
2688788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
2698788fec1SOlivier Matz }
2708788fec1SOlivier Matz 
2718788fec1SOlivier Matz /**
2728788fec1SOlivier Matz  * DPDK callback to check the status of a rx descriptor.
2738788fec1SOlivier Matz  *
2748788fec1SOlivier Matz  * @param rx_queue
2758788fec1SOlivier Matz  *   The rx queue.
2768788fec1SOlivier Matz  * @param[in] offset
2778788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2788788fec1SOlivier Matz  *
2798788fec1SOlivier Matz  * @return
2808788fec1SOlivier Matz  *   The status of the tx descriptor.
2818788fec1SOlivier Matz  */
2828788fec1SOlivier Matz int
2838788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
2848788fec1SOlivier Matz {
2858788fec1SOlivier Matz 	struct rxq *rxq = rx_queue;
2868788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
2878788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
2888788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
2898788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
2908788fec1SOlivier Matz 	unsigned int cq_ci;
2918788fec1SOlivier Matz 	unsigned int used;
2928788fec1SOlivier Matz 
2938788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
2948788fec1SOlivier Matz 	if (zip->ai) {
2958788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
2968788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
2978788fec1SOlivier Matz 	} else {
2988788fec1SOlivier Matz 		used = 0;
2998788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
3008788fec1SOlivier Matz 	}
3018788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3028788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
3038788fec1SOlivier Matz 		int8_t op_own;
3048788fec1SOlivier Matz 		unsigned int n;
3058788fec1SOlivier Matz 
3068788fec1SOlivier Matz 		op_own = cqe->op_own;
3078788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
3086b30a6a8SShachar Beiser 			n = rte_be_to_cpu_32(cqe->byte_cnt);
3098788fec1SOlivier Matz 		else
3108788fec1SOlivier Matz 			n = 1;
3118788fec1SOlivier Matz 		cq_ci += n;
3128788fec1SOlivier Matz 		used += n;
3138788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3148788fec1SOlivier Matz 	}
3158788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
3168788fec1SOlivier Matz 	if (offset < used)
3178788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
3188788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
3198788fec1SOlivier Matz }
3208788fec1SOlivier Matz 
3218788fec1SOlivier Matz /**
3222e22920bSAdrien Mazarguil  * DPDK callback for TX.
3232e22920bSAdrien Mazarguil  *
3242e22920bSAdrien Mazarguil  * @param dpdk_txq
3252e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
3262e22920bSAdrien Mazarguil  * @param[in] pkts
3272e22920bSAdrien Mazarguil  *   Packets to transmit.
3282e22920bSAdrien Mazarguil  * @param pkts_n
3292e22920bSAdrien Mazarguil  *   Number of packets in array.
3302e22920bSAdrien Mazarguil  *
3312e22920bSAdrien Mazarguil  * @return
3322e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
3332e22920bSAdrien Mazarguil  */
3342e22920bSAdrien Mazarguil uint16_t
3352e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
3362e22920bSAdrien Mazarguil {
3372e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
3381d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
3398c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
3408c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
341c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
342a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
3433f13f8c2SShahaf Shuler 	unsigned int k = 0;
3448c819a69SYongseok Koh 	uint16_t max_elts;
345ab76eab3SYongseok Koh 	unsigned int max_inline = txq->max_inline;
346ab76eab3SYongseok Koh 	const unsigned int inline_en = !!max_inline && txq->inline_en;
347f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
348c305090bSAdrien Mazarguil 	unsigned int comp;
3499a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
350ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
3516579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
3526579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
3536579c27cSNélio Laranjeiro 	uint8_t *raw;
3542e22920bSAdrien Mazarguil 
3551d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
3561d88ba17SNélio Laranjeiro 		return 0;
3575e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
358c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
3591d88ba17SNélio Laranjeiro 	/* Start processing. */
3606cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
3618c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
362f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
363f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
364f04f1d51SNélio Laranjeiro 		return 0;
365c3d62cc9SAdrien Mazarguil 	do {
3669a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
367573f54afSNélio Laranjeiro 		uint32_t length;
3688688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
369ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
3706579c27cSNélio Laranjeiro 		uintptr_t addr;
3719a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
3720d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
3733f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
374eef822ddSNélio Laranjeiro 		uint16_t ehdr;
3759a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
3763f13f8c2SShahaf Shuler 		uint64_t tso = 0;
37783daf156SShahaf Shuler 		uint16_t tso_segsz = 0;
3786579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
3796579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
3806579c27cSNélio Laranjeiro #endif
3812e22920bSAdrien Mazarguil 
3826579c27cSNélio Laranjeiro 		/* first_seg */
3833730e6c6SYongseok Koh 		buf = *pkts;
3846579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
385c3d62cc9SAdrien Mazarguil 		/*
386c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
387c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
388c3d62cc9SAdrien Mazarguil 		 */
389a5bf6af9SAdrien Mazarguil 		assert(segs_n);
3908c819a69SYongseok Koh 		if (max_elts < segs_n)
391c3d62cc9SAdrien Mazarguil 			break;
3928c819a69SYongseok Koh 		max_elts -= segs_n;
3936579c27cSNélio Laranjeiro 		--segs_n;
394f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
395f04f1d51SNélio Laranjeiro 			break;
3969a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
397fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
398fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
3993730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4003730e6c6SYongseok Koh 			rte_prefetch0(*(pkts + 1));
4016579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
4022e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
403eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
404eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
4056579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
4066579c27cSNélio Laranjeiro 		total_length = length;
4076579c27cSNélio Laranjeiro #endif
40824c14430SShahaf Shuler 		if (length < (MLX5_WQE_DWORD_SIZE + 2)) {
40924c14430SShahaf Shuler 			txq->stats.oerrors++;
410959be52eSNélio Laranjeiro 			break;
41124c14430SShahaf Shuler 		}
4122e22920bSAdrien Mazarguil 		/* Update element. */
4138c819a69SYongseok Koh 		(*txq->elts)[elts_head & elts_m] = buf;
4145e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
4153730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4163730e6c6SYongseok Koh 			rte_prefetch0(
4173730e6c6SYongseok Koh 			    rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
4181d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
4191d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
4201d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
421f5fde520SShahaf Shuler 			const uint64_t is_tunneled = buf->ol_flags &
422f5fde520SShahaf Shuler 						     (PKT_TX_TUNNEL_GRE |
423f5fde520SShahaf Shuler 						      PKT_TX_TUNNEL_VXLAN);
424f5fde520SShahaf Shuler 
425f5fde520SShahaf Shuler 			if (is_tunneled && txq->tunnel_en) {
426f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM |
427f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_INNER_CSUM;
428f5fde520SShahaf Shuler 				if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
429f5fde520SShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L3_CSUM;
430f5fde520SShahaf Shuler 			} else {
431f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_CSUM |
432f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_CSUM;
433f5fde520SShahaf Shuler 			}
4341d88ba17SNélio Laranjeiro 		}
435b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
4366579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
4376579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
4386b30a6a8SShachar Beiser 			uint32_t vlan = rte_cpu_to_be_32(0x81000000 |
4396b30a6a8SShachar Beiser 							 buf->vlan_tci);
4400d637a34SNélio Laranjeiro 			unsigned int len = 2 * ETHER_ADDR_LEN - 2;
4416579c27cSNélio Laranjeiro 
4420d637a34SNélio Laranjeiro 			addr += 2;
4430d637a34SNélio Laranjeiro 			length -= 2;
4440d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
4450d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
4460d637a34SNélio Laranjeiro 			/* Copy VLAN. */
4470d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
4480d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
4490d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
4500d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
4510d637a34SNélio Laranjeiro 			addr += len + 2;
4520d637a34SNélio Laranjeiro 			length -= (len + 2);
4530d637a34SNélio Laranjeiro 		} else {
4540d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
4550d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
4560d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
4570d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
4586579c27cSNélio Laranjeiro 		}
459d8292497SYongseok Koh 		raw += MLX5_WQE_DWORD_SIZE;
4603f13f8c2SShahaf Shuler 		if (txq->tso_en) {
4613f13f8c2SShahaf Shuler 			tso = buf->ol_flags & PKT_TX_TCP_SEG;
4623f13f8c2SShahaf Shuler 			if (tso) {
4633f13f8c2SShahaf Shuler 				uintptr_t end = (uintptr_t)
4643f13f8c2SShahaf Shuler 						(((uintptr_t)txq->wqes) +
4653f13f8c2SShahaf Shuler 						(1 << txq->wqe_n) *
4663f13f8c2SShahaf Shuler 						MLX5_WQE_SIZE);
4673f13f8c2SShahaf Shuler 				unsigned int copy_b;
4683f13f8c2SShahaf Shuler 				uint8_t vlan_sz = (buf->ol_flags &
4693f13f8c2SShahaf Shuler 						  PKT_TX_VLAN_PKT) ? 4 : 0;
470b247f346SShahaf Shuler 				const uint64_t is_tunneled =
471b247f346SShahaf Shuler 							buf->ol_flags &
472b247f346SShahaf Shuler 							(PKT_TX_TUNNEL_GRE |
473b247f346SShahaf Shuler 							 PKT_TX_TUNNEL_VXLAN);
4743f13f8c2SShahaf Shuler 
4753f13f8c2SShahaf Shuler 				tso_header_sz = buf->l2_len + vlan_sz +
4763f13f8c2SShahaf Shuler 						buf->l3_len + buf->l4_len;
47783daf156SShahaf Shuler 				tso_segsz = buf->tso_segsz;
47896fc8d65SShahaf Shuler 				if (unlikely(tso_segsz == 0)) {
47996fc8d65SShahaf Shuler 					txq->stats.oerrors++;
48096fc8d65SShahaf Shuler 					break;
48196fc8d65SShahaf Shuler 				}
482b247f346SShahaf Shuler 				if (is_tunneled	&& txq->tunnel_en) {
483b247f346SShahaf Shuler 					tso_header_sz += buf->outer_l2_len +
484b247f346SShahaf Shuler 							 buf->outer_l3_len;
4852a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
4862a6c96beSShahaf Shuler 				} else {
4872a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_CSUM;
488b247f346SShahaf Shuler 				}
4893f13f8c2SShahaf Shuler 				if (unlikely(tso_header_sz >
49024c14430SShahaf Shuler 					     MLX5_MAX_TSO_HEADER)) {
49124c14430SShahaf Shuler 					txq->stats.oerrors++;
4923f13f8c2SShahaf Shuler 					break;
49324c14430SShahaf Shuler 				}
4943f13f8c2SShahaf Shuler 				copy_b = tso_header_sz - pkt_inline_sz;
4953f13f8c2SShahaf Shuler 				/* First seg must contain all headers. */
4963f13f8c2SShahaf Shuler 				assert(copy_b <= length);
4973f13f8c2SShahaf Shuler 				if (copy_b &&
4983f13f8c2SShahaf Shuler 				   ((end - (uintptr_t)raw) > copy_b)) {
4993f13f8c2SShahaf Shuler 					uint16_t n = (MLX5_WQE_DS(copy_b) -
5003f13f8c2SShahaf Shuler 						      1 + 3) / 4;
5013f13f8c2SShahaf Shuler 
5023f13f8c2SShahaf Shuler 					if (unlikely(max_wqe < n))
5033f13f8c2SShahaf Shuler 						break;
5043f13f8c2SShahaf Shuler 					max_wqe -= n;
5053f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5063f13f8c2SShahaf Shuler 						   (void *)addr, copy_b);
5073f13f8c2SShahaf Shuler 					addr += copy_b;
5083f13f8c2SShahaf Shuler 					length -= copy_b;
509d8292497SYongseok Koh 					/* Include padding for TSO header. */
510d8292497SYongseok Koh 					copy_b = MLX5_WQE_DS(copy_b) *
5113f13f8c2SShahaf Shuler 						 MLX5_WQE_DWORD_SIZE;
512d8292497SYongseok Koh 					pkt_inline_sz += copy_b;
513d8292497SYongseok Koh 					raw += copy_b;
5143f13f8c2SShahaf Shuler 				} else {
5153f13f8c2SShahaf Shuler 					/* NOP WQE. */
5163f13f8c2SShahaf Shuler 					wqe->ctrl = (rte_v128u32_t){
5176b30a6a8SShachar Beiser 						     rte_cpu_to_be_32(
5186b30a6a8SShachar Beiser 							txq->wqe_ci << 8),
5196b30a6a8SShachar Beiser 						     rte_cpu_to_be_32(
5206b30a6a8SShachar Beiser 							txq->qp_num_8s | 1),
5213f13f8c2SShahaf Shuler 						     0,
5223f13f8c2SShahaf Shuler 						     0,
5233f13f8c2SShahaf Shuler 					};
5243f13f8c2SShahaf Shuler 					ds = 1;
5253f13f8c2SShahaf Shuler 					total_length = 0;
5263f13f8c2SShahaf Shuler 					k++;
5273f13f8c2SShahaf Shuler 					goto next_wqe;
5283f13f8c2SShahaf Shuler 				}
5293f13f8c2SShahaf Shuler 			}
5303f13f8c2SShahaf Shuler 		}
5316579c27cSNélio Laranjeiro 		/* Inline if enough room. */
532ab76eab3SYongseok Koh 		if (inline_en || tso) {
533d8292497SYongseok Koh 			uint32_t inl;
534fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
535fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
536fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
537ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
5388fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
539d8292497SYongseok Koh 						   (pkt_inline_sz - 2) -
540d8292497SYongseok Koh 						   !!tso * sizeof(inl);
541ab76eab3SYongseok Koh 			uintptr_t addr_end = (addr + inline_room) &
5426579c27cSNélio Laranjeiro 					     ~(RTE_CACHE_LINE_SIZE - 1);
5438fcd6c2cSNélio Laranjeiro 			unsigned int copy_b = (addr_end > addr) ?
5448fcd6c2cSNélio Laranjeiro 				RTE_MIN((addr_end - addr), length) :
5458fcd6c2cSNélio Laranjeiro 				0;
5466579c27cSNélio Laranjeiro 
5478fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
548f04f1d51SNélio Laranjeiro 				/*
549f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
550f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
551f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
552f04f1d51SNélio Laranjeiro 				 */
5538fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
5548fcd6c2cSNélio Laranjeiro 
555f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
556f04f1d51SNélio Laranjeiro 					break;
557f04f1d51SNélio Laranjeiro 				max_wqe -= n;
5583f13f8c2SShahaf Shuler 				if (tso) {
5596b30a6a8SShachar Beiser 					uint32_t inl =
5606b30a6a8SShachar Beiser 					rte_cpu_to_be_32(copy_b |
5616b30a6a8SShachar Beiser 							 MLX5_INLINE_SEG);
5626b30a6a8SShachar Beiser 
5636b30a6a8SShachar Beiser 					pkt_inline_sz =
5646b30a6a8SShachar Beiser 						MLX5_WQE_DS(tso_header_sz) *
5656b30a6a8SShachar Beiser 						MLX5_WQE_DWORD_SIZE;
5666b30a6a8SShachar Beiser 
5673f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5683f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
5693f13f8c2SShahaf Shuler 					raw += sizeof(inl);
5703f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
5713f13f8c2SShahaf Shuler 				}
5726579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
5736579c27cSNélio Laranjeiro 				addr += copy_b;
5746579c27cSNélio Laranjeiro 				length -= copy_b;
5756579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
5766579c27cSNélio Laranjeiro 			}
5776579c27cSNélio Laranjeiro 			/*
578786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
5796579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
5806579c27cSNélio Laranjeiro 			 */
5816579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
5826579c27cSNélio Laranjeiro 			if (length > 0) {
583f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
584f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
585f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
586f04f1d51SNélio Laranjeiro 						break;
587f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
588f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
589f04f1d51SNélio Laranjeiro 							   ds / 4);
590f04f1d51SNélio Laranjeiro 				} else {
5919a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
5926579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
5936579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
594f04f1d51SNélio Laranjeiro 				}
5956579c27cSNélio Laranjeiro 				goto use_dseg;
5966579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5976579c27cSNélio Laranjeiro 				goto next_pkt;
5986579c27cSNélio Laranjeiro 			} else {
599786b5c2dSShahaf Shuler 				/* dseg will be advance as part of next_seg */
600786b5c2dSShahaf Shuler 				dseg = (volatile rte_v128u32_t *)
601786b5c2dSShahaf Shuler 					((uintptr_t)wqe +
602786b5c2dSShahaf Shuler 					 ((ds - 1) * MLX5_WQE_DWORD_SIZE));
6036579c27cSNélio Laranjeiro 				goto next_seg;
6046579c27cSNélio Laranjeiro 			}
6056579c27cSNélio Laranjeiro 		} else {
6066579c27cSNélio Laranjeiro 			/*
6076579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
6086579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
6096579c27cSNélio Laranjeiro 			 */
6109a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
6116579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
6126579c27cSNélio Laranjeiro 			ds = 3;
6136579c27cSNélio Laranjeiro use_dseg:
6146579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
6156b30a6a8SShachar Beiser 			naddr = rte_cpu_to_be_64(addr);
6169a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
6176b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
6186cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
6199a7fa9f7SNélio Laranjeiro 				naddr,
6209a7fa9f7SNélio Laranjeiro 				naddr >> 32,
6216579c27cSNélio Laranjeiro 			};
6226579c27cSNélio Laranjeiro 			++ds;
6236579c27cSNélio Laranjeiro 			if (!segs_n)
6246579c27cSNélio Laranjeiro 				goto next_pkt;
6256579c27cSNélio Laranjeiro 		}
6266579c27cSNélio Laranjeiro next_seg:
6276579c27cSNélio Laranjeiro 		assert(buf);
6286579c27cSNélio Laranjeiro 		assert(ds);
6296579c27cSNélio Laranjeiro 		assert(wqe);
630a5bf6af9SAdrien Mazarguil 		/*
631a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
632a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
633a5bf6af9SAdrien Mazarguil 		 * of data segment size.
634a5bf6af9SAdrien Mazarguil 		 */
6358688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
6366579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
637f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
638f04f1d51SNélio Laranjeiro 				break;
6399a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
640f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
641f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
642f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
6436579c27cSNélio Laranjeiro 		} else {
644a5bf6af9SAdrien Mazarguil 			++dseg;
6456579c27cSNélio Laranjeiro 		}
646a5bf6af9SAdrien Mazarguil 		++ds;
647a5bf6af9SAdrien Mazarguil 		buf = buf->next;
648a5bf6af9SAdrien Mazarguil 		assert(buf);
6496579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
650a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
6516579c27cSNélio Laranjeiro 		total_length += length;
652a5bf6af9SAdrien Mazarguil #endif
6536579c27cSNélio Laranjeiro 		/* Store segment information. */
6546b30a6a8SShachar Beiser 		naddr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t));
6559a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
6566b30a6a8SShachar Beiser 			rte_cpu_to_be_32(length),
6576cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
6589a7fa9f7SNélio Laranjeiro 			naddr,
6599a7fa9f7SNélio Laranjeiro 			naddr >> 32,
6606579c27cSNélio Laranjeiro 		};
6618c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
662ac180a21SYongseok Koh 		++sg;
663ac180a21SYongseok Koh 		/* Advance counter only if all segs are successfully posted. */
6643730e6c6SYongseok Koh 		if (sg < segs_n)
6656579c27cSNélio Laranjeiro 			goto next_seg;
6663730e6c6SYongseok Koh 		else
667ac180a21SYongseok Koh 			j += sg;
6686579c27cSNélio Laranjeiro next_pkt:
669883ce172SShahaf Shuler 		if (ds > MLX5_DSEG_MAX) {
670883ce172SShahaf Shuler 			txq->stats.oerrors++;
671883ce172SShahaf Shuler 			break;
672883ce172SShahaf Shuler 		}
6738c819a69SYongseok Koh 		++elts_head;
6743730e6c6SYongseok Koh 		++pkts;
6756579c27cSNélio Laranjeiro 		++i;
676b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
6773f13f8c2SShahaf Shuler 		if (tso) {
6783f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
6796b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6806b30a6a8SShachar Beiser 						 MLX5_OPCODE_TSO),
6816b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6823f13f8c2SShahaf Shuler 				0,
6833f13f8c2SShahaf Shuler 				0,
6843f13f8c2SShahaf Shuler 			};
6853f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
6863f13f8c2SShahaf Shuler 				0,
6876b30a6a8SShachar Beiser 				cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16),
6883f13f8c2SShahaf Shuler 				0,
6896b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(tso_header_sz),
6903f13f8c2SShahaf Shuler 			};
6913f13f8c2SShahaf Shuler 		} else {
6929a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
6936b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6946b30a6a8SShachar Beiser 						 MLX5_OPCODE_SEND),
6956b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6969a7fa9f7SNélio Laranjeiro 				0,
6979a7fa9f7SNélio Laranjeiro 				0,
6989a7fa9f7SNélio Laranjeiro 			};
6999a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
7009a7fa9f7SNélio Laranjeiro 				0,
7019a7fa9f7SNélio Laranjeiro 				cs_flags,
7029a7fa9f7SNélio Laranjeiro 				0,
7036b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz),
7049a7fa9f7SNélio Laranjeiro 			};
7053f13f8c2SShahaf Shuler 		}
7063f13f8c2SShahaf Shuler next_wqe:
7076579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
708ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
709ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
71087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
711573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
7126579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
71387011737SAdrien Mazarguil #endif
7143730e6c6SYongseok Koh 	} while (i < pkts_n);
7152e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
7163f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
7172e22920bSAdrien Mazarguil 		return 0;
7188c819a69SYongseok Koh 	txq->elts_head += (i + j);
719c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
7203f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
721c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
722c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
7236b30a6a8SShachar Beiser 		last_wqe->ctrl2 = rte_cpu_to_be_32(8);
724c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
725ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
726c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
727c305090bSAdrien Mazarguil 	} else {
728c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
729c305090bSAdrien Mazarguil 	}
73087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
73187011737SAdrien Mazarguil 	/* Increment sent packets counter. */
73287011737SAdrien Mazarguil 	txq->stats.opackets += i;
73387011737SAdrien Mazarguil #endif
7342e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
735ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
7362e22920bSAdrien Mazarguil 	return i;
7372e22920bSAdrien Mazarguil }
7382e22920bSAdrien Mazarguil 
7392e22920bSAdrien Mazarguil /**
740230189d9SNélio Laranjeiro  * Open a MPW session.
741230189d9SNélio Laranjeiro  *
742230189d9SNélio Laranjeiro  * @param txq
743230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
744230189d9SNélio Laranjeiro  * @param mpw
745230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
746230189d9SNélio Laranjeiro  * @param length
747230189d9SNélio Laranjeiro  *   Packet length.
748230189d9SNélio Laranjeiro  */
749230189d9SNélio Laranjeiro static inline void
750230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
751230189d9SNélio Laranjeiro {
752a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
753230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
754230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
755fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
756230189d9SNélio Laranjeiro 
757230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
758230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
759230189d9SNélio Laranjeiro 	mpw->len = length;
760230189d9SNélio Laranjeiro 	mpw->total_len = 0;
761fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
7626b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
7638688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
7648688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
7658688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
7668688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
7676b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
7686b30a6a8SShachar Beiser 					     (txq->wqe_ci << 8) |
7696b30a6a8SShachar Beiser 					     MLX5_OPCODE_TSO);
7708688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
7718688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
7728688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
7738688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
7748688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
7758688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
776230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
777230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
778230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
779230189d9SNélio Laranjeiro }
780230189d9SNélio Laranjeiro 
781230189d9SNélio Laranjeiro /**
782230189d9SNélio Laranjeiro  * Close a MPW session.
783230189d9SNélio Laranjeiro  *
784230189d9SNélio Laranjeiro  * @param txq
785230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
786230189d9SNélio Laranjeiro  * @param mpw
787230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
788230189d9SNélio Laranjeiro  */
789230189d9SNélio Laranjeiro static inline void
790230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
791230189d9SNélio Laranjeiro {
792230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
793230189d9SNélio Laranjeiro 
794230189d9SNélio Laranjeiro 	/*
795230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
796230189d9SNélio Laranjeiro 	 * count as 2.
797230189d9SNélio Laranjeiro 	 */
7986b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num));
799230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
800230189d9SNélio Laranjeiro 	if (num < 3)
801230189d9SNélio Laranjeiro 		++txq->wqe_ci;
802230189d9SNélio Laranjeiro 	else
803230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
804fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
805fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
806230189d9SNélio Laranjeiro }
807230189d9SNélio Laranjeiro 
808230189d9SNélio Laranjeiro /**
809230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
810230189d9SNélio Laranjeiro  *
811230189d9SNélio Laranjeiro  * @param dpdk_txq
812230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
813230189d9SNélio Laranjeiro  * @param[in] pkts
814230189d9SNélio Laranjeiro  *   Packets to transmit.
815230189d9SNélio Laranjeiro  * @param pkts_n
816230189d9SNélio Laranjeiro  *   Number of packets in array.
817230189d9SNélio Laranjeiro  *
818230189d9SNélio Laranjeiro  * @return
819230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
820230189d9SNélio Laranjeiro  */
821230189d9SNélio Laranjeiro uint16_t
822230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
823230189d9SNélio Laranjeiro {
824230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
825230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
8268c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
8278c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
828c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
829a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
8308c819a69SYongseok Koh 	uint16_t max_elts;
831f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
832230189d9SNélio Laranjeiro 	unsigned int comp;
833230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
834230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
835230189d9SNélio Laranjeiro 	};
836230189d9SNélio Laranjeiro 
837c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
838c3d62cc9SAdrien Mazarguil 		return 0;
839230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
840fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
841fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
842230189d9SNélio Laranjeiro 	/* Start processing. */
8436cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
8448c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
845f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
846f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
847f04f1d51SNélio Laranjeiro 		return 0;
848c3d62cc9SAdrien Mazarguil 	do {
849a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
850230189d9SNélio Laranjeiro 		uint32_t length;
851a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
852230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
853230189d9SNélio Laranjeiro 
854c3d62cc9SAdrien Mazarguil 		/*
855c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
856c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
857c3d62cc9SAdrien Mazarguil 		 */
858a5bf6af9SAdrien Mazarguil 		assert(segs_n);
8598c819a69SYongseok Koh 		if (max_elts < segs_n)
860c3d62cc9SAdrien Mazarguil 			break;
861a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
86224c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
86324c14430SShahaf Shuler 			txq->stats.oerrors++;
864a5bf6af9SAdrien Mazarguil 			break;
86524c14430SShahaf Shuler 		}
8668c819a69SYongseok Koh 		max_elts -= segs_n;
867c3d62cc9SAdrien Mazarguil 		--pkts_n;
868230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
869230189d9SNélio Laranjeiro 		if (buf->ol_flags &
870230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
871230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
872a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
873a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
874a5bf6af9SAdrien Mazarguil 		assert(length);
875230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
876230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
877230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
878a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
8798688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
880230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
881230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
882f04f1d51SNélio Laranjeiro 			/*
883f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
884f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
885f04f1d51SNélio Laranjeiro 			 * resources.
886f04f1d51SNélio Laranjeiro 			 */
887f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
888f04f1d51SNélio Laranjeiro 				break;
889f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
890230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
8918688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
892230189d9SNélio Laranjeiro 		}
893a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
894a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
895a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
896a5bf6af9SAdrien Mazarguil 		length = 0;
897a5bf6af9SAdrien Mazarguil #endif
898a5bf6af9SAdrien Mazarguil 		do {
899a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
900a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
901a5bf6af9SAdrien Mazarguil 
902a5bf6af9SAdrien Mazarguil 			assert(buf);
9038c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
904230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
905a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
906230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
9076b30a6a8SShachar Beiser 				.byte_count = rte_cpu_to_be_32(DATA_LEN(buf)),
9086cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
9096b30a6a8SShachar Beiser 				.addr = rte_cpu_to_be_64(addr),
910230189d9SNélio Laranjeiro 			};
911a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
912a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
913a5bf6af9SAdrien Mazarguil #endif
914a5bf6af9SAdrien Mazarguil 			buf = buf->next;
915230189d9SNélio Laranjeiro 			++mpw.pkts_n;
916a5bf6af9SAdrien Mazarguil 			++j;
917a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
918a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
919230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
920230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
921230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
922230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
923230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
924230189d9SNélio Laranjeiro #endif
925c3d62cc9SAdrien Mazarguil 		++i;
926c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
927230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
928230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
929230189d9SNélio Laranjeiro 		return 0;
930230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
931a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
932a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
933230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
9348688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
935230189d9SNélio Laranjeiro 
936230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
9376b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
938230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
9398688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
940230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
941230189d9SNélio Laranjeiro 	} else {
942230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
943230189d9SNélio Laranjeiro 	}
944230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
945230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
946230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
947230189d9SNélio Laranjeiro #endif
948230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
949230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
950230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
95130807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
952230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
953230189d9SNélio Laranjeiro 	return i;
954230189d9SNélio Laranjeiro }
955230189d9SNélio Laranjeiro 
956230189d9SNélio Laranjeiro /**
957230189d9SNélio Laranjeiro  * Open a MPW inline session.
958230189d9SNélio Laranjeiro  *
959230189d9SNélio Laranjeiro  * @param txq
960230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
961230189d9SNélio Laranjeiro  * @param mpw
962230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
963230189d9SNélio Laranjeiro  * @param length
964230189d9SNélio Laranjeiro  *   Packet length.
965230189d9SNélio Laranjeiro  */
966230189d9SNélio Laranjeiro static inline void
967230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
968230189d9SNélio Laranjeiro {
969a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
9708688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
971230189d9SNélio Laranjeiro 
972230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
973230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
974230189d9SNélio Laranjeiro 	mpw->len = length;
975230189d9SNélio Laranjeiro 	mpw->total_len = 0;
976fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9776b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
978230189d9SNélio Laranjeiro 					     (txq->wqe_ci << 8) |
979c904ae25SNélio Laranjeiro 					     MLX5_OPCODE_TSO);
9808688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9818688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9826b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
9838688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9848688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
9858688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9868688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9878688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
9888688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
9898688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
9908688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
991230189d9SNélio Laranjeiro }
992230189d9SNélio Laranjeiro 
993230189d9SNélio Laranjeiro /**
994230189d9SNélio Laranjeiro  * Close a MPW inline session.
995230189d9SNélio Laranjeiro  *
996230189d9SNélio Laranjeiro  * @param txq
997230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
998230189d9SNélio Laranjeiro  * @param mpw
999230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1000230189d9SNélio Laranjeiro  */
1001230189d9SNélio Laranjeiro static inline void
1002230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
1003230189d9SNélio Laranjeiro {
1004230189d9SNélio Laranjeiro 	unsigned int size;
10058688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
10068688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
1007230189d9SNélio Laranjeiro 
10088688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
1009230189d9SNélio Laranjeiro 	/*
1010230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
1011230189d9SNélio Laranjeiro 	 * count as 2.
1012230189d9SNélio Laranjeiro 	 */
10136b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
10146b30a6a8SShachar Beiser 					     MLX5_WQE_DS(size));
1015230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
10166b30a6a8SShachar Beiser 	inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG);
10178688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1018230189d9SNélio Laranjeiro }
1019230189d9SNélio Laranjeiro 
1020230189d9SNélio Laranjeiro /**
1021230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1022230189d9SNélio Laranjeiro  *
1023230189d9SNélio Laranjeiro  * @param dpdk_txq
1024230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1025230189d9SNélio Laranjeiro  * @param[in] pkts
1026230189d9SNélio Laranjeiro  *   Packets to transmit.
1027230189d9SNélio Laranjeiro  * @param pkts_n
1028230189d9SNélio Laranjeiro  *   Number of packets in array.
1029230189d9SNélio Laranjeiro  *
1030230189d9SNélio Laranjeiro  * @return
1031230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1032230189d9SNélio Laranjeiro  */
1033230189d9SNélio Laranjeiro uint16_t
1034230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1035230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1036230189d9SNélio Laranjeiro {
1037230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
1038230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
10398c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
10408c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1041c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1042a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
10438c819a69SYongseok Koh 	uint16_t max_elts;
1044f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1045230189d9SNélio Laranjeiro 	unsigned int comp;
10460e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1047230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1048230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1049230189d9SNélio Laranjeiro 	};
1050f04f1d51SNélio Laranjeiro 	/*
1051f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1052f04f1d51SNélio Laranjeiro 	 * code.
1053f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1054f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1055f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1056f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1057f04f1d51SNélio Laranjeiro 	 */
1058f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1059f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1060f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1061f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1062230189d9SNélio Laranjeiro 
1063c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1064c3d62cc9SAdrien Mazarguil 		return 0;
1065230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1066fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1067fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1068230189d9SNélio Laranjeiro 	/* Start processing. */
10696cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
10708c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
1071c3d62cc9SAdrien Mazarguil 	do {
1072a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1073230189d9SNélio Laranjeiro 		uintptr_t addr;
1074230189d9SNélio Laranjeiro 		uint32_t length;
1075a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
1076230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
1077230189d9SNélio Laranjeiro 
1078c3d62cc9SAdrien Mazarguil 		/*
1079c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1080c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1081c3d62cc9SAdrien Mazarguil 		 */
1082a5bf6af9SAdrien Mazarguil 		assert(segs_n);
10838c819a69SYongseok Koh 		if (max_elts < segs_n)
1084c3d62cc9SAdrien Mazarguil 			break;
1085a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
108624c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
108724c14430SShahaf Shuler 			txq->stats.oerrors++;
1088a5bf6af9SAdrien Mazarguil 			break;
108924c14430SShahaf Shuler 		}
10908c819a69SYongseok Koh 		max_elts -= segs_n;
1091c3d62cc9SAdrien Mazarguil 		--pkts_n;
1092f04f1d51SNélio Laranjeiro 		/*
1093f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1094f04f1d51SNélio Laranjeiro 		 * iteration.
1095f04f1d51SNélio Laranjeiro 		 */
1096f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
1097230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
1098230189d9SNélio Laranjeiro 		if (buf->ol_flags &
1099230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
1100230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
1101a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1102a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1103230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1104230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1105230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1106a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
11078688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1108230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1109230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1110230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1111a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1112230189d9SNélio Laranjeiro 			    (length > inline_room) ||
11138688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1114230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11150e8679fcSNélio Laranjeiro 				inline_room =
11160e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1117230189d9SNélio Laranjeiro 			}
1118230189d9SNélio Laranjeiro 		}
1119230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1120a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1121a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1122f04f1d51SNélio Laranjeiro 				/*
1123f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1124f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1125f04f1d51SNélio Laranjeiro 				 * such resources.
1126f04f1d51SNélio Laranjeiro 				 */
1127f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1128f04f1d51SNélio Laranjeiro 					break;
1129f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1130230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
11318688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1132230189d9SNélio Laranjeiro 			} else {
1133f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1134f04f1d51SNélio Laranjeiro 					break;
1135f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1136230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
11378688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1138230189d9SNélio Laranjeiro 			}
1139230189d9SNélio Laranjeiro 		}
1140a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1141a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1142230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
11430e8679fcSNélio Laranjeiro 			assert(inline_room ==
11440e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1145a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1146a5bf6af9SAdrien Mazarguil 			length = 0;
1147a5bf6af9SAdrien Mazarguil #endif
1148a5bf6af9SAdrien Mazarguil 			do {
1149230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1150230189d9SNélio Laranjeiro 
1151a5bf6af9SAdrien Mazarguil 				assert(buf);
11528c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1153230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1154a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1155230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
11566b30a6a8SShachar Beiser 					.byte_count =
11576b30a6a8SShachar Beiser 					       rte_cpu_to_be_32(DATA_LEN(buf)),
11586cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
11596b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
1160230189d9SNélio Laranjeiro 				};
1161a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1162a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1163a5bf6af9SAdrien Mazarguil #endif
1164a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1165230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1166a5bf6af9SAdrien Mazarguil 				++j;
1167a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1168a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1169230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1170230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1171230189d9SNélio Laranjeiro 		} else {
1172230189d9SNélio Laranjeiro 			unsigned int max;
1173230189d9SNélio Laranjeiro 
1174230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1175230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1176a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1177a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
11788c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1179230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1180fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1181fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1182fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1183230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1184230189d9SNélio Laranjeiro 			if (length > max) {
1185230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1186230189d9SNélio Laranjeiro 					   (void *)addr,
1187230189d9SNélio Laranjeiro 					   max);
1188fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1189230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1190230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1191230189d9SNélio Laranjeiro 					   length - max);
1192230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1193230189d9SNélio Laranjeiro 			} else {
1194230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1195230189d9SNélio Laranjeiro 					   (void *)addr,
1196230189d9SNélio Laranjeiro 					   length);
119716c64768SYongseok Koh 
119816c64768SYongseok Koh 				if (length == max)
119916c64768SYongseok Koh 					mpw.data.raw =
120016c64768SYongseok Koh 						(volatile void *)txq->wqes;
120116c64768SYongseok Koh 				else
1202230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1203230189d9SNélio Laranjeiro 			}
1204230189d9SNélio Laranjeiro 			++mpw.pkts_n;
120576bf1574SYongseok Koh 			mpw.total_len += length;
1206a5bf6af9SAdrien Mazarguil 			++j;
1207230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1208230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
12090e8679fcSNélio Laranjeiro 				inline_room =
12100e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1211230189d9SNélio Laranjeiro 			} else {
1212230189d9SNélio Laranjeiro 				inline_room -= length;
1213230189d9SNélio Laranjeiro 			}
1214230189d9SNélio Laranjeiro 		}
1215230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1216230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1217230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1218230189d9SNélio Laranjeiro #endif
1219c3d62cc9SAdrien Mazarguil 		++i;
1220c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1221230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1222230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1223230189d9SNélio Laranjeiro 		return 0;
1224230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1225a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1226a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1227230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
12288688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1229230189d9SNélio Laranjeiro 
1230230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
12316b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
1232230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
12338688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1234230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1235230189d9SNélio Laranjeiro 	} else {
1236230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1237230189d9SNélio Laranjeiro 	}
1238230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1239230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1240230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1241230189d9SNélio Laranjeiro #endif
1242230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1243230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1244230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1245230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1246230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
124730807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1248230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1249230189d9SNélio Laranjeiro 	return i;
1250230189d9SNélio Laranjeiro }
1251230189d9SNélio Laranjeiro 
1252230189d9SNélio Laranjeiro /**
12536ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
12546ce84bd8SYongseok Koh  *
12556ce84bd8SYongseok Koh  * @param txq
12566ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12576ce84bd8SYongseok Koh  * @param mpw
12586ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12596ce84bd8SYongseok Koh  * @param length
12606ce84bd8SYongseok Koh  *   Packet length.
12616ce84bd8SYongseok Koh  */
12626ce84bd8SYongseok Koh static inline void
12636ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding)
12646ce84bd8SYongseok Koh {
12656ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
12666ce84bd8SYongseok Koh 
12676ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
12686ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
12696ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
12706ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
12716b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] =
12726b30a6a8SShachar Beiser 		rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
12736ce84bd8SYongseok Koh 				 (txq->wqe_ci << 8) |
12746ce84bd8SYongseok Koh 				 MLX5_OPCODE_ENHANCED_MPSW);
12756ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
12766ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
12776ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
12786ce84bd8SYongseok Koh 	if (unlikely(padding)) {
12796ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
12806ce84bd8SYongseok Koh 
12816ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
12826b30a6a8SShachar Beiser 		*(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG);
12836ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
12846b30a6a8SShachar Beiser 			rte_cpu_to_be_32(MLX5_INLINE_SEG);
12856ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
12866ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
12876ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
12886ce84bd8SYongseok Koh 	} else {
12896ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
12906ce84bd8SYongseok Koh 	}
12916ce84bd8SYongseok Koh }
12926ce84bd8SYongseok Koh 
12936ce84bd8SYongseok Koh /**
12946ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
12956ce84bd8SYongseok Koh  *
12966ce84bd8SYongseok Koh  * @param txq
12976ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12986ce84bd8SYongseok Koh  * @param mpw
12996ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
13006ce84bd8SYongseok Koh  *
13016ce84bd8SYongseok Koh  * @return
13026ce84bd8SYongseok Koh  *   Number of consumed WQEs.
13036ce84bd8SYongseok Koh  */
13046ce84bd8SYongseok Koh static inline uint16_t
13056ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw)
13066ce84bd8SYongseok Koh {
13076ce84bd8SYongseok Koh 	uint16_t ret;
13086ce84bd8SYongseok Koh 
13096ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
13106ce84bd8SYongseok Koh 	 * count as 2.
13116ce84bd8SYongseok Koh 	 */
13126b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
13136b30a6a8SShachar Beiser 					     MLX5_WQE_DS(mpw->total_len));
13146ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
13156ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
13166ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
13176ce84bd8SYongseok Koh 	return ret;
13186ce84bd8SYongseok Koh }
13196ce84bd8SYongseok Koh 
13206ce84bd8SYongseok Koh /**
13216ce84bd8SYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
13226ce84bd8SYongseok Koh  *
13236ce84bd8SYongseok Koh  * @param dpdk_txq
13246ce84bd8SYongseok Koh  *   Generic pointer to TX queue structure.
13256ce84bd8SYongseok Koh  * @param[in] pkts
13266ce84bd8SYongseok Koh  *   Packets to transmit.
13276ce84bd8SYongseok Koh  * @param pkts_n
13286ce84bd8SYongseok Koh  *   Number of packets in array.
13296ce84bd8SYongseok Koh  *
13306ce84bd8SYongseok Koh  * @return
13316ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
13326ce84bd8SYongseok Koh  */
13336ce84bd8SYongseok Koh uint16_t
13346ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
13356ce84bd8SYongseok Koh {
13366ce84bd8SYongseok Koh 	struct txq *txq = (struct txq *)dpdk_txq;
13376ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
13388c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
13398c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
13406ce84bd8SYongseok Koh 	unsigned int i = 0;
13416ce84bd8SYongseok Koh 	unsigned int j = 0;
13428c819a69SYongseok Koh 	uint16_t max_elts;
13436ce84bd8SYongseok Koh 	uint16_t max_wqe;
13446ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
13456ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
13466ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
13476ce84bd8SYongseok Koh 	uint32_t inl_hdr;
13486ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
13496ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
13506ce84bd8SYongseok Koh 	};
13516ce84bd8SYongseok Koh 
13526ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
13536ce84bd8SYongseok Koh 		return 0;
13546ce84bd8SYongseok Koh 	/* Start processing. */
13556cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
13566ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
13576ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
13586ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
13596ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
13606ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
13616ce84bd8SYongseok Koh 		return 0;
13626ce84bd8SYongseok Koh 	do {
13636ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
13646ce84bd8SYongseok Koh 		uintptr_t addr;
13656ce84bd8SYongseok Koh 		uint64_t naddr;
13666ce84bd8SYongseok Koh 		unsigned int n;
13676ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
13686ce84bd8SYongseok Koh 		uint32_t length;
13696ce84bd8SYongseok Koh 		unsigned int segs_n = buf->nb_segs;
13706ce84bd8SYongseok Koh 		uint32_t cs_flags = 0;
13716ce84bd8SYongseok Koh 
13726ce84bd8SYongseok Koh 		/*
13736ce84bd8SYongseok Koh 		 * Make sure there is enough room to store this packet and
13746ce84bd8SYongseok Koh 		 * that one ring entry remains unused.
13756ce84bd8SYongseok Koh 		 */
13766ce84bd8SYongseok Koh 		assert(segs_n);
13778c819a69SYongseok Koh 		if (max_elts - j < segs_n)
13786ce84bd8SYongseok Koh 			break;
13796ce84bd8SYongseok Koh 		/* Do not bother with large packets MPW cannot handle. */
138024c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
138124c14430SShahaf Shuler 			txq->stats.oerrors++;
13826ce84bd8SYongseok Koh 			break;
138324c14430SShahaf Shuler 		}
13846ce84bd8SYongseok Koh 		/* Should we enable HW CKSUM offload. */
13856ce84bd8SYongseok Koh 		if (buf->ol_flags &
13866ce84bd8SYongseok Koh 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
13876ce84bd8SYongseok Koh 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
13886ce84bd8SYongseok Koh 		/* Retrieve packet information. */
13896ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
13906ce84bd8SYongseok Koh 		/* Start new session if:
13916ce84bd8SYongseok Koh 		 * - multi-segment packet
13926ce84bd8SYongseok Koh 		 * - no space left even for a dseg
13936ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
13946ce84bd8SYongseok Koh 		 * - cs_flag differs
13956ce84bd8SYongseok Koh 		 * It can't be MLX5_MPW_STATE_OPENED as always have a single
13966ce84bd8SYongseok Koh 		 * segmented packet.
13976ce84bd8SYongseok Koh 		 */
13986ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
13996ce84bd8SYongseok Koh 			if ((segs_n != 1) ||
14006ce84bd8SYongseok Koh 			    (inl_pad + sizeof(struct mlx5_wqe_data_seg) >
14016ce84bd8SYongseok Koh 			      mpw_room) ||
14026ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
14036ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
14046ce84bd8SYongseok Koh 			      mpw_room) ||
14056ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
14066ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
14076ce84bd8SYongseok Koh 		}
14086ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
14096ce84bd8SYongseok Koh 			if (unlikely(segs_n != 1)) {
14106ce84bd8SYongseok Koh 				/* Fall back to legacy MPW.
14116ce84bd8SYongseok Koh 				 * A MPW session consumes 2 WQEs at most to
14126ce84bd8SYongseok Koh 				 * include MLX5_MPW_DSEG_MAX pointers.
14136ce84bd8SYongseok Koh 				 */
14146ce84bd8SYongseok Koh 				if (unlikely(max_wqe < 2))
14156ce84bd8SYongseok Koh 					break;
14166ce84bd8SYongseok Koh 				mlx5_mpw_new(txq, &mpw, length);
14176ce84bd8SYongseok Koh 			} else {
14186ce84bd8SYongseok Koh 				/* In Enhanced MPW, inline as much as the budget
14196ce84bd8SYongseok Koh 				 * is allowed. The remaining space is to be
14206ce84bd8SYongseok Koh 				 * filled with dsegs. If the title WQEBB isn't
14216ce84bd8SYongseok Koh 				 * padded, it will have 2 dsegs there.
14226ce84bd8SYongseok Koh 				 */
14236ce84bd8SYongseok Koh 				mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
14246ce84bd8SYongseok Koh 					    (max_inline ? max_inline :
14256ce84bd8SYongseok Koh 					     pkts_n * MLX5_WQE_DWORD_SIZE) +
14266ce84bd8SYongseok Koh 					    MLX5_WQE_SIZE);
14276ce84bd8SYongseok Koh 				if (unlikely(max_wqe * MLX5_WQE_SIZE <
14286ce84bd8SYongseok Koh 					      mpw_room))
14296ce84bd8SYongseok Koh 					break;
14306ce84bd8SYongseok Koh 				/* Don't pad the title WQEBB to not waste WQ. */
14316ce84bd8SYongseok Koh 				mlx5_empw_new(txq, &mpw, 0);
14326ce84bd8SYongseok Koh 				mpw_room -= mpw.total_len;
14336ce84bd8SYongseok Koh 				inl_pad = 0;
14346ce84bd8SYongseok Koh 				do_inline =
14356ce84bd8SYongseok Koh 					length <= txq->inline_max_packet_sz &&
14366ce84bd8SYongseok Koh 					sizeof(inl_hdr) + length <= mpw_room &&
14376ce84bd8SYongseok Koh 					!txq->mpw_hdr_dseg;
14386ce84bd8SYongseok Koh 			}
14396ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
14406ce84bd8SYongseok Koh 		} else {
14416ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
14426ce84bd8SYongseok Koh 			 * Inlininig is possible when:
14436ce84bd8SYongseok Koh 			 * - length is less than configured value
14446ce84bd8SYongseok Koh 			 * - length fits for remaining space
14456ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
14466ce84bd8SYongseok Koh 			 */
14476ce84bd8SYongseok Koh 			do_inline =
14486ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
14496ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
14506ce84bd8SYongseok Koh 				 mpw_room &&
14516ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
14526ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
14536ce84bd8SYongseok Koh 		}
14546ce84bd8SYongseok Koh 		/* Multi-segment packets must be alone in their MPW. */
14556ce84bd8SYongseok Koh 		assert((segs_n == 1) || (mpw.pkts_n == 0));
14566ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) {
14576ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14586ce84bd8SYongseok Koh 			length = 0;
14596ce84bd8SYongseok Koh #endif
14606ce84bd8SYongseok Koh 			do {
14616ce84bd8SYongseok Koh 				volatile struct mlx5_wqe_data_seg *dseg;
14626ce84bd8SYongseok Koh 
14636ce84bd8SYongseok Koh 				assert(buf);
14648c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
14656ce84bd8SYongseok Koh 				dseg = mpw.data.dseg[mpw.pkts_n];
14666ce84bd8SYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
14676ce84bd8SYongseok Koh 				*dseg = (struct mlx5_wqe_data_seg){
14686b30a6a8SShachar Beiser 					.byte_count = rte_cpu_to_be_32(
14696b30a6a8SShachar Beiser 								DATA_LEN(buf)),
14706cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
14716b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
14726ce84bd8SYongseok Koh 				};
14736ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14746ce84bd8SYongseok Koh 				length += DATA_LEN(buf);
14756ce84bd8SYongseok Koh #endif
14766ce84bd8SYongseok Koh 				buf = buf->next;
14776ce84bd8SYongseok Koh 				++j;
14786ce84bd8SYongseok Koh 				++mpw.pkts_n;
14796ce84bd8SYongseok Koh 			} while (--segs_n);
14806ce84bd8SYongseok Koh 			/* A multi-segmented packet takes one MPW session.
14816ce84bd8SYongseok Koh 			 * TODO: Pack more multi-segmented packets if possible.
14826ce84bd8SYongseok Koh 			 */
14836ce84bd8SYongseok Koh 			mlx5_mpw_close(txq, &mpw);
14846ce84bd8SYongseok Koh 			if (mpw.pkts_n < 3)
14856ce84bd8SYongseok Koh 				max_wqe--;
14866ce84bd8SYongseok Koh 			else
14876ce84bd8SYongseok Koh 				max_wqe -= 2;
14886ce84bd8SYongseok Koh 		} else if (do_inline) {
14896ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
14906ce84bd8SYongseok Koh 			unsigned int max;
14916ce84bd8SYongseok Koh 
14926ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14936ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14946b30a6a8SShachar Beiser 			inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG);
14956ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14966ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14976ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
14986ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
14996ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
15006ce84bd8SYongseok Koh 			/* Copy inline header. */
15016ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
15026ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
15036ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
15046ce84bd8SYongseok Koh 					  &inl_hdr,
15056ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
15066ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
15076ce84bd8SYongseok Koh 					  max);
15086ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
15096ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
15106ce84bd8SYongseok Koh 			/* Copy packet data. */
15116ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
15126ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
15136ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
15146ce84bd8SYongseok Koh 					  (void *)addr,
15156ce84bd8SYongseok Koh 					  length,
15166ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
15176ce84bd8SYongseok Koh 					  max);
15186ce84bd8SYongseok Koh 			++mpw.pkts_n;
15196ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
15206ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
15216ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
15226ce84bd8SYongseok Koh 			 */
15236ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
15246ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
15256ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
15266ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
15276ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
15286ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
15296ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
15306ce84bd8SYongseok Koh 		} else {
15316ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
15326ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
15336ce84bd8SYongseok Koh 
15346ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
15356ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
15366ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
15376ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
15386ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
15396ce84bd8SYongseok Koh 						+ inl_pad)))
15406ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
15416ce84bd8SYongseok Koh 			else
15426ce84bd8SYongseok Koh 				dseg = (volatile void *)
15436ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
15446ce84bd8SYongseok Koh 					 inl_pad);
15458c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
15466ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
15476ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
15486ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
15496ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
15506b30a6a8SShachar Beiser 			naddr = rte_cpu_to_be_64(addr);
15516ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
15526b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
15536cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
15546ce84bd8SYongseok Koh 				naddr,
15556ce84bd8SYongseok Koh 				naddr >> 32,
15566ce84bd8SYongseok Koh 			};
15576ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
15586ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
15596ce84bd8SYongseok Koh 			++j;
15606ce84bd8SYongseok Koh 			++mpw.pkts_n;
15616ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
15626ce84bd8SYongseok Koh 			inl_pad = 0;
15636ce84bd8SYongseok Koh 		}
15646ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15656ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
15666ce84bd8SYongseok Koh 		txq->stats.obytes += length;
15676ce84bd8SYongseok Koh #endif
15686ce84bd8SYongseok Koh 		++i;
15696ce84bd8SYongseok Koh 	} while (i < pkts_n);
15706ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
15716ce84bd8SYongseok Koh 	if (unlikely(i == 0))
15726ce84bd8SYongseok Koh 		return 0;
15736ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
15746ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
15756ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
15766ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
15776ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
15786ce84bd8SYongseok Koh 
15796ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
15806b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
15816ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
15826ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
15836ce84bd8SYongseok Koh 		txq->elts_comp = 0;
15846ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
15856ce84bd8SYongseok Koh 		txq->cq_pi++;
15866ce84bd8SYongseok Koh 	} else {
15876ce84bd8SYongseok Koh 		txq->elts_comp += j;
15886ce84bd8SYongseok Koh 	}
15896ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15906ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
15916ce84bd8SYongseok Koh 	txq->stats.opackets += i;
15926ce84bd8SYongseok Koh #endif
15936ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
15946ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
15956ce84bd8SYongseok Koh 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
15966ce84bd8SYongseok Koh 		mlx5_mpw_close(txq, &mpw);
15976ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
15986ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
15996ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
16006ce84bd8SYongseok Koh 	return i;
16016ce84bd8SYongseok Koh }
16026ce84bd8SYongseok Koh 
16036ce84bd8SYongseok Koh /**
160467fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
160567fa62bcSAdrien Mazarguil  *
16066218063bSNélio Laranjeiro  * @param[in] cqe
16076218063bSNélio Laranjeiro  *   Pointer to CQE.
160867fa62bcSAdrien Mazarguil  *
160978a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
161078a38edfSJianfeng Tan  *
161167fa62bcSAdrien Mazarguil  * @return
161267fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
161367fa62bcSAdrien Mazarguil  */
161467fa62bcSAdrien Mazarguil static inline uint32_t
161597267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
161667fa62bcSAdrien Mazarguil {
1617ea16068cSYongseok Koh 	uint8_t idx;
1618ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
1619ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
162067fa62bcSAdrien Mazarguil 
1621ea16068cSYongseok Koh 	/*
1622ea16068cSYongseok Koh 	 * The index to the array should have:
1623ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
1624ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
1625ea16068cSYongseok Koh 	 * bit[5] = ip_frag
1626ea16068cSYongseok Koh 	 * bit[6] = tunneled
1627ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
1628ea16068cSYongseok Koh 	 */
1629ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
1630ea16068cSYongseok Koh 	return mlx5_ptype_table[idx];
163167fa62bcSAdrien Mazarguil }
163267fa62bcSAdrien Mazarguil 
163367fa62bcSAdrien Mazarguil /**
163499c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
163599c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
163699c12dccSNélio Laranjeiro  * been processed.
163799c12dccSNélio Laranjeiro  *
163899c12dccSNélio Laranjeiro  * @param rxq
163999c12dccSNélio Laranjeiro  *   Pointer to RX queue.
164099c12dccSNélio Laranjeiro  * @param cqe
164199c12dccSNélio Laranjeiro  *   CQE to process.
1642ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1643ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
164499c12dccSNélio Laranjeiro  *
164599c12dccSNélio Laranjeiro  * @return
164699c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
164799c12dccSNélio Laranjeiro  *   with error.
164899c12dccSNélio Laranjeiro  */
164999c12dccSNélio Laranjeiro static inline int
165097267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
1651ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
165299c12dccSNélio Laranjeiro {
165399c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
165499c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
165599c12dccSNélio Laranjeiro 	int len = 0;
1656d2e842d0SYongseok Koh 	uint16_t idx, end;
165799c12dccSNélio Laranjeiro 
165899c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
165999c12dccSNélio Laranjeiro 	if (zip->ai) {
166099c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
166199c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
16624aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
166399c12dccSNélio Laranjeiro 
16646b30a6a8SShachar Beiser 		len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
16656b30a6a8SShachar Beiser 		*rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result);
166699c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1667d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1668d2e842d0SYongseok Koh 			idx = zip->ca;
1669d2e842d0SYongseok Koh 			end = zip->na;
1670d2e842d0SYongseok Koh 			while (idx != end) {
1671d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1672d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1673d2e842d0SYongseok Koh 				++idx;
1674d2e842d0SYongseok Koh 			}
167599c12dccSNélio Laranjeiro 			/*
167699c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
167799c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
167899c12dccSNélio Laranjeiro 			 * ring for software use.
167999c12dccSNélio Laranjeiro 			 */
168099c12dccSNélio Laranjeiro 			zip->ca = zip->na;
168199c12dccSNélio Laranjeiro 			zip->na += 8;
168299c12dccSNélio Laranjeiro 		}
168399c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1684d2e842d0SYongseok Koh 			/* Invalidate the rest */
1685d2e842d0SYongseok Koh 			idx = zip->ca;
1686d2e842d0SYongseok Koh 			end = zip->cq_ci;
168799c12dccSNélio Laranjeiro 
168899c12dccSNélio Laranjeiro 			while (idx != end) {
168997267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
169099c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
169199c12dccSNélio Laranjeiro 				++idx;
169299c12dccSNélio Laranjeiro 			}
169399c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
169499c12dccSNélio Laranjeiro 			zip->ai = 0;
169599c12dccSNélio Laranjeiro 		}
169699c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
169799c12dccSNélio Laranjeiro 	} else {
169899c12dccSNélio Laranjeiro 		int ret;
169999c12dccSNélio Laranjeiro 		int8_t op_own;
170099c12dccSNélio Laranjeiro 
170197267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
170299c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
170399c12dccSNélio Laranjeiro 			return 0;
170499c12dccSNélio Laranjeiro 		++rxq->cq_ci;
170599c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
170699c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
170799c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
170899c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
170999c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
17104aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
171199c12dccSNélio Laranjeiro 
171299c12dccSNélio Laranjeiro 			/* Fix endianness. */
17136b30a6a8SShachar Beiser 			zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
171499c12dccSNélio Laranjeiro 			/*
171599c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
171699c12dccSNélio Laranjeiro 			 * check_cqe64().
171799c12dccSNélio Laranjeiro 			 *
171899c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
171999c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
172099c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
172199c12dccSNélio Laranjeiro 			 */
1722d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
172399c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
172499c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
172599c12dccSNélio Laranjeiro 			--rxq->cq_ci;
172699c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
172799c12dccSNélio Laranjeiro 			/* Get packet size to return. */
17286b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
17296b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result);
173099c12dccSNélio Laranjeiro 			zip->ai = 1;
1731d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1732d2e842d0SYongseok Koh 			idx = zip->ca;
1733d2e842d0SYongseok Koh 			end = zip->cq_ci;
1734d2e842d0SYongseok Koh 			while (idx != end) {
1735d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1736d2e842d0SYongseok Koh 				++idx;
1737d2e842d0SYongseok Koh 			}
173899c12dccSNélio Laranjeiro 		} else {
17396b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32(cqe->byte_cnt);
17406b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res);
174199c12dccSNélio Laranjeiro 		}
174299c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
174399c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
174499c12dccSNélio Laranjeiro 			return -1;
174599c12dccSNélio Laranjeiro 	}
174699c12dccSNélio Laranjeiro 	return len;
174799c12dccSNélio Laranjeiro }
174899c12dccSNélio Laranjeiro 
174999c12dccSNélio Laranjeiro /**
175067fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
175167fa62bcSAdrien Mazarguil  *
175267fa62bcSAdrien Mazarguil  * @param[in] rxq
175367fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
17546218063bSNélio Laranjeiro  * @param[in] cqe
17556218063bSNélio Laranjeiro  *   Pointer to CQE.
175667fa62bcSAdrien Mazarguil  *
175767fa62bcSAdrien Mazarguil  * @return
175867fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
175967fa62bcSAdrien Mazarguil  */
176067fa62bcSAdrien Mazarguil static inline uint32_t
176197267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
176267fa62bcSAdrien Mazarguil {
176367fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
17646b30a6a8SShachar Beiser 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
176567fa62bcSAdrien Mazarguil 
17660603df73SNélio Laranjeiro 	ol_flags =
17670603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17680603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
17690603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
17700603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17710603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
177283e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
177397267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
177467fa62bcSAdrien Mazarguil 		ol_flags |=
17750603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17760603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
177783e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
17780603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17790603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
178083e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
178167fa62bcSAdrien Mazarguil 	return ol_flags;
178267fa62bcSAdrien Mazarguil }
178367fa62bcSAdrien Mazarguil 
178467fa62bcSAdrien Mazarguil /**
17852e22920bSAdrien Mazarguil  * DPDK callback for RX.
17862e22920bSAdrien Mazarguil  *
17872e22920bSAdrien Mazarguil  * @param dpdk_rxq
17882e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
17892e22920bSAdrien Mazarguil  * @param[out] pkts
17902e22920bSAdrien Mazarguil  *   Array to store received packets.
17912e22920bSAdrien Mazarguil  * @param pkts_n
17922e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
17932e22920bSAdrien Mazarguil  *
17942e22920bSAdrien Mazarguil  * @return
17952e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
17962e22920bSAdrien Mazarguil  */
17972e22920bSAdrien Mazarguil uint16_t
17982e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
17992e22920bSAdrien Mazarguil {
18006218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
1801b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1802e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
18039964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
18049964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
18059964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
180697267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
180797267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
18089964b965SNélio Laranjeiro 	unsigned int i = 0;
18099964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
18104e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
18112e22920bSAdrien Mazarguil 
18129964b965SNélio Laranjeiro 	while (pkts_n) {
18139964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
18149964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
18159964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1816ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
18179964b965SNélio Laranjeiro 
18189964b965SNélio Laranjeiro 		if (pkt)
18199964b965SNélio Laranjeiro 			NEXT(seg) = rep;
18209964b965SNélio Laranjeiro 		seg = rep;
18219964b965SNélio Laranjeiro 		rte_prefetch0(seg);
18226218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
18239964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1824fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
18252e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
182615a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
182715a756b6SSagi Grimberg 			if (!pkt) {
182815a756b6SSagi Grimberg 				/*
182915a756b6SSagi Grimberg 				 * no buffers before we even started,
183015a756b6SSagi Grimberg 				 * bail out silently.
183115a756b6SSagi Grimberg 				 */
183215a756b6SSagi Grimberg 				break;
183315a756b6SSagi Grimberg 			}
1834a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1835a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1836fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
18378f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
18388f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
18391f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1840fe5fe382SNélio Laranjeiro 				pkt = rep;
18419964b965SNélio Laranjeiro 			}
18426218063bSNélio Laranjeiro 			break;
18432e22920bSAdrien Mazarguil 		}
18449964b965SNélio Laranjeiro 		if (!pkt) {
184597267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1846ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1847ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1848ecf60761SNélio Laranjeiro 			if (!len) {
18491f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
18506218063bSNélio Laranjeiro 				break;
18516218063bSNélio Laranjeiro 			}
185299c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
185399c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
18541f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
185599c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
185699c12dccSNélio Laranjeiro 				goto skip;
185799c12dccSNélio Laranjeiro 			}
18589964b965SNélio Laranjeiro 			pkt = seg;
18599964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
18609964b965SNélio Laranjeiro 			/* Update packet information. */
186148dfc20fSYongseok Koh 			pkt->packet_type = rxq_cq_to_pkt_type(cqe);
18620ac64846SMaxime Leroy 			pkt->ol_flags = 0;
186336ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1864ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1865ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1866ecf60761SNélio Laranjeiro 			}
1867c604f619SNélio Laranjeiro 			if (rxq->mark &&
1868c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1869b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
1870b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
18716b30a6a8SShachar Beiser 				    rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
1872b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
1873b268a3eeSNélio Laranjeiro 
1874b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
1875ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
1876b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
1877b268a3eeSNélio Laranjeiro 				}
1878ea3bc3b1SNélio Laranjeiro 			}
187948dfc20fSYongseok Koh 			if (rxq->csum | rxq->csum_l2tun)
18806703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
18816703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
18826703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
18836b30a6a8SShachar Beiser 			     rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
18846218063bSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_VLAN_PKT |
1885b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
18866b30a6a8SShachar Beiser 				pkt->vlan_tci =
18876b30a6a8SShachar Beiser 					rte_be_to_cpu_16(cqe->vlan_info);
1888f3db9489SYaacov Hazan 			}
18896218063bSNélio Laranjeiro 			if (rxq->crc_present)
18906218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
18916218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
18929964b965SNélio Laranjeiro 		}
18939964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
18949964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
18959964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
18969964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
18979964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
18989964b965SNélio Laranjeiro 		/*
18999964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
19009964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
19019964b965SNélio Laranjeiro 		 * changes.
19029964b965SNélio Laranjeiro 		 */
19036b30a6a8SShachar Beiser 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
19049964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
19059964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
19069964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
19079964b965SNélio Laranjeiro 			++rq_ci;
19089964b965SNélio Laranjeiro 			continue;
19099964b965SNélio Laranjeiro 		}
19109964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
191187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
191287011737SAdrien Mazarguil 		/* Increment bytes counter. */
19139964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
191487011737SAdrien Mazarguil #endif
19156218063bSNélio Laranjeiro 		/* Return packet. */
19166218063bSNélio Laranjeiro 		*(pkts++) = pkt;
19179964b965SNélio Laranjeiro 		pkt = NULL;
19189964b965SNélio Laranjeiro 		--pkts_n;
19199964b965SNélio Laranjeiro 		++i;
192099c12dccSNélio Laranjeiro skip:
19219964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
19229964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
19236218063bSNélio Laranjeiro 		++rq_ci;
19249964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
19252e22920bSAdrien Mazarguil 	}
19269964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
19272e22920bSAdrien Mazarguil 		return 0;
19286218063bSNélio Laranjeiro 	/* Update the consumer index. */
19299964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
19306218063bSNélio Laranjeiro 	rte_wmb();
19316b30a6a8SShachar Beiser 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
19326218063bSNélio Laranjeiro 	rte_wmb();
19336b30a6a8SShachar Beiser 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
193487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
193587011737SAdrien Mazarguil 	/* Increment packets counter. */
19369964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
193787011737SAdrien Mazarguil #endif
19389964b965SNélio Laranjeiro 	return i;
19392e22920bSAdrien Mazarguil }
19402e22920bSAdrien Mazarguil 
19412e22920bSAdrien Mazarguil /**
19422e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
19432e22920bSAdrien Mazarguil  *
19442e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19452e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19462e22920bSAdrien Mazarguil  *
19472e22920bSAdrien Mazarguil  * @param dpdk_txq
19482e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
19492e22920bSAdrien Mazarguil  * @param[in] pkts
19502e22920bSAdrien Mazarguil  *   Packets to transmit.
19512e22920bSAdrien Mazarguil  * @param pkts_n
19522e22920bSAdrien Mazarguil  *   Number of packets in array.
19532e22920bSAdrien Mazarguil  *
19542e22920bSAdrien Mazarguil  * @return
19552e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
19562e22920bSAdrien Mazarguil  */
19572e22920bSAdrien Mazarguil uint16_t
19582e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19592e22920bSAdrien Mazarguil {
19602e22920bSAdrien Mazarguil 	(void)dpdk_txq;
19612e22920bSAdrien Mazarguil 	(void)pkts;
19622e22920bSAdrien Mazarguil 	(void)pkts_n;
19632e22920bSAdrien Mazarguil 	return 0;
19642e22920bSAdrien Mazarguil }
19652e22920bSAdrien Mazarguil 
19662e22920bSAdrien Mazarguil /**
19672e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
19682e22920bSAdrien Mazarguil  *
19692e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19702e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19712e22920bSAdrien Mazarguil  *
19722e22920bSAdrien Mazarguil  * @param dpdk_rxq
19732e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
19742e22920bSAdrien Mazarguil  * @param[out] pkts
19752e22920bSAdrien Mazarguil  *   Array to store received packets.
19762e22920bSAdrien Mazarguil  * @param pkts_n
19772e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
19782e22920bSAdrien Mazarguil  *
19792e22920bSAdrien Mazarguil  * @return
19802e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
19812e22920bSAdrien Mazarguil  */
19822e22920bSAdrien Mazarguil uint16_t
19832e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19842e22920bSAdrien Mazarguil {
19852e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
19862e22920bSAdrien Mazarguil 	(void)pkts;
19872e22920bSAdrien Mazarguil 	(void)pkts_n;
19882e22920bSAdrien Mazarguil 	return 0;
19892e22920bSAdrien Mazarguil }
19906cb559d6SYongseok Koh 
19916cb559d6SYongseok Koh /*
19926cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
19936cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
19946cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
19956cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
19966cb559d6SYongseok Koh  */
19976cb559d6SYongseok Koh 
19986cb559d6SYongseok Koh uint16_t __attribute__((weak))
19996cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
20006cb559d6SYongseok Koh {
20016cb559d6SYongseok Koh 	(void)dpdk_txq;
20026cb559d6SYongseok Koh 	(void)pkts;
20036cb559d6SYongseok Koh 	(void)pkts_n;
20046cb559d6SYongseok Koh 	return 0;
20056cb559d6SYongseok Koh }
20066cb559d6SYongseok Koh 
20076cb559d6SYongseok Koh uint16_t __attribute__((weak))
20086cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
20096cb559d6SYongseok Koh {
20106cb559d6SYongseok Koh 	(void)dpdk_txq;
20116cb559d6SYongseok Koh 	(void)pkts;
20126cb559d6SYongseok Koh 	(void)pkts_n;
20136cb559d6SYongseok Koh 	return 0;
20146cb559d6SYongseok Koh }
20156cb559d6SYongseok Koh 
20166cb559d6SYongseok Koh uint16_t __attribute__((weak))
20176cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
20186cb559d6SYongseok Koh {
20196cb559d6SYongseok Koh 	(void)dpdk_rxq;
20206cb559d6SYongseok Koh 	(void)pkts;
20216cb559d6SYongseok Koh 	(void)pkts_n;
20226cb559d6SYongseok Koh 	return 0;
20236cb559d6SYongseok Koh }
20246cb559d6SYongseok Koh 
20256cb559d6SYongseok Koh int __attribute__((weak))
20266cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv)
20276cb559d6SYongseok Koh {
20286cb559d6SYongseok Koh 	(void)priv;
20296cb559d6SYongseok Koh 	return -ENOTSUP;
20306cb559d6SYongseok Koh }
20316cb559d6SYongseok Koh 
20326cb559d6SYongseok Koh int __attribute__((weak))
20336cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv)
20346cb559d6SYongseok Koh {
20356cb559d6SYongseok Koh 	(void)priv;
20366cb559d6SYongseok Koh 	return -ENOTSUP;
20376cb559d6SYongseok Koh }
20386cb559d6SYongseok Koh 
20396cb559d6SYongseok Koh int __attribute__((weak))
20406cb559d6SYongseok Koh rxq_check_vec_support(struct rxq *rxq)
20416cb559d6SYongseok Koh {
20426cb559d6SYongseok Koh 	(void)rxq;
20436cb559d6SYongseok Koh 	return -ENOTSUP;
20446cb559d6SYongseok Koh }
20456cb559d6SYongseok Koh 
20466cb559d6SYongseok Koh int __attribute__((weak))
20476cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv)
20486cb559d6SYongseok Koh {
20496cb559d6SYongseok Koh 	(void)priv;
20506cb559d6SYongseok Koh 	return -ENOTSUP;
20516cb559d6SYongseok Koh }
2052