xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 96fc8d6561b1b1348af97c2ed275922315d228c4)
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>
456218063bSNélio Laranjeiro #include <infiniband/mlx5_hw.h>
466218063bSNélio Laranjeiro #include <infiniband/arch.h>
472e22920bSAdrien Mazarguil #ifdef PEDANTIC
48fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
492e22920bSAdrien Mazarguil #endif
502e22920bSAdrien Mazarguil 
512e22920bSAdrien Mazarguil #include <rte_mbuf.h>
522e22920bSAdrien Mazarguil #include <rte_mempool.h>
532e22920bSAdrien Mazarguil #include <rte_prefetch.h>
542e22920bSAdrien Mazarguil #include <rte_common.h>
552e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
566218063bSNélio Laranjeiro #include <rte_ether.h>
572e22920bSAdrien Mazarguil 
582e22920bSAdrien Mazarguil #include "mlx5.h"
592e22920bSAdrien Mazarguil #include "mlx5_utils.h"
602e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
61f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
622e22920bSAdrien Mazarguil #include "mlx5_defs.h"
636218063bSNélio Laranjeiro #include "mlx5_prm.h"
646218063bSNélio Laranjeiro 
65c0583d98SJerin Jacob static __rte_always_inline uint32_t
66c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe);
67ff1807a3SNélio Laranjeiro 
68c0583d98SJerin Jacob static __rte_always_inline int
69ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
70c0583d98SJerin Jacob 		 uint16_t cqe_cnt, uint32_t *rss_hash);
71ff1807a3SNélio Laranjeiro 
72c0583d98SJerin Jacob static __rte_always_inline uint32_t
73c0583d98SJerin Jacob rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe);
74ff1807a3SNélio Laranjeiro 
75ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
76ea16068cSYongseok Koh 	[0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
77ea16068cSYongseok Koh };
78ea16068cSYongseok Koh 
79ea16068cSYongseok Koh /**
80ea16068cSYongseok Koh  * Build a table to translate Rx completion flags to packet type.
81ea16068cSYongseok Koh  *
82ea16068cSYongseok Koh  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
83ea16068cSYongseok Koh  */
84ea16068cSYongseok Koh void
85ea16068cSYongseok Koh mlx5_set_ptype_table(void)
86ea16068cSYongseok Koh {
87ea16068cSYongseok Koh 	unsigned int i;
88ea16068cSYongseok Koh 	uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
89ea16068cSYongseok Koh 
909807f113SYongseok Koh 	/* Last entry must not be overwritten, reserved for errored packet. */
919807f113SYongseok Koh 	for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
92ea16068cSYongseok Koh 		(*p)[i] = RTE_PTYPE_UNKNOWN;
936cb559d6SYongseok Koh 	/*
946cb559d6SYongseok Koh 	 * The index to the array should have:
95ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
96ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
97ea16068cSYongseok Koh 	 * bit[5] = ip_frag
98ea16068cSYongseok Koh 	 * bit[6] = tunneled
99ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
10099c12dccSNélio Laranjeiro 	 */
101ea16068cSYongseok Koh 	/* L3 */
102ea16068cSYongseok Koh 	(*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
103ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
104ea16068cSYongseok Koh 	(*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
105ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
106ea16068cSYongseok Koh 	/* Fragmented */
107ea16068cSYongseok Koh 	(*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
108ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
109ea16068cSYongseok Koh 	(*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
110ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
111ea16068cSYongseok Koh 	/* TCP */
112ea16068cSYongseok Koh 	(*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
113ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
114ea16068cSYongseok Koh 	(*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
115ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
116ea16068cSYongseok Koh 	/* UDP */
117ea16068cSYongseok Koh 	(*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
118ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
119ea16068cSYongseok Koh 	(*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
120ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
121ea16068cSYongseok Koh 	/* Repeat with outer_l3_type being set. Just in case. */
122ea16068cSYongseok Koh 	(*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
123ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
124ea16068cSYongseok Koh 	(*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
125ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
126ea16068cSYongseok Koh 	(*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
127ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
128ea16068cSYongseok Koh 	(*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
129ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
130ea16068cSYongseok Koh 	(*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
131ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
132ea16068cSYongseok Koh 	(*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
133ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
134ea16068cSYongseok Koh 	(*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
135ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
136ea16068cSYongseok Koh 	(*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
137ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
138ea16068cSYongseok Koh 	/* Tunneled - L3 */
139ea16068cSYongseok Koh 	(*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
140ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
141ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
142ea16068cSYongseok Koh 	(*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
143ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
144ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
145ea16068cSYongseok Koh 	(*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
146ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
147ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
148ea16068cSYongseok Koh 	(*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
149ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
150ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
151ea16068cSYongseok Koh 	/* Tunneled - Fragmented */
152ea16068cSYongseok Koh 	(*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
153ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
154ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
155ea16068cSYongseok Koh 	(*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
156ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
157ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
158ea16068cSYongseok Koh 	(*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
159ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
160ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
161ea16068cSYongseok Koh 	(*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
162ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
163ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
164ea16068cSYongseok Koh 	/* Tunneled - TCP */
165ea16068cSYongseok Koh 	(*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
166ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
167ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
168ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
169ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
170ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
171ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
172ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
173ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
174ea16068cSYongseok Koh 	(*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
175ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
176ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
177ea16068cSYongseok Koh 	/* Tunneled - UDP */
178ea16068cSYongseok Koh 	(*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
179ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
180ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
181ea16068cSYongseok Koh 	(*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
182ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
183ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
184ea16068cSYongseok Koh 	(*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
185ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
186ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
187ea16068cSYongseok Koh 	(*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
188ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
189ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
190ea16068cSYongseok Koh }
191fdcb0f53SNélio Laranjeiro 
1922e22920bSAdrien Mazarguil /**
1936ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
1946ce84bd8SYongseok Koh  *
1956ce84bd8SYongseok Koh  * @param txq
1966ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
1976ce84bd8SYongseok Koh  * @param addr
1986ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
1996ce84bd8SYongseok Koh  *
2006ce84bd8SYongseok Koh  * @return
2016ce84bd8SYongseok Koh  *   Size of tailroom.
2026ce84bd8SYongseok Koh  */
2036ce84bd8SYongseok Koh static inline size_t
2046ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr)
2056ce84bd8SYongseok Koh {
2066ce84bd8SYongseok Koh 	size_t tailroom;
2076ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
2086ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
2096ce84bd8SYongseok Koh 		   (uintptr_t)addr;
2106ce84bd8SYongseok Koh 	return tailroom;
2116ce84bd8SYongseok Koh }
2126ce84bd8SYongseok Koh 
2136ce84bd8SYongseok Koh /**
2146ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
2156ce84bd8SYongseok Koh  *
2166ce84bd8SYongseok Koh  * @param dst
2176ce84bd8SYongseok Koh  *   Pointer to destination.
2186ce84bd8SYongseok Koh  * @param src
2196ce84bd8SYongseok Koh  *   Pointer to source.
2206ce84bd8SYongseok Koh  * @param n
2216ce84bd8SYongseok Koh  *   Number of bytes to copy.
2226ce84bd8SYongseok Koh  * @param base
2236ce84bd8SYongseok Koh  *   Pointer to head of queue.
2246ce84bd8SYongseok Koh  * @param tailroom
2256ce84bd8SYongseok Koh  *   Size of tailroom from dst.
2266ce84bd8SYongseok Koh  *
2276ce84bd8SYongseok Koh  * @return
2286ce84bd8SYongseok Koh  *   Pointer after copied data.
2296ce84bd8SYongseok Koh  */
2306ce84bd8SYongseok Koh static inline void *
2316ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
2326ce84bd8SYongseok Koh 		void *base, size_t tailroom)
2336ce84bd8SYongseok Koh {
2346ce84bd8SYongseok Koh 	void *ret;
2356ce84bd8SYongseok Koh 
2366ce84bd8SYongseok Koh 	if (n > tailroom) {
2376ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
2386ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
2396ce84bd8SYongseok Koh 			   n - tailroom);
2406ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
2416ce84bd8SYongseok Koh 	} else {
2426ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
2436ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
2446ce84bd8SYongseok Koh 	}
2456ce84bd8SYongseok Koh 	return ret;
2466ce84bd8SYongseok Koh }
2476ce84bd8SYongseok Koh 
2486ce84bd8SYongseok Koh /**
2498788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
2508788fec1SOlivier Matz  *
2518788fec1SOlivier Matz  * @param tx_queue
2528788fec1SOlivier Matz  *   The tx queue.
2538788fec1SOlivier Matz  * @param[in] offset
2548788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2558788fec1SOlivier Matz  *
2568788fec1SOlivier Matz  * @return
2578788fec1SOlivier Matz  *   The status of the tx descriptor.
2588788fec1SOlivier Matz  */
2598788fec1SOlivier Matz int
2608788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
2618788fec1SOlivier Matz {
2628788fec1SOlivier Matz 	struct txq *txq = tx_queue;
2638c819a69SYongseok Koh 	uint16_t used;
2648788fec1SOlivier Matz 
2656cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
2668c819a69SYongseok Koh 	used = txq->elts_head - txq->elts_tail;
2678788fec1SOlivier Matz 	if (offset < used)
2688788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
2698788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
2708788fec1SOlivier Matz }
2718788fec1SOlivier Matz 
2728788fec1SOlivier Matz /**
2738788fec1SOlivier Matz  * DPDK callback to check the status of a rx descriptor.
2748788fec1SOlivier Matz  *
2758788fec1SOlivier Matz  * @param rx_queue
2768788fec1SOlivier Matz  *   The rx queue.
2778788fec1SOlivier Matz  * @param[in] offset
2788788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2798788fec1SOlivier Matz  *
2808788fec1SOlivier Matz  * @return
2818788fec1SOlivier Matz  *   The status of the tx descriptor.
2828788fec1SOlivier Matz  */
2838788fec1SOlivier Matz int
2848788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
2858788fec1SOlivier Matz {
2868788fec1SOlivier Matz 	struct rxq *rxq = rx_queue;
2878788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
2888788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
2898788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
2908788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
2918788fec1SOlivier Matz 	unsigned int cq_ci;
2928788fec1SOlivier Matz 	unsigned int used;
2938788fec1SOlivier Matz 
2948788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
2958788fec1SOlivier Matz 	if (zip->ai) {
2968788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
2978788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
2988788fec1SOlivier Matz 	} else {
2998788fec1SOlivier Matz 		used = 0;
3008788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
3018788fec1SOlivier Matz 	}
3028788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3038788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
3048788fec1SOlivier Matz 		int8_t op_own;
3058788fec1SOlivier Matz 		unsigned int n;
3068788fec1SOlivier Matz 
3078788fec1SOlivier Matz 		op_own = cqe->op_own;
3088788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
3098788fec1SOlivier Matz 			n = ntohl(cqe->byte_cnt);
3108788fec1SOlivier Matz 		else
3118788fec1SOlivier Matz 			n = 1;
3128788fec1SOlivier Matz 		cq_ci += n;
3138788fec1SOlivier Matz 		used += n;
3148788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3158788fec1SOlivier Matz 	}
3168788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
3178788fec1SOlivier Matz 	if (offset < used)
3188788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
3198788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
3208788fec1SOlivier Matz }
3218788fec1SOlivier Matz 
3228788fec1SOlivier Matz /**
3232e22920bSAdrien Mazarguil  * DPDK callback for TX.
3242e22920bSAdrien Mazarguil  *
3252e22920bSAdrien Mazarguil  * @param dpdk_txq
3262e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
3272e22920bSAdrien Mazarguil  * @param[in] pkts
3282e22920bSAdrien Mazarguil  *   Packets to transmit.
3292e22920bSAdrien Mazarguil  * @param pkts_n
3302e22920bSAdrien Mazarguil  *   Number of packets in array.
3312e22920bSAdrien Mazarguil  *
3322e22920bSAdrien Mazarguil  * @return
3332e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
3342e22920bSAdrien Mazarguil  */
3352e22920bSAdrien Mazarguil uint16_t
3362e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
3372e22920bSAdrien Mazarguil {
3382e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
3391d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
3408c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
3418c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
342c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
343a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
3443f13f8c2SShahaf Shuler 	unsigned int k = 0;
3458c819a69SYongseok Koh 	uint16_t max_elts;
346ab76eab3SYongseok Koh 	unsigned int max_inline = txq->max_inline;
347ab76eab3SYongseok Koh 	const unsigned int inline_en = !!max_inline && txq->inline_en;
348f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
349c305090bSAdrien Mazarguil 	unsigned int comp;
3509a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
351ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
3526579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
3536579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
3546579c27cSNélio Laranjeiro 	uint8_t *raw;
3552e22920bSAdrien Mazarguil 
3561d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
3571d88ba17SNélio Laranjeiro 		return 0;
3585e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
359c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
3601d88ba17SNélio Laranjeiro 	/* Start processing. */
3616cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
3628c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
363f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
364f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
365f04f1d51SNélio Laranjeiro 		return 0;
366c3d62cc9SAdrien Mazarguil 	do {
3679a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
368573f54afSNélio Laranjeiro 		uint32_t length;
3698688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
370ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
3716579c27cSNélio Laranjeiro 		uintptr_t addr;
3729a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
3730d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
3743f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
375eef822ddSNélio Laranjeiro 		uint16_t ehdr;
3769a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
3773f13f8c2SShahaf Shuler 		uint64_t tso = 0;
37883daf156SShahaf Shuler 		uint16_t tso_segsz = 0;
3796579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
3806579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
3816579c27cSNélio Laranjeiro #endif
3822e22920bSAdrien Mazarguil 
3836579c27cSNélio Laranjeiro 		/* first_seg */
3843730e6c6SYongseok Koh 		buf = *pkts;
3856579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
386c3d62cc9SAdrien Mazarguil 		/*
387c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
388c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
389c3d62cc9SAdrien Mazarguil 		 */
390a5bf6af9SAdrien Mazarguil 		assert(segs_n);
3918c819a69SYongseok Koh 		if (max_elts < segs_n)
392c3d62cc9SAdrien Mazarguil 			break;
3938c819a69SYongseok Koh 		max_elts -= segs_n;
3946579c27cSNélio Laranjeiro 		--segs_n;
395f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
396f04f1d51SNélio Laranjeiro 			break;
3979a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
398fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
399fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
4003730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4013730e6c6SYongseok Koh 			rte_prefetch0(*(pkts + 1));
4026579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
4032e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
404eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
405eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
4066579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
4076579c27cSNélio Laranjeiro 		total_length = length;
4086579c27cSNélio Laranjeiro #endif
40924c14430SShahaf Shuler 		if (length < (MLX5_WQE_DWORD_SIZE + 2)) {
41024c14430SShahaf Shuler 			txq->stats.oerrors++;
411959be52eSNélio Laranjeiro 			break;
41224c14430SShahaf Shuler 		}
4132e22920bSAdrien Mazarguil 		/* Update element. */
4148c819a69SYongseok Koh 		(*txq->elts)[elts_head & elts_m] = buf;
4155e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
4163730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4173730e6c6SYongseok Koh 			rte_prefetch0(
4183730e6c6SYongseok Koh 			    rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
4191d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
4201d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
4211d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
422f5fde520SShahaf Shuler 			const uint64_t is_tunneled = buf->ol_flags &
423f5fde520SShahaf Shuler 						     (PKT_TX_TUNNEL_GRE |
424f5fde520SShahaf Shuler 						      PKT_TX_TUNNEL_VXLAN);
425f5fde520SShahaf Shuler 
426f5fde520SShahaf Shuler 			if (is_tunneled && txq->tunnel_en) {
427f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM |
428f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_INNER_CSUM;
429f5fde520SShahaf Shuler 				if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
430f5fde520SShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L3_CSUM;
431f5fde520SShahaf Shuler 			} else {
432f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_CSUM |
433f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_CSUM;
434f5fde520SShahaf Shuler 			}
4351d88ba17SNélio Laranjeiro 		}
436b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
4376579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
4386579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
4396579c27cSNélio Laranjeiro 			uint32_t vlan = htonl(0x81000000 | 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;
478*96fc8d65SShahaf Shuler 				if (unlikely(tso_segsz == 0)) {
479*96fc8d65SShahaf Shuler 					txq->stats.oerrors++;
480*96fc8d65SShahaf Shuler 					break;
481*96fc8d65SShahaf 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){
5173f13f8c2SShahaf Shuler 						     htonl(txq->wqe_ci << 8),
5183f13f8c2SShahaf Shuler 						     htonl(txq->qp_num_8s | 1),
5193f13f8c2SShahaf Shuler 						     0,
5203f13f8c2SShahaf Shuler 						     0,
5213f13f8c2SShahaf Shuler 					};
5223f13f8c2SShahaf Shuler 					ds = 1;
5233f13f8c2SShahaf Shuler 					total_length = 0;
5243f13f8c2SShahaf Shuler 					k++;
5253f13f8c2SShahaf Shuler 					goto next_wqe;
5263f13f8c2SShahaf Shuler 				}
5273f13f8c2SShahaf Shuler 			}
5283f13f8c2SShahaf Shuler 		}
5296579c27cSNélio Laranjeiro 		/* Inline if enough room. */
530ab76eab3SYongseok Koh 		if (inline_en || tso) {
531d8292497SYongseok Koh 			uint32_t inl;
532fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
533fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
534fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
535ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
5368fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
537d8292497SYongseok Koh 						   (pkt_inline_sz - 2) -
538d8292497SYongseok Koh 						   !!tso * sizeof(inl);
539ab76eab3SYongseok Koh 			uintptr_t addr_end = (addr + inline_room) &
5406579c27cSNélio Laranjeiro 					     ~(RTE_CACHE_LINE_SIZE - 1);
5418fcd6c2cSNélio Laranjeiro 			unsigned int copy_b = (addr_end > addr) ?
5428fcd6c2cSNélio Laranjeiro 				RTE_MIN((addr_end - addr), length) :
5438fcd6c2cSNélio Laranjeiro 				0;
5446579c27cSNélio Laranjeiro 
5458fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
546f04f1d51SNélio Laranjeiro 				/*
547f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
548f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
549f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
550f04f1d51SNélio Laranjeiro 				 */
5518fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
5528fcd6c2cSNélio Laranjeiro 
553f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
554f04f1d51SNélio Laranjeiro 					break;
555f04f1d51SNélio Laranjeiro 				max_wqe -= n;
5563f13f8c2SShahaf Shuler 				if (tso) {
557d8292497SYongseok Koh 					inl = htonl(copy_b | MLX5_INLINE_SEG);
5583f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5593f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
5603f13f8c2SShahaf Shuler 					raw += sizeof(inl);
5613f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
5623f13f8c2SShahaf Shuler 				}
5636579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
5646579c27cSNélio Laranjeiro 				addr += copy_b;
5656579c27cSNélio Laranjeiro 				length -= copy_b;
5666579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
5676579c27cSNélio Laranjeiro 			}
5686579c27cSNélio Laranjeiro 			/*
569786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
5706579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
5716579c27cSNélio Laranjeiro 			 */
5726579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
5736579c27cSNélio Laranjeiro 			if (length > 0) {
574f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
575f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
576f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
577f04f1d51SNélio Laranjeiro 						break;
578f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
579f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
580f04f1d51SNélio Laranjeiro 							   ds / 4);
581f04f1d51SNélio Laranjeiro 				} else {
5829a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
5836579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
5846579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
585f04f1d51SNélio Laranjeiro 				}
5866579c27cSNélio Laranjeiro 				goto use_dseg;
5876579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5886579c27cSNélio Laranjeiro 				goto next_pkt;
5896579c27cSNélio Laranjeiro 			} else {
590786b5c2dSShahaf Shuler 				/* dseg will be advance as part of next_seg */
591786b5c2dSShahaf Shuler 				dseg = (volatile rte_v128u32_t *)
592786b5c2dSShahaf Shuler 					((uintptr_t)wqe +
593786b5c2dSShahaf Shuler 					 ((ds - 1) * MLX5_WQE_DWORD_SIZE));
5946579c27cSNélio Laranjeiro 				goto next_seg;
5956579c27cSNélio Laranjeiro 			}
5966579c27cSNélio Laranjeiro 		} else {
5976579c27cSNélio Laranjeiro 			/*
5986579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
5996579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
6006579c27cSNélio Laranjeiro 			 */
6019a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
6026579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
6036579c27cSNélio Laranjeiro 			ds = 3;
6046579c27cSNélio Laranjeiro use_dseg:
6056579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
6069a7fa9f7SNélio Laranjeiro 			naddr = htonll(addr);
6079a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
6089a7fa9f7SNélio Laranjeiro 				htonl(length),
6096cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
6109a7fa9f7SNélio Laranjeiro 				naddr,
6119a7fa9f7SNélio Laranjeiro 				naddr >> 32,
6126579c27cSNélio Laranjeiro 			};
6136579c27cSNélio Laranjeiro 			++ds;
6146579c27cSNélio Laranjeiro 			if (!segs_n)
6156579c27cSNélio Laranjeiro 				goto next_pkt;
6166579c27cSNélio Laranjeiro 		}
6176579c27cSNélio Laranjeiro next_seg:
6186579c27cSNélio Laranjeiro 		assert(buf);
6196579c27cSNélio Laranjeiro 		assert(ds);
6206579c27cSNélio Laranjeiro 		assert(wqe);
621a5bf6af9SAdrien Mazarguil 		/*
622a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
623a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
624a5bf6af9SAdrien Mazarguil 		 * of data segment size.
625a5bf6af9SAdrien Mazarguil 		 */
6268688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
6276579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
628f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
629f04f1d51SNélio Laranjeiro 				break;
6309a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
631f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
632f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
633f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
6346579c27cSNélio Laranjeiro 		} else {
635a5bf6af9SAdrien Mazarguil 			++dseg;
6366579c27cSNélio Laranjeiro 		}
637a5bf6af9SAdrien Mazarguil 		++ds;
638a5bf6af9SAdrien Mazarguil 		buf = buf->next;
639a5bf6af9SAdrien Mazarguil 		assert(buf);
6406579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
641a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
6426579c27cSNélio Laranjeiro 		total_length += length;
643a5bf6af9SAdrien Mazarguil #endif
6446579c27cSNélio Laranjeiro 		/* Store segment information. */
6459a7fa9f7SNélio Laranjeiro 		naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t));
6469a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
6479a7fa9f7SNélio Laranjeiro 			htonl(length),
6486cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
6499a7fa9f7SNélio Laranjeiro 			naddr,
6509a7fa9f7SNélio Laranjeiro 			naddr >> 32,
6516579c27cSNélio Laranjeiro 		};
6528c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
653ac180a21SYongseok Koh 		++sg;
654ac180a21SYongseok Koh 		/* Advance counter only if all segs are successfully posted. */
6553730e6c6SYongseok Koh 		if (sg < segs_n)
6566579c27cSNélio Laranjeiro 			goto next_seg;
6573730e6c6SYongseok Koh 		else
658ac180a21SYongseok Koh 			j += sg;
6596579c27cSNélio Laranjeiro next_pkt:
660883ce172SShahaf Shuler 		if (ds > MLX5_DSEG_MAX) {
661883ce172SShahaf Shuler 			txq->stats.oerrors++;
662883ce172SShahaf Shuler 			break;
663883ce172SShahaf Shuler 		}
6648c819a69SYongseok Koh 		++elts_head;
6653730e6c6SYongseok Koh 		++pkts;
6666579c27cSNélio Laranjeiro 		++i;
667b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
6683f13f8c2SShahaf Shuler 		if (tso) {
6693f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
6703f13f8c2SShahaf Shuler 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO),
6713f13f8c2SShahaf Shuler 				htonl(txq->qp_num_8s | ds),
6723f13f8c2SShahaf Shuler 				0,
6733f13f8c2SShahaf Shuler 				0,
6743f13f8c2SShahaf Shuler 			};
6753f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
6763f13f8c2SShahaf Shuler 				0,
67783daf156SShahaf Shuler 				cs_flags | (htons(tso_segsz) << 16),
6783f13f8c2SShahaf Shuler 				0,
6793f13f8c2SShahaf Shuler 				(ehdr << 16) | htons(tso_header_sz),
6803f13f8c2SShahaf Shuler 			};
6813f13f8c2SShahaf Shuler 		} else {
6829a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
6839a7fa9f7SNélio Laranjeiro 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
6849a7fa9f7SNélio Laranjeiro 				htonl(txq->qp_num_8s | ds),
6859a7fa9f7SNélio Laranjeiro 				0,
6869a7fa9f7SNélio Laranjeiro 				0,
6879a7fa9f7SNélio Laranjeiro 			};
6889a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
6899a7fa9f7SNélio Laranjeiro 				0,
6909a7fa9f7SNélio Laranjeiro 				cs_flags,
6919a7fa9f7SNélio Laranjeiro 				0,
692eef822ddSNélio Laranjeiro 				(ehdr << 16) | htons(pkt_inline_sz),
6939a7fa9f7SNélio Laranjeiro 			};
6943f13f8c2SShahaf Shuler 		}
6953f13f8c2SShahaf Shuler next_wqe:
6966579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
697ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
698ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
69987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
700573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
7016579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
70287011737SAdrien Mazarguil #endif
7033730e6c6SYongseok Koh 	} while (i < pkts_n);
7042e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
7053f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
7062e22920bSAdrien Mazarguil 		return 0;
7078c819a69SYongseok Koh 	txq->elts_head += (i + j);
708c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
7093f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
710c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
711c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
712ac180a21SYongseok Koh 		last_wqe->ctrl2 = htonl(8);
713c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
714ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
715c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
716c305090bSAdrien Mazarguil 	} else {
717c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
718c305090bSAdrien Mazarguil 	}
71987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
72087011737SAdrien Mazarguil 	/* Increment sent packets counter. */
72187011737SAdrien Mazarguil 	txq->stats.opackets += i;
72287011737SAdrien Mazarguil #endif
7232e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
724ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
7252e22920bSAdrien Mazarguil 	return i;
7262e22920bSAdrien Mazarguil }
7272e22920bSAdrien Mazarguil 
7282e22920bSAdrien Mazarguil /**
729230189d9SNélio Laranjeiro  * Open a MPW session.
730230189d9SNélio Laranjeiro  *
731230189d9SNélio Laranjeiro  * @param txq
732230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
733230189d9SNélio Laranjeiro  * @param mpw
734230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
735230189d9SNélio Laranjeiro  * @param length
736230189d9SNélio Laranjeiro  *   Packet length.
737230189d9SNélio Laranjeiro  */
738230189d9SNélio Laranjeiro static inline void
739230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
740230189d9SNélio Laranjeiro {
741a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
742230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
743230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
744fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
745230189d9SNélio Laranjeiro 
746230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
747230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
748230189d9SNélio Laranjeiro 	mpw->len = length;
749230189d9SNélio Laranjeiro 	mpw->total_len = 0;
750fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
7518688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
7528688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
7538688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
7548688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
7558688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
7568688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
757c904ae25SNélio Laranjeiro 				  (txq->wqe_ci << 8) | MLX5_OPCODE_TSO);
7588688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
7598688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
7608688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
7618688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
7628688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
7638688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
764230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
765230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
766230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
767230189d9SNélio Laranjeiro }
768230189d9SNélio Laranjeiro 
769230189d9SNélio Laranjeiro /**
770230189d9SNélio Laranjeiro  * Close a MPW session.
771230189d9SNélio Laranjeiro  *
772230189d9SNélio Laranjeiro  * @param txq
773230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
774230189d9SNélio Laranjeiro  * @param mpw
775230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
776230189d9SNélio Laranjeiro  */
777230189d9SNélio Laranjeiro static inline void
778230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
779230189d9SNélio Laranjeiro {
780230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
781230189d9SNélio Laranjeiro 
782230189d9SNélio Laranjeiro 	/*
783230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
784230189d9SNélio Laranjeiro 	 * count as 2.
785230189d9SNélio Laranjeiro 	 */
7868688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num));
787230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
788230189d9SNélio Laranjeiro 	if (num < 3)
789230189d9SNélio Laranjeiro 		++txq->wqe_ci;
790230189d9SNélio Laranjeiro 	else
791230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
792fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
793fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
794230189d9SNélio Laranjeiro }
795230189d9SNélio Laranjeiro 
796230189d9SNélio Laranjeiro /**
797230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
798230189d9SNélio Laranjeiro  *
799230189d9SNélio Laranjeiro  * @param dpdk_txq
800230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
801230189d9SNélio Laranjeiro  * @param[in] pkts
802230189d9SNélio Laranjeiro  *   Packets to transmit.
803230189d9SNélio Laranjeiro  * @param pkts_n
804230189d9SNélio Laranjeiro  *   Number of packets in array.
805230189d9SNélio Laranjeiro  *
806230189d9SNélio Laranjeiro  * @return
807230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
808230189d9SNélio Laranjeiro  */
809230189d9SNélio Laranjeiro uint16_t
810230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
811230189d9SNélio Laranjeiro {
812230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
813230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
8148c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
8158c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
816c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
817a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
8188c819a69SYongseok Koh 	uint16_t max_elts;
819f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
820230189d9SNélio Laranjeiro 	unsigned int comp;
821230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
822230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
823230189d9SNélio Laranjeiro 	};
824230189d9SNélio Laranjeiro 
825c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
826c3d62cc9SAdrien Mazarguil 		return 0;
827230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
828fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
829fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
830230189d9SNélio Laranjeiro 	/* Start processing. */
8316cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
8328c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
833f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
834f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
835f04f1d51SNélio Laranjeiro 		return 0;
836c3d62cc9SAdrien Mazarguil 	do {
837a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
838230189d9SNélio Laranjeiro 		uint32_t length;
839a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
840230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
841230189d9SNélio Laranjeiro 
842c3d62cc9SAdrien Mazarguil 		/*
843c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
844c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
845c3d62cc9SAdrien Mazarguil 		 */
846a5bf6af9SAdrien Mazarguil 		assert(segs_n);
8478c819a69SYongseok Koh 		if (max_elts < segs_n)
848c3d62cc9SAdrien Mazarguil 			break;
849a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
85024c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
85124c14430SShahaf Shuler 			txq->stats.oerrors++;
852a5bf6af9SAdrien Mazarguil 			break;
85324c14430SShahaf Shuler 		}
8548c819a69SYongseok Koh 		max_elts -= segs_n;
855c3d62cc9SAdrien Mazarguil 		--pkts_n;
856230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
857230189d9SNélio Laranjeiro 		if (buf->ol_flags &
858230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
859230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
860a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
861a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
862a5bf6af9SAdrien Mazarguil 		assert(length);
863230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
864230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
865230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
866a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
8678688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
868230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
869230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
870f04f1d51SNélio Laranjeiro 			/*
871f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
872f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
873f04f1d51SNélio Laranjeiro 			 * resources.
874f04f1d51SNélio Laranjeiro 			 */
875f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
876f04f1d51SNélio Laranjeiro 				break;
877f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
878230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
8798688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
880230189d9SNélio Laranjeiro 		}
881a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
882a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
883a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
884a5bf6af9SAdrien Mazarguil 		length = 0;
885a5bf6af9SAdrien Mazarguil #endif
886a5bf6af9SAdrien Mazarguil 		do {
887a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
888a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
889a5bf6af9SAdrien Mazarguil 
890a5bf6af9SAdrien Mazarguil 			assert(buf);
8918c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
892230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
893a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
894230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
895a5bf6af9SAdrien Mazarguil 				.byte_count = htonl(DATA_LEN(buf)),
8966cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
897230189d9SNélio Laranjeiro 				.addr = htonll(addr),
898230189d9SNélio Laranjeiro 			};
899a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
900a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
901a5bf6af9SAdrien Mazarguil #endif
902a5bf6af9SAdrien Mazarguil 			buf = buf->next;
903230189d9SNélio Laranjeiro 			++mpw.pkts_n;
904a5bf6af9SAdrien Mazarguil 			++j;
905a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
906a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
907230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
908230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
909230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
910230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
911230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
912230189d9SNélio Laranjeiro #endif
913c3d62cc9SAdrien Mazarguil 		++i;
914c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
915230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
916230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
917230189d9SNélio Laranjeiro 		return 0;
918230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
919a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
920a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
921230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
9228688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
923230189d9SNélio Laranjeiro 
924230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
9258688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
926230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
9278688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
928230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
929230189d9SNélio Laranjeiro 	} else {
930230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
931230189d9SNélio Laranjeiro 	}
932230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
933230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
934230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
935230189d9SNélio Laranjeiro #endif
936230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
937230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
938230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
93930807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
940230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
941230189d9SNélio Laranjeiro 	return i;
942230189d9SNélio Laranjeiro }
943230189d9SNélio Laranjeiro 
944230189d9SNélio Laranjeiro /**
945230189d9SNélio Laranjeiro  * Open a MPW inline session.
946230189d9SNélio Laranjeiro  *
947230189d9SNélio Laranjeiro  * @param txq
948230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
949230189d9SNélio Laranjeiro  * @param mpw
950230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
951230189d9SNélio Laranjeiro  * @param length
952230189d9SNélio Laranjeiro  *   Packet length.
953230189d9SNélio Laranjeiro  */
954230189d9SNélio Laranjeiro static inline void
955230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
956230189d9SNélio Laranjeiro {
957a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
9588688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
959230189d9SNélio Laranjeiro 
960230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
961230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
962230189d9SNélio Laranjeiro 	mpw->len = length;
963230189d9SNélio Laranjeiro 	mpw->total_len = 0;
964fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9658688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
966230189d9SNélio Laranjeiro 				  (txq->wqe_ci << 8) |
967c904ae25SNélio Laranjeiro 				  MLX5_OPCODE_TSO);
9688688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9698688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9708688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
9718688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9728688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
9738688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9748688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9758688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
9768688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
9778688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
9788688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
979230189d9SNélio Laranjeiro }
980230189d9SNélio Laranjeiro 
981230189d9SNélio Laranjeiro /**
982230189d9SNélio Laranjeiro  * Close a MPW inline session.
983230189d9SNélio Laranjeiro  *
984230189d9SNélio Laranjeiro  * @param txq
985230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
986230189d9SNélio Laranjeiro  * @param mpw
987230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
988230189d9SNélio Laranjeiro  */
989230189d9SNélio Laranjeiro static inline void
990230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
991230189d9SNélio Laranjeiro {
992230189d9SNélio Laranjeiro 	unsigned int size;
9938688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
9948688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
995230189d9SNélio Laranjeiro 
9968688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
997230189d9SNélio Laranjeiro 	/*
998230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
999230189d9SNélio Laranjeiro 	 * count as 2.
1000230189d9SNélio Laranjeiro 	 */
10018688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size));
1002230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
10038688b2f8SNélio Laranjeiro 	inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG);
10048688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1005230189d9SNélio Laranjeiro }
1006230189d9SNélio Laranjeiro 
1007230189d9SNélio Laranjeiro /**
1008230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1009230189d9SNélio Laranjeiro  *
1010230189d9SNélio Laranjeiro  * @param dpdk_txq
1011230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1012230189d9SNélio Laranjeiro  * @param[in] pkts
1013230189d9SNélio Laranjeiro  *   Packets to transmit.
1014230189d9SNélio Laranjeiro  * @param pkts_n
1015230189d9SNélio Laranjeiro  *   Number of packets in array.
1016230189d9SNélio Laranjeiro  *
1017230189d9SNélio Laranjeiro  * @return
1018230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1019230189d9SNélio Laranjeiro  */
1020230189d9SNélio Laranjeiro uint16_t
1021230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1022230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1023230189d9SNélio Laranjeiro {
1024230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
1025230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
10268c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
10278c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1028c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1029a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
10308c819a69SYongseok Koh 	uint16_t max_elts;
1031f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1032230189d9SNélio Laranjeiro 	unsigned int comp;
10330e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1034230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1035230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1036230189d9SNélio Laranjeiro 	};
1037f04f1d51SNélio Laranjeiro 	/*
1038f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1039f04f1d51SNélio Laranjeiro 	 * code.
1040f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1041f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1042f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1043f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1044f04f1d51SNélio Laranjeiro 	 */
1045f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1046f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1047f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1048f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1049230189d9SNélio Laranjeiro 
1050c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1051c3d62cc9SAdrien Mazarguil 		return 0;
1052230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1053fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1054fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1055230189d9SNélio Laranjeiro 	/* Start processing. */
10566cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
10578c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
1058c3d62cc9SAdrien Mazarguil 	do {
1059a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1060230189d9SNélio Laranjeiro 		uintptr_t addr;
1061230189d9SNélio Laranjeiro 		uint32_t length;
1062a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
1063230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
1064230189d9SNélio Laranjeiro 
1065c3d62cc9SAdrien Mazarguil 		/*
1066c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1067c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1068c3d62cc9SAdrien Mazarguil 		 */
1069a5bf6af9SAdrien Mazarguil 		assert(segs_n);
10708c819a69SYongseok Koh 		if (max_elts < segs_n)
1071c3d62cc9SAdrien Mazarguil 			break;
1072a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
107324c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
107424c14430SShahaf Shuler 			txq->stats.oerrors++;
1075a5bf6af9SAdrien Mazarguil 			break;
107624c14430SShahaf Shuler 		}
10778c819a69SYongseok Koh 		max_elts -= segs_n;
1078c3d62cc9SAdrien Mazarguil 		--pkts_n;
1079f04f1d51SNélio Laranjeiro 		/*
1080f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1081f04f1d51SNélio Laranjeiro 		 * iteration.
1082f04f1d51SNélio Laranjeiro 		 */
1083f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
1084230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
1085230189d9SNélio Laranjeiro 		if (buf->ol_flags &
1086230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
1087230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
1088a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1089a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1090230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1091230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1092230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1093a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
10948688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1095230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1096230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1097230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1098a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1099230189d9SNélio Laranjeiro 			    (length > inline_room) ||
11008688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1101230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11020e8679fcSNélio Laranjeiro 				inline_room =
11030e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1104230189d9SNélio Laranjeiro 			}
1105230189d9SNélio Laranjeiro 		}
1106230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1107a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1108a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1109f04f1d51SNélio Laranjeiro 				/*
1110f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1111f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1112f04f1d51SNélio Laranjeiro 				 * such resources.
1113f04f1d51SNélio Laranjeiro 				 */
1114f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1115f04f1d51SNélio Laranjeiro 					break;
1116f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1117230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
11188688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1119230189d9SNélio Laranjeiro 			} else {
1120f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1121f04f1d51SNélio Laranjeiro 					break;
1122f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1123230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
11248688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1125230189d9SNélio Laranjeiro 			}
1126230189d9SNélio Laranjeiro 		}
1127a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1128a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1129230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
11300e8679fcSNélio Laranjeiro 			assert(inline_room ==
11310e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1132a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1133a5bf6af9SAdrien Mazarguil 			length = 0;
1134a5bf6af9SAdrien Mazarguil #endif
1135a5bf6af9SAdrien Mazarguil 			do {
1136230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1137230189d9SNélio Laranjeiro 
1138a5bf6af9SAdrien Mazarguil 				assert(buf);
11398c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1140230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1141a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1142230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
1143a5bf6af9SAdrien Mazarguil 					.byte_count = htonl(DATA_LEN(buf)),
11446cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
1145230189d9SNélio Laranjeiro 					.addr = htonll(addr),
1146230189d9SNélio Laranjeiro 				};
1147a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1148a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1149a5bf6af9SAdrien Mazarguil #endif
1150a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1151230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1152a5bf6af9SAdrien Mazarguil 				++j;
1153a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1154a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1155230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1156230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1157230189d9SNélio Laranjeiro 		} else {
1158230189d9SNélio Laranjeiro 			unsigned int max;
1159230189d9SNélio Laranjeiro 
1160230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1161230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1162a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1163a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
11648c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1165230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1166fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1167fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1168fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1169230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1170230189d9SNélio Laranjeiro 			if (length > max) {
1171230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1172230189d9SNélio Laranjeiro 					   (void *)addr,
1173230189d9SNélio Laranjeiro 					   max);
1174fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1175230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1176230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1177230189d9SNélio Laranjeiro 					   length - max);
1178230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1179230189d9SNélio Laranjeiro 			} else {
1180230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1181230189d9SNélio Laranjeiro 					   (void *)addr,
1182230189d9SNélio Laranjeiro 					   length);
118316c64768SYongseok Koh 
118416c64768SYongseok Koh 				if (length == max)
118516c64768SYongseok Koh 					mpw.data.raw =
118616c64768SYongseok Koh 						(volatile void *)txq->wqes;
118716c64768SYongseok Koh 				else
1188230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1189230189d9SNélio Laranjeiro 			}
1190230189d9SNélio Laranjeiro 			++mpw.pkts_n;
119176bf1574SYongseok Koh 			mpw.total_len += length;
1192a5bf6af9SAdrien Mazarguil 			++j;
1193230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1194230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11950e8679fcSNélio Laranjeiro 				inline_room =
11960e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1197230189d9SNélio Laranjeiro 			} else {
1198230189d9SNélio Laranjeiro 				inline_room -= length;
1199230189d9SNélio Laranjeiro 			}
1200230189d9SNélio Laranjeiro 		}
1201230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1202230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1203230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1204230189d9SNélio Laranjeiro #endif
1205c3d62cc9SAdrien Mazarguil 		++i;
1206c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1207230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1208230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1209230189d9SNélio Laranjeiro 		return 0;
1210230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1211a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1212a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1213230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
12148688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1215230189d9SNélio Laranjeiro 
1216230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
12178688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1218230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
12198688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1220230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1221230189d9SNélio Laranjeiro 	} else {
1222230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1223230189d9SNélio Laranjeiro 	}
1224230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1225230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1226230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1227230189d9SNélio Laranjeiro #endif
1228230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1229230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1230230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1231230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1232230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
123330807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1234230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1235230189d9SNélio Laranjeiro 	return i;
1236230189d9SNélio Laranjeiro }
1237230189d9SNélio Laranjeiro 
1238230189d9SNélio Laranjeiro /**
12396ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
12406ce84bd8SYongseok Koh  *
12416ce84bd8SYongseok Koh  * @param txq
12426ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12436ce84bd8SYongseok Koh  * @param mpw
12446ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12456ce84bd8SYongseok Koh  * @param length
12466ce84bd8SYongseok Koh  *   Packet length.
12476ce84bd8SYongseok Koh  */
12486ce84bd8SYongseok Koh static inline void
12496ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding)
12506ce84bd8SYongseok Koh {
12516ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
12526ce84bd8SYongseok Koh 
12536ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
12546ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
12556ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
12566ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
12576ce84bd8SYongseok Koh 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
12586ce84bd8SYongseok Koh 				  (txq->wqe_ci << 8) |
12596ce84bd8SYongseok Koh 				  MLX5_OPCODE_ENHANCED_MPSW);
12606ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
12616ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
12626ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
12636ce84bd8SYongseok Koh 	if (unlikely(padding)) {
12646ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
12656ce84bd8SYongseok Koh 
12666ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
12676ce84bd8SYongseok Koh 		*(volatile uint32_t *)addr = htonl(MLX5_INLINE_SEG);
12686ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
12696ce84bd8SYongseok Koh 			htonl(MLX5_INLINE_SEG);
12706ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
12716ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
12726ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
12736ce84bd8SYongseok Koh 	} else {
12746ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
12756ce84bd8SYongseok Koh 	}
12766ce84bd8SYongseok Koh }
12776ce84bd8SYongseok Koh 
12786ce84bd8SYongseok Koh /**
12796ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
12806ce84bd8SYongseok Koh  *
12816ce84bd8SYongseok Koh  * @param txq
12826ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12836ce84bd8SYongseok Koh  * @param mpw
12846ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12856ce84bd8SYongseok Koh  *
12866ce84bd8SYongseok Koh  * @return
12876ce84bd8SYongseok Koh  *   Number of consumed WQEs.
12886ce84bd8SYongseok Koh  */
12896ce84bd8SYongseok Koh static inline uint16_t
12906ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw)
12916ce84bd8SYongseok Koh {
12926ce84bd8SYongseok Koh 	uint16_t ret;
12936ce84bd8SYongseok Koh 
12946ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
12956ce84bd8SYongseok Koh 	 * count as 2.
12966ce84bd8SYongseok Koh 	 */
12976ce84bd8SYongseok Koh 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(mpw->total_len));
12986ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
12996ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
13006ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
13016ce84bd8SYongseok Koh 	return ret;
13026ce84bd8SYongseok Koh }
13036ce84bd8SYongseok Koh 
13046ce84bd8SYongseok Koh /**
13056ce84bd8SYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
13066ce84bd8SYongseok Koh  *
13076ce84bd8SYongseok Koh  * @param dpdk_txq
13086ce84bd8SYongseok Koh  *   Generic pointer to TX queue structure.
13096ce84bd8SYongseok Koh  * @param[in] pkts
13106ce84bd8SYongseok Koh  *   Packets to transmit.
13116ce84bd8SYongseok Koh  * @param pkts_n
13126ce84bd8SYongseok Koh  *   Number of packets in array.
13136ce84bd8SYongseok Koh  *
13146ce84bd8SYongseok Koh  * @return
13156ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
13166ce84bd8SYongseok Koh  */
13176ce84bd8SYongseok Koh uint16_t
13186ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
13196ce84bd8SYongseok Koh {
13206ce84bd8SYongseok Koh 	struct txq *txq = (struct txq *)dpdk_txq;
13216ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
13228c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
13238c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
13246ce84bd8SYongseok Koh 	unsigned int i = 0;
13256ce84bd8SYongseok Koh 	unsigned int j = 0;
13268c819a69SYongseok Koh 	uint16_t max_elts;
13276ce84bd8SYongseok Koh 	uint16_t max_wqe;
13286ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
13296ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
13306ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
13316ce84bd8SYongseok Koh 	uint32_t inl_hdr;
13326ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
13336ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
13346ce84bd8SYongseok Koh 	};
13356ce84bd8SYongseok Koh 
13366ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
13376ce84bd8SYongseok Koh 		return 0;
13386ce84bd8SYongseok Koh 	/* Start processing. */
13396cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
13406ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
13416ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
13426ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
13436ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
13446ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
13456ce84bd8SYongseok Koh 		return 0;
13466ce84bd8SYongseok Koh 	do {
13476ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
13486ce84bd8SYongseok Koh 		uintptr_t addr;
13496ce84bd8SYongseok Koh 		uint64_t naddr;
13506ce84bd8SYongseok Koh 		unsigned int n;
13516ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
13526ce84bd8SYongseok Koh 		uint32_t length;
13536ce84bd8SYongseok Koh 		unsigned int segs_n = buf->nb_segs;
13546ce84bd8SYongseok Koh 		uint32_t cs_flags = 0;
13556ce84bd8SYongseok Koh 
13566ce84bd8SYongseok Koh 		/*
13576ce84bd8SYongseok Koh 		 * Make sure there is enough room to store this packet and
13586ce84bd8SYongseok Koh 		 * that one ring entry remains unused.
13596ce84bd8SYongseok Koh 		 */
13606ce84bd8SYongseok Koh 		assert(segs_n);
13618c819a69SYongseok Koh 		if (max_elts - j < segs_n)
13626ce84bd8SYongseok Koh 			break;
13636ce84bd8SYongseok Koh 		/* Do not bother with large packets MPW cannot handle. */
136424c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
136524c14430SShahaf Shuler 			txq->stats.oerrors++;
13666ce84bd8SYongseok Koh 			break;
136724c14430SShahaf Shuler 		}
13686ce84bd8SYongseok Koh 		/* Should we enable HW CKSUM offload. */
13696ce84bd8SYongseok Koh 		if (buf->ol_flags &
13706ce84bd8SYongseok Koh 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
13716ce84bd8SYongseok Koh 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
13726ce84bd8SYongseok Koh 		/* Retrieve packet information. */
13736ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
13746ce84bd8SYongseok Koh 		/* Start new session if:
13756ce84bd8SYongseok Koh 		 * - multi-segment packet
13766ce84bd8SYongseok Koh 		 * - no space left even for a dseg
13776ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
13786ce84bd8SYongseok Koh 		 * - cs_flag differs
13796ce84bd8SYongseok Koh 		 * It can't be MLX5_MPW_STATE_OPENED as always have a single
13806ce84bd8SYongseok Koh 		 * segmented packet.
13816ce84bd8SYongseok Koh 		 */
13826ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
13836ce84bd8SYongseok Koh 			if ((segs_n != 1) ||
13846ce84bd8SYongseok Koh 			    (inl_pad + sizeof(struct mlx5_wqe_data_seg) >
13856ce84bd8SYongseok Koh 			      mpw_room) ||
13866ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
13876ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
13886ce84bd8SYongseok Koh 			      mpw_room) ||
13896ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
13906ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
13916ce84bd8SYongseok Koh 		}
13926ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
13936ce84bd8SYongseok Koh 			if (unlikely(segs_n != 1)) {
13946ce84bd8SYongseok Koh 				/* Fall back to legacy MPW.
13956ce84bd8SYongseok Koh 				 * A MPW session consumes 2 WQEs at most to
13966ce84bd8SYongseok Koh 				 * include MLX5_MPW_DSEG_MAX pointers.
13976ce84bd8SYongseok Koh 				 */
13986ce84bd8SYongseok Koh 				if (unlikely(max_wqe < 2))
13996ce84bd8SYongseok Koh 					break;
14006ce84bd8SYongseok Koh 				mlx5_mpw_new(txq, &mpw, length);
14016ce84bd8SYongseok Koh 			} else {
14026ce84bd8SYongseok Koh 				/* In Enhanced MPW, inline as much as the budget
14036ce84bd8SYongseok Koh 				 * is allowed. The remaining space is to be
14046ce84bd8SYongseok Koh 				 * filled with dsegs. If the title WQEBB isn't
14056ce84bd8SYongseok Koh 				 * padded, it will have 2 dsegs there.
14066ce84bd8SYongseok Koh 				 */
14076ce84bd8SYongseok Koh 				mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
14086ce84bd8SYongseok Koh 					    (max_inline ? max_inline :
14096ce84bd8SYongseok Koh 					     pkts_n * MLX5_WQE_DWORD_SIZE) +
14106ce84bd8SYongseok Koh 					    MLX5_WQE_SIZE);
14116ce84bd8SYongseok Koh 				if (unlikely(max_wqe * MLX5_WQE_SIZE <
14126ce84bd8SYongseok Koh 					      mpw_room))
14136ce84bd8SYongseok Koh 					break;
14146ce84bd8SYongseok Koh 				/* Don't pad the title WQEBB to not waste WQ. */
14156ce84bd8SYongseok Koh 				mlx5_empw_new(txq, &mpw, 0);
14166ce84bd8SYongseok Koh 				mpw_room -= mpw.total_len;
14176ce84bd8SYongseok Koh 				inl_pad = 0;
14186ce84bd8SYongseok Koh 				do_inline =
14196ce84bd8SYongseok Koh 					length <= txq->inline_max_packet_sz &&
14206ce84bd8SYongseok Koh 					sizeof(inl_hdr) + length <= mpw_room &&
14216ce84bd8SYongseok Koh 					!txq->mpw_hdr_dseg;
14226ce84bd8SYongseok Koh 			}
14236ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
14246ce84bd8SYongseok Koh 		} else {
14256ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
14266ce84bd8SYongseok Koh 			 * Inlininig is possible when:
14276ce84bd8SYongseok Koh 			 * - length is less than configured value
14286ce84bd8SYongseok Koh 			 * - length fits for remaining space
14296ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
14306ce84bd8SYongseok Koh 			 */
14316ce84bd8SYongseok Koh 			do_inline =
14326ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
14336ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
14346ce84bd8SYongseok Koh 				 mpw_room &&
14356ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
14366ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
14376ce84bd8SYongseok Koh 		}
14386ce84bd8SYongseok Koh 		/* Multi-segment packets must be alone in their MPW. */
14396ce84bd8SYongseok Koh 		assert((segs_n == 1) || (mpw.pkts_n == 0));
14406ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) {
14416ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14426ce84bd8SYongseok Koh 			length = 0;
14436ce84bd8SYongseok Koh #endif
14446ce84bd8SYongseok Koh 			do {
14456ce84bd8SYongseok Koh 				volatile struct mlx5_wqe_data_seg *dseg;
14466ce84bd8SYongseok Koh 
14476ce84bd8SYongseok Koh 				assert(buf);
14488c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
14496ce84bd8SYongseok Koh 				dseg = mpw.data.dseg[mpw.pkts_n];
14506ce84bd8SYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
14516ce84bd8SYongseok Koh 				*dseg = (struct mlx5_wqe_data_seg){
14526ce84bd8SYongseok Koh 					.byte_count = htonl(DATA_LEN(buf)),
14536cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
14546ce84bd8SYongseok Koh 					.addr = htonll(addr),
14556ce84bd8SYongseok Koh 				};
14566ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14576ce84bd8SYongseok Koh 				length += DATA_LEN(buf);
14586ce84bd8SYongseok Koh #endif
14596ce84bd8SYongseok Koh 				buf = buf->next;
14606ce84bd8SYongseok Koh 				++j;
14616ce84bd8SYongseok Koh 				++mpw.pkts_n;
14626ce84bd8SYongseok Koh 			} while (--segs_n);
14636ce84bd8SYongseok Koh 			/* A multi-segmented packet takes one MPW session.
14646ce84bd8SYongseok Koh 			 * TODO: Pack more multi-segmented packets if possible.
14656ce84bd8SYongseok Koh 			 */
14666ce84bd8SYongseok Koh 			mlx5_mpw_close(txq, &mpw);
14676ce84bd8SYongseok Koh 			if (mpw.pkts_n < 3)
14686ce84bd8SYongseok Koh 				max_wqe--;
14696ce84bd8SYongseok Koh 			else
14706ce84bd8SYongseok Koh 				max_wqe -= 2;
14716ce84bd8SYongseok Koh 		} else if (do_inline) {
14726ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
14736ce84bd8SYongseok Koh 			unsigned int max;
14746ce84bd8SYongseok Koh 
14756ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14766ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14776ce84bd8SYongseok Koh 			inl_hdr = htonl(length | MLX5_INLINE_SEG);
14786ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14796ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14806ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
14816ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
14826ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
14836ce84bd8SYongseok Koh 			/* Copy inline header. */
14846ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14856ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
14866ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
14876ce84bd8SYongseok Koh 					  &inl_hdr,
14886ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
14896ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
14906ce84bd8SYongseok Koh 					  max);
14916ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
14926ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
14936ce84bd8SYongseok Koh 			/* Copy packet data. */
14946ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14956ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
14966ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
14976ce84bd8SYongseok Koh 					  (void *)addr,
14986ce84bd8SYongseok Koh 					  length,
14996ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
15006ce84bd8SYongseok Koh 					  max);
15016ce84bd8SYongseok Koh 			++mpw.pkts_n;
15026ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
15036ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
15046ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
15056ce84bd8SYongseok Koh 			 */
15066ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
15076ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
15086ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
15096ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
15106ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
15116ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
15126ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
15136ce84bd8SYongseok Koh 		} else {
15146ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
15156ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
15166ce84bd8SYongseok Koh 
15176ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
15186ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
15196ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
15206ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
15216ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
15226ce84bd8SYongseok Koh 						+ inl_pad)))
15236ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
15246ce84bd8SYongseok Koh 			else
15256ce84bd8SYongseok Koh 				dseg = (volatile void *)
15266ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
15276ce84bd8SYongseok Koh 					 inl_pad);
15288c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
15296ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
15306ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
15316ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
15326ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
15336ce84bd8SYongseok Koh 			naddr = htonll(addr);
15346ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
15356ce84bd8SYongseok Koh 				htonl(length),
15366cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
15376ce84bd8SYongseok Koh 				naddr,
15386ce84bd8SYongseok Koh 				naddr >> 32,
15396ce84bd8SYongseok Koh 			};
15406ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
15416ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
15426ce84bd8SYongseok Koh 			++j;
15436ce84bd8SYongseok Koh 			++mpw.pkts_n;
15446ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
15456ce84bd8SYongseok Koh 			inl_pad = 0;
15466ce84bd8SYongseok Koh 		}
15476ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15486ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
15496ce84bd8SYongseok Koh 		txq->stats.obytes += length;
15506ce84bd8SYongseok Koh #endif
15516ce84bd8SYongseok Koh 		++i;
15526ce84bd8SYongseok Koh 	} while (i < pkts_n);
15536ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
15546ce84bd8SYongseok Koh 	if (unlikely(i == 0))
15556ce84bd8SYongseok Koh 		return 0;
15566ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
15576ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
15586ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
15596ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
15606ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
15616ce84bd8SYongseok Koh 
15626ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
15636ce84bd8SYongseok Koh 		wqe->ctrl[2] = htonl(8);
15646ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
15656ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
15666ce84bd8SYongseok Koh 		txq->elts_comp = 0;
15676ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
15686ce84bd8SYongseok Koh 		txq->cq_pi++;
15696ce84bd8SYongseok Koh 	} else {
15706ce84bd8SYongseok Koh 		txq->elts_comp += j;
15716ce84bd8SYongseok Koh 	}
15726ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15736ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
15746ce84bd8SYongseok Koh 	txq->stats.opackets += i;
15756ce84bd8SYongseok Koh #endif
15766ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
15776ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
15786ce84bd8SYongseok Koh 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
15796ce84bd8SYongseok Koh 		mlx5_mpw_close(txq, &mpw);
15806ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
15816ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
15826ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
15836ce84bd8SYongseok Koh 	return i;
15846ce84bd8SYongseok Koh }
15856ce84bd8SYongseok Koh 
15866ce84bd8SYongseok Koh /**
158767fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
158867fa62bcSAdrien Mazarguil  *
15896218063bSNélio Laranjeiro  * @param[in] cqe
15906218063bSNélio Laranjeiro  *   Pointer to CQE.
159167fa62bcSAdrien Mazarguil  *
159278a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
159378a38edfSJianfeng Tan  *
159467fa62bcSAdrien Mazarguil  * @return
159567fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
159667fa62bcSAdrien Mazarguil  */
159767fa62bcSAdrien Mazarguil static inline uint32_t
159897267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
159967fa62bcSAdrien Mazarguil {
1600ea16068cSYongseok Koh 	uint8_t idx;
1601ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
1602ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
160367fa62bcSAdrien Mazarguil 
1604ea16068cSYongseok Koh 	/*
1605ea16068cSYongseok Koh 	 * The index to the array should have:
1606ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
1607ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
1608ea16068cSYongseok Koh 	 * bit[5] = ip_frag
1609ea16068cSYongseok Koh 	 * bit[6] = tunneled
1610ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
1611ea16068cSYongseok Koh 	 */
1612ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
1613ea16068cSYongseok Koh 	return mlx5_ptype_table[idx];
161467fa62bcSAdrien Mazarguil }
161567fa62bcSAdrien Mazarguil 
161667fa62bcSAdrien Mazarguil /**
161799c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
161899c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
161999c12dccSNélio Laranjeiro  * been processed.
162099c12dccSNélio Laranjeiro  *
162199c12dccSNélio Laranjeiro  * @param rxq
162299c12dccSNélio Laranjeiro  *   Pointer to RX queue.
162399c12dccSNélio Laranjeiro  * @param cqe
162499c12dccSNélio Laranjeiro  *   CQE to process.
1625ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1626ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
162799c12dccSNélio Laranjeiro  *
162899c12dccSNélio Laranjeiro  * @return
162999c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
163099c12dccSNélio Laranjeiro  *   with error.
163199c12dccSNélio Laranjeiro  */
163299c12dccSNélio Laranjeiro static inline int
163397267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
1634ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
163599c12dccSNélio Laranjeiro {
163699c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
163799c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
163899c12dccSNélio Laranjeiro 	int len = 0;
1639d2e842d0SYongseok Koh 	uint16_t idx, end;
164099c12dccSNélio Laranjeiro 
164199c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
164299c12dccSNélio Laranjeiro 	if (zip->ai) {
164399c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
164499c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
16454aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
164699c12dccSNélio Laranjeiro 
164799c12dccSNélio Laranjeiro 		len = ntohl((*mc)[zip->ai & 7].byte_cnt);
1648ecf60761SNélio Laranjeiro 		*rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result);
164999c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1650d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1651d2e842d0SYongseok Koh 			idx = zip->ca;
1652d2e842d0SYongseok Koh 			end = zip->na;
1653d2e842d0SYongseok Koh 			while (idx != end) {
1654d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1655d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1656d2e842d0SYongseok Koh 				++idx;
1657d2e842d0SYongseok Koh 			}
165899c12dccSNélio Laranjeiro 			/*
165999c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
166099c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
166199c12dccSNélio Laranjeiro 			 * ring for software use.
166299c12dccSNélio Laranjeiro 			 */
166399c12dccSNélio Laranjeiro 			zip->ca = zip->na;
166499c12dccSNélio Laranjeiro 			zip->na += 8;
166599c12dccSNélio Laranjeiro 		}
166699c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1667d2e842d0SYongseok Koh 			/* Invalidate the rest */
1668d2e842d0SYongseok Koh 			idx = zip->ca;
1669d2e842d0SYongseok Koh 			end = zip->cq_ci;
167099c12dccSNélio Laranjeiro 
167199c12dccSNélio Laranjeiro 			while (idx != end) {
167297267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
167399c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
167499c12dccSNélio Laranjeiro 				++idx;
167599c12dccSNélio Laranjeiro 			}
167699c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
167799c12dccSNélio Laranjeiro 			zip->ai = 0;
167899c12dccSNélio Laranjeiro 		}
167999c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
168099c12dccSNélio Laranjeiro 	} else {
168199c12dccSNélio Laranjeiro 		int ret;
168299c12dccSNélio Laranjeiro 		int8_t op_own;
168399c12dccSNélio Laranjeiro 
168497267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
168599c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
168699c12dccSNélio Laranjeiro 			return 0;
168799c12dccSNélio Laranjeiro 		++rxq->cq_ci;
168899c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
168999c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
169099c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
169199c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
169299c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
16934aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
169499c12dccSNélio Laranjeiro 
169599c12dccSNélio Laranjeiro 			/* Fix endianness. */
169699c12dccSNélio Laranjeiro 			zip->cqe_cnt = ntohl(cqe->byte_cnt);
169799c12dccSNélio Laranjeiro 			/*
169899c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
169999c12dccSNélio Laranjeiro 			 * check_cqe64().
170099c12dccSNélio Laranjeiro 			 *
170199c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
170299c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
170399c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
170499c12dccSNélio Laranjeiro 			 */
1705d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
170699c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
170799c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
170899c12dccSNélio Laranjeiro 			--rxq->cq_ci;
170999c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
171099c12dccSNélio Laranjeiro 			/* Get packet size to return. */
171199c12dccSNélio Laranjeiro 			len = ntohl((*mc)[0].byte_cnt);
1712ecf60761SNélio Laranjeiro 			*rss_hash = ntohl((*mc)[0].rx_hash_result);
171399c12dccSNélio Laranjeiro 			zip->ai = 1;
1714d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1715d2e842d0SYongseok Koh 			idx = zip->ca;
1716d2e842d0SYongseok Koh 			end = zip->cq_ci;
1717d2e842d0SYongseok Koh 			while (idx != end) {
1718d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1719d2e842d0SYongseok Koh 				++idx;
1720d2e842d0SYongseok Koh 			}
172199c12dccSNélio Laranjeiro 		} else {
172299c12dccSNélio Laranjeiro 			len = ntohl(cqe->byte_cnt);
1723ecf60761SNélio Laranjeiro 			*rss_hash = ntohl(cqe->rx_hash_res);
172499c12dccSNélio Laranjeiro 		}
172599c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
172699c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
172799c12dccSNélio Laranjeiro 			return -1;
172899c12dccSNélio Laranjeiro 	}
172999c12dccSNélio Laranjeiro 	return len;
173099c12dccSNélio Laranjeiro }
173199c12dccSNélio Laranjeiro 
173299c12dccSNélio Laranjeiro /**
173367fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
173467fa62bcSAdrien Mazarguil  *
173567fa62bcSAdrien Mazarguil  * @param[in] rxq
173667fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
17376218063bSNélio Laranjeiro  * @param[in] cqe
17386218063bSNélio Laranjeiro  *   Pointer to CQE.
173967fa62bcSAdrien Mazarguil  *
174067fa62bcSAdrien Mazarguil  * @return
174167fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
174267fa62bcSAdrien Mazarguil  */
174367fa62bcSAdrien Mazarguil static inline uint32_t
174497267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
174567fa62bcSAdrien Mazarguil {
174667fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
17470603df73SNélio Laranjeiro 	uint16_t flags = ntohs(cqe->hdr_type_etc);
174867fa62bcSAdrien Mazarguil 
17490603df73SNélio Laranjeiro 	ol_flags =
17500603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17510603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
17520603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
17530603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17540603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
175583e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
175697267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
175767fa62bcSAdrien Mazarguil 		ol_flags |=
17580603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17590603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
176083e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
17610603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17620603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
176383e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
176467fa62bcSAdrien Mazarguil 	return ol_flags;
176567fa62bcSAdrien Mazarguil }
176667fa62bcSAdrien Mazarguil 
176767fa62bcSAdrien Mazarguil /**
17682e22920bSAdrien Mazarguil  * DPDK callback for RX.
17692e22920bSAdrien Mazarguil  *
17702e22920bSAdrien Mazarguil  * @param dpdk_rxq
17712e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
17722e22920bSAdrien Mazarguil  * @param[out] pkts
17732e22920bSAdrien Mazarguil  *   Array to store received packets.
17742e22920bSAdrien Mazarguil  * @param pkts_n
17752e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
17762e22920bSAdrien Mazarguil  *
17772e22920bSAdrien Mazarguil  * @return
17782e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
17792e22920bSAdrien Mazarguil  */
17802e22920bSAdrien Mazarguil uint16_t
17812e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
17822e22920bSAdrien Mazarguil {
17836218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
1784b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1785e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
17869964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
17879964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
17889964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
178997267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
179097267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
17919964b965SNélio Laranjeiro 	unsigned int i = 0;
17929964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
17934e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
17942e22920bSAdrien Mazarguil 
17959964b965SNélio Laranjeiro 	while (pkts_n) {
17969964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
17979964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
17989964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1799ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
18009964b965SNélio Laranjeiro 
18019964b965SNélio Laranjeiro 		if (pkt)
18029964b965SNélio Laranjeiro 			NEXT(seg) = rep;
18039964b965SNélio Laranjeiro 		seg = rep;
18049964b965SNélio Laranjeiro 		rte_prefetch0(seg);
18056218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
18069964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1807fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
18082e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
180915a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
181015a756b6SSagi Grimberg 			if (!pkt) {
181115a756b6SSagi Grimberg 				/*
181215a756b6SSagi Grimberg 				 * no buffers before we even started,
181315a756b6SSagi Grimberg 				 * bail out silently.
181415a756b6SSagi Grimberg 				 */
181515a756b6SSagi Grimberg 				break;
181615a756b6SSagi Grimberg 			}
1817a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1818a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1819fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
18208f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
18218f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
18221f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1823fe5fe382SNélio Laranjeiro 				pkt = rep;
18249964b965SNélio Laranjeiro 			}
18256218063bSNélio Laranjeiro 			break;
18262e22920bSAdrien Mazarguil 		}
18279964b965SNélio Laranjeiro 		if (!pkt) {
182897267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1829ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1830ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1831ecf60761SNélio Laranjeiro 			if (!len) {
18321f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
18336218063bSNélio Laranjeiro 				break;
18346218063bSNélio Laranjeiro 			}
183599c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
183699c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
18371f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
183899c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
183999c12dccSNélio Laranjeiro 				goto skip;
184099c12dccSNélio Laranjeiro 			}
18419964b965SNélio Laranjeiro 			pkt = seg;
18429964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
18439964b965SNélio Laranjeiro 			/* Update packet information. */
184448dfc20fSYongseok Koh 			pkt->packet_type = rxq_cq_to_pkt_type(cqe);
18450ac64846SMaxime Leroy 			pkt->ol_flags = 0;
184636ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1847ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1848ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1849ecf60761SNélio Laranjeiro 			}
1850c604f619SNélio Laranjeiro 			if (rxq->mark &&
1851c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1852b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
1853b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
1854b268a3eeSNélio Laranjeiro 				    htonl(MLX5_FLOW_MARK_DEFAULT)) {
1855b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
1856b268a3eeSNélio Laranjeiro 
1857b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
1858ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
1859b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
1860b268a3eeSNélio Laranjeiro 				}
1861ea3bc3b1SNélio Laranjeiro 			}
186248dfc20fSYongseok Koh 			if (rxq->csum | rxq->csum_l2tun)
18636703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
18646703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
18656703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
18666703d836SNélio Laranjeiro 			     htons(MLX5_CQE_VLAN_STRIPPED))) {
18676218063bSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_VLAN_PKT |
1868b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
18696218063bSNélio Laranjeiro 				pkt->vlan_tci = ntohs(cqe->vlan_info);
1870f3db9489SYaacov Hazan 			}
18716218063bSNélio Laranjeiro 			if (rxq->crc_present)
18726218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
18736218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
18749964b965SNélio Laranjeiro 		}
18759964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
18769964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
18779964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
18789964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
18799964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
18809964b965SNélio Laranjeiro 		/*
18819964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
18829964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
18839964b965SNélio Laranjeiro 		 * changes.
18849964b965SNélio Laranjeiro 		 */
18859964b965SNélio Laranjeiro 		wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
18869964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
18879964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
18889964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
18899964b965SNélio Laranjeiro 			++rq_ci;
18909964b965SNélio Laranjeiro 			continue;
18919964b965SNélio Laranjeiro 		}
18929964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
189387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
189487011737SAdrien Mazarguil 		/* Increment bytes counter. */
18959964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
189687011737SAdrien Mazarguil #endif
18976218063bSNélio Laranjeiro 		/* Return packet. */
18986218063bSNélio Laranjeiro 		*(pkts++) = pkt;
18999964b965SNélio Laranjeiro 		pkt = NULL;
19009964b965SNélio Laranjeiro 		--pkts_n;
19019964b965SNélio Laranjeiro 		++i;
190299c12dccSNélio Laranjeiro skip:
19039964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
19049964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
19056218063bSNélio Laranjeiro 		++rq_ci;
19069964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
19072e22920bSAdrien Mazarguil 	}
19089964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
19092e22920bSAdrien Mazarguil 		return 0;
19106218063bSNélio Laranjeiro 	/* Update the consumer index. */
19119964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
19126218063bSNélio Laranjeiro 	rte_wmb();
19136218063bSNélio Laranjeiro 	*rxq->cq_db = htonl(rxq->cq_ci);
19146218063bSNélio Laranjeiro 	rte_wmb();
19156218063bSNélio Laranjeiro 	*rxq->rq_db = htonl(rxq->rq_ci);
191687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
191787011737SAdrien Mazarguil 	/* Increment packets counter. */
19189964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
191987011737SAdrien Mazarguil #endif
19209964b965SNélio Laranjeiro 	return i;
19212e22920bSAdrien Mazarguil }
19222e22920bSAdrien Mazarguil 
19232e22920bSAdrien Mazarguil /**
19242e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
19252e22920bSAdrien Mazarguil  *
19262e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19272e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19282e22920bSAdrien Mazarguil  *
19292e22920bSAdrien Mazarguil  * @param dpdk_txq
19302e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
19312e22920bSAdrien Mazarguil  * @param[in] pkts
19322e22920bSAdrien Mazarguil  *   Packets to transmit.
19332e22920bSAdrien Mazarguil  * @param pkts_n
19342e22920bSAdrien Mazarguil  *   Number of packets in array.
19352e22920bSAdrien Mazarguil  *
19362e22920bSAdrien Mazarguil  * @return
19372e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
19382e22920bSAdrien Mazarguil  */
19392e22920bSAdrien Mazarguil uint16_t
19402e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19412e22920bSAdrien Mazarguil {
19422e22920bSAdrien Mazarguil 	(void)dpdk_txq;
19432e22920bSAdrien Mazarguil 	(void)pkts;
19442e22920bSAdrien Mazarguil 	(void)pkts_n;
19452e22920bSAdrien Mazarguil 	return 0;
19462e22920bSAdrien Mazarguil }
19472e22920bSAdrien Mazarguil 
19482e22920bSAdrien Mazarguil /**
19492e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
19502e22920bSAdrien Mazarguil  *
19512e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19522e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19532e22920bSAdrien Mazarguil  *
19542e22920bSAdrien Mazarguil  * @param dpdk_rxq
19552e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
19562e22920bSAdrien Mazarguil  * @param[out] pkts
19572e22920bSAdrien Mazarguil  *   Array to store received packets.
19582e22920bSAdrien Mazarguil  * @param pkts_n
19592e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
19602e22920bSAdrien Mazarguil  *
19612e22920bSAdrien Mazarguil  * @return
19622e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
19632e22920bSAdrien Mazarguil  */
19642e22920bSAdrien Mazarguil uint16_t
19652e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19662e22920bSAdrien Mazarguil {
19672e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
19682e22920bSAdrien Mazarguil 	(void)pkts;
19692e22920bSAdrien Mazarguil 	(void)pkts_n;
19702e22920bSAdrien Mazarguil 	return 0;
19712e22920bSAdrien Mazarguil }
19726cb559d6SYongseok Koh 
19736cb559d6SYongseok Koh /*
19746cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
19756cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
19766cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
19776cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
19786cb559d6SYongseok Koh  */
19796cb559d6SYongseok Koh 
19806cb559d6SYongseok Koh uint16_t __attribute__((weak))
19816cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19826cb559d6SYongseok Koh {
19836cb559d6SYongseok Koh 	(void)dpdk_txq;
19846cb559d6SYongseok Koh 	(void)pkts;
19856cb559d6SYongseok Koh 	(void)pkts_n;
19866cb559d6SYongseok Koh 	return 0;
19876cb559d6SYongseok Koh }
19886cb559d6SYongseok Koh 
19896cb559d6SYongseok Koh uint16_t __attribute__((weak))
19906cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19916cb559d6SYongseok Koh {
19926cb559d6SYongseok Koh 	(void)dpdk_txq;
19936cb559d6SYongseok Koh 	(void)pkts;
19946cb559d6SYongseok Koh 	(void)pkts_n;
19956cb559d6SYongseok Koh 	return 0;
19966cb559d6SYongseok Koh }
19976cb559d6SYongseok Koh 
19986cb559d6SYongseok Koh uint16_t __attribute__((weak))
19996cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
20006cb559d6SYongseok Koh {
20016cb559d6SYongseok Koh 	(void)dpdk_rxq;
20026cb559d6SYongseok Koh 	(void)pkts;
20036cb559d6SYongseok Koh 	(void)pkts_n;
20046cb559d6SYongseok Koh 	return 0;
20056cb559d6SYongseok Koh }
20066cb559d6SYongseok Koh 
20076cb559d6SYongseok Koh int __attribute__((weak))
20086cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv)
20096cb559d6SYongseok Koh {
20106cb559d6SYongseok Koh 	(void)priv;
20116cb559d6SYongseok Koh 	return -ENOTSUP;
20126cb559d6SYongseok Koh }
20136cb559d6SYongseok Koh 
20146cb559d6SYongseok Koh int __attribute__((weak))
20156cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv)
20166cb559d6SYongseok Koh {
20176cb559d6SYongseok Koh 	(void)priv;
20186cb559d6SYongseok Koh 	return -ENOTSUP;
20196cb559d6SYongseok Koh }
20206cb559d6SYongseok Koh 
20216cb559d6SYongseok Koh int __attribute__((weak))
20226cb559d6SYongseok Koh rxq_check_vec_support(struct rxq *rxq)
20236cb559d6SYongseok Koh {
20246cb559d6SYongseok Koh 	(void)rxq;
20256cb559d6SYongseok Koh 	return -ENOTSUP;
20266cb559d6SYongseok Koh }
20276cb559d6SYongseok Koh 
20286cb559d6SYongseok Koh int __attribute__((weak))
20296cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv)
20306cb559d6SYongseok Koh {
20316cb559d6SYongseok Koh 	(void)priv;
20326cb559d6SYongseok Koh 	return -ENOTSUP;
20336cb559d6SYongseok Koh }
2034