xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 3ca63b88a8c9c79d3ca630e2ed6cdff110b382b0)
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>
4543e9d979SShachar Beiser #include <infiniband/mlx5dv.h>
462e22920bSAdrien Mazarguil #ifdef PEDANTIC
47fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
482e22920bSAdrien Mazarguil #endif
492e22920bSAdrien Mazarguil 
502e22920bSAdrien Mazarguil #include <rte_mbuf.h>
512e22920bSAdrien Mazarguil #include <rte_mempool.h>
522e22920bSAdrien Mazarguil #include <rte_prefetch.h>
532e22920bSAdrien Mazarguil #include <rte_common.h>
542e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
556218063bSNélio Laranjeiro #include <rte_ether.h>
562e22920bSAdrien Mazarguil 
572e22920bSAdrien Mazarguil #include "mlx5.h"
582e22920bSAdrien Mazarguil #include "mlx5_utils.h"
592e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
60f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
612e22920bSAdrien Mazarguil #include "mlx5_defs.h"
626218063bSNélio Laranjeiro #include "mlx5_prm.h"
636218063bSNélio Laranjeiro 
64c0583d98SJerin Jacob static __rte_always_inline uint32_t
65c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe);
66ff1807a3SNélio Laranjeiro 
67c0583d98SJerin Jacob static __rte_always_inline int
6878142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
69c0583d98SJerin Jacob 		 uint16_t cqe_cnt, uint32_t *rss_hash);
70ff1807a3SNélio Laranjeiro 
71c0583d98SJerin Jacob static __rte_always_inline uint32_t
7278142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe);
73ff1807a3SNélio Laranjeiro 
74ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
75ea16068cSYongseok Koh 	[0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
76ea16068cSYongseok Koh };
77ea16068cSYongseok Koh 
78ea16068cSYongseok Koh /**
79ea16068cSYongseok Koh  * Build a table to translate Rx completion flags to packet type.
80ea16068cSYongseok Koh  *
81ea16068cSYongseok Koh  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
82ea16068cSYongseok Koh  */
83ea16068cSYongseok Koh void
84ea16068cSYongseok Koh mlx5_set_ptype_table(void)
85ea16068cSYongseok Koh {
86ea16068cSYongseok Koh 	unsigned int i;
87ea16068cSYongseok Koh 	uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
88ea16068cSYongseok Koh 
899807f113SYongseok Koh 	/* Last entry must not be overwritten, reserved for errored packet. */
909807f113SYongseok Koh 	for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
91ea16068cSYongseok Koh 		(*p)[i] = RTE_PTYPE_UNKNOWN;
926cb559d6SYongseok Koh 	/*
936cb559d6SYongseok Koh 	 * The index to the array should have:
94ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
95ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
96ea16068cSYongseok Koh 	 * bit[5] = ip_frag
97ea16068cSYongseok Koh 	 * bit[6] = tunneled
98ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
9999c12dccSNélio Laranjeiro 	 */
100*3ca63b88SShahaf Shuler 	/* L2 */
101*3ca63b88SShahaf Shuler 	(*p)[0x00] = RTE_PTYPE_L2_ETHER;
102ea16068cSYongseok Koh 	/* L3 */
103ea16068cSYongseok Koh 	(*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
104ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
105ea16068cSYongseok Koh 	(*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
106ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
107ea16068cSYongseok Koh 	/* Fragmented */
108ea16068cSYongseok Koh 	(*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
109ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
110ea16068cSYongseok Koh 	(*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
111ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
112ea16068cSYongseok Koh 	/* TCP */
113ea16068cSYongseok Koh 	(*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
114ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
115ea16068cSYongseok Koh 	(*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
116ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
117ea16068cSYongseok Koh 	/* UDP */
118ea16068cSYongseok Koh 	(*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
119ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
120ea16068cSYongseok Koh 	(*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
121ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
122ea16068cSYongseok Koh 	/* Repeat with outer_l3_type being set. Just in case. */
123ea16068cSYongseok Koh 	(*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
124ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
125ea16068cSYongseok Koh 	(*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
126ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
127ea16068cSYongseok Koh 	(*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
128ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
129ea16068cSYongseok Koh 	(*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
130ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
131ea16068cSYongseok Koh 	(*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
132ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
133ea16068cSYongseok Koh 	(*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
134ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
135ea16068cSYongseok Koh 	(*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
136ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
137ea16068cSYongseok Koh 	(*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
138ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
139ea16068cSYongseok Koh 	/* Tunneled - L3 */
140ea16068cSYongseok Koh 	(*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
141ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
142ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
143ea16068cSYongseok Koh 	(*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
144ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
145ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
146ea16068cSYongseok Koh 	(*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
147ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
148ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
149ea16068cSYongseok Koh 	(*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
150ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
151ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
152ea16068cSYongseok Koh 	/* Tunneled - Fragmented */
153ea16068cSYongseok Koh 	(*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
154ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
155ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
156ea16068cSYongseok Koh 	(*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
157ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
158ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
159ea16068cSYongseok Koh 	(*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
160ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
161ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
162ea16068cSYongseok Koh 	(*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
163ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
164ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
165ea16068cSYongseok Koh 	/* Tunneled - TCP */
166ea16068cSYongseok Koh 	(*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
167ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
168ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
169ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
170ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
171ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
172ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
173ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
174ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
175ea16068cSYongseok Koh 	(*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
176ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
177ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
178ea16068cSYongseok Koh 	/* Tunneled - UDP */
179ea16068cSYongseok Koh 	(*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
180ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
181ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
182ea16068cSYongseok Koh 	(*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
183ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
184ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
185ea16068cSYongseok Koh 	(*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
186ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
187ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
188ea16068cSYongseok Koh 	(*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
189ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
190ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
191ea16068cSYongseok Koh }
192fdcb0f53SNélio Laranjeiro 
1932e22920bSAdrien Mazarguil /**
1946ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
1956ce84bd8SYongseok Koh  *
1966ce84bd8SYongseok Koh  * @param txq
1976ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
1986ce84bd8SYongseok Koh  * @param addr
1996ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
2006ce84bd8SYongseok Koh  *
2016ce84bd8SYongseok Koh  * @return
2026ce84bd8SYongseok Koh  *   Size of tailroom.
2036ce84bd8SYongseok Koh  */
2046ce84bd8SYongseok Koh static inline size_t
205991b04f6SNélio Laranjeiro tx_mlx5_wq_tailroom(struct mlx5_txq_data *txq, void *addr)
2066ce84bd8SYongseok Koh {
2076ce84bd8SYongseok Koh 	size_t tailroom;
2086ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
2096ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
2106ce84bd8SYongseok Koh 		   (uintptr_t)addr;
2116ce84bd8SYongseok Koh 	return tailroom;
2126ce84bd8SYongseok Koh }
2136ce84bd8SYongseok Koh 
2146ce84bd8SYongseok Koh /**
2156ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
2166ce84bd8SYongseok Koh  *
2176ce84bd8SYongseok Koh  * @param dst
2186ce84bd8SYongseok Koh  *   Pointer to destination.
2196ce84bd8SYongseok Koh  * @param src
2206ce84bd8SYongseok Koh  *   Pointer to source.
2216ce84bd8SYongseok Koh  * @param n
2226ce84bd8SYongseok Koh  *   Number of bytes to copy.
2236ce84bd8SYongseok Koh  * @param base
2246ce84bd8SYongseok Koh  *   Pointer to head of queue.
2256ce84bd8SYongseok Koh  * @param tailroom
2266ce84bd8SYongseok Koh  *   Size of tailroom from dst.
2276ce84bd8SYongseok Koh  *
2286ce84bd8SYongseok Koh  * @return
2296ce84bd8SYongseok Koh  *   Pointer after copied data.
2306ce84bd8SYongseok Koh  */
2316ce84bd8SYongseok Koh static inline void *
2326ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
2336ce84bd8SYongseok Koh 		void *base, size_t tailroom)
2346ce84bd8SYongseok Koh {
2356ce84bd8SYongseok Koh 	void *ret;
2366ce84bd8SYongseok Koh 
2376ce84bd8SYongseok Koh 	if (n > tailroom) {
2386ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
2396ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
2406ce84bd8SYongseok Koh 			   n - tailroom);
2416ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
2426ce84bd8SYongseok Koh 	} else {
2436ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
2446ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
2456ce84bd8SYongseok Koh 	}
2466ce84bd8SYongseok Koh 	return ret;
2476ce84bd8SYongseok Koh }
2486ce84bd8SYongseok Koh 
2496ce84bd8SYongseok Koh /**
2508788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
2518788fec1SOlivier Matz  *
2528788fec1SOlivier Matz  * @param tx_queue
2538788fec1SOlivier Matz  *   The tx queue.
2548788fec1SOlivier Matz  * @param[in] offset
2558788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2568788fec1SOlivier Matz  *
2578788fec1SOlivier Matz  * @return
2588788fec1SOlivier Matz  *   The status of the tx descriptor.
2598788fec1SOlivier Matz  */
2608788fec1SOlivier Matz int
2618788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
2628788fec1SOlivier Matz {
263991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = tx_queue;
2648c819a69SYongseok Koh 	uint16_t used;
2658788fec1SOlivier Matz 
2666cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
2678c819a69SYongseok Koh 	used = txq->elts_head - txq->elts_tail;
2688788fec1SOlivier Matz 	if (offset < used)
2698788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
2708788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
2718788fec1SOlivier Matz }
2728788fec1SOlivier Matz 
2738788fec1SOlivier Matz /**
2748788fec1SOlivier Matz  * DPDK callback to check the status of a rx descriptor.
2758788fec1SOlivier Matz  *
2768788fec1SOlivier Matz  * @param rx_queue
2778788fec1SOlivier Matz  *   The rx queue.
2788788fec1SOlivier Matz  * @param[in] offset
2798788fec1SOlivier Matz  *   The index of the descriptor in the ring.
2808788fec1SOlivier Matz  *
2818788fec1SOlivier Matz  * @return
2828788fec1SOlivier Matz  *   The status of the tx descriptor.
2838788fec1SOlivier Matz  */
2848788fec1SOlivier Matz int
2858788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
2868788fec1SOlivier Matz {
28778142aacSNélio Laranjeiro 	struct mlx5_rxq_data *rxq = rx_queue;
2888788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
2898788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
2908788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
2918788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
2928788fec1SOlivier Matz 	unsigned int cq_ci;
2938788fec1SOlivier Matz 	unsigned int used;
2948788fec1SOlivier Matz 
2958788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
2968788fec1SOlivier Matz 	if (zip->ai) {
2978788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
2988788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
2998788fec1SOlivier Matz 	} else {
3008788fec1SOlivier Matz 		used = 0;
3018788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
3028788fec1SOlivier Matz 	}
3038788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3048788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
3058788fec1SOlivier Matz 		int8_t op_own;
3068788fec1SOlivier Matz 		unsigned int n;
3078788fec1SOlivier Matz 
3088788fec1SOlivier Matz 		op_own = cqe->op_own;
3098788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
3106b30a6a8SShachar Beiser 			n = rte_be_to_cpu_32(cqe->byte_cnt);
3118788fec1SOlivier Matz 		else
3128788fec1SOlivier Matz 			n = 1;
3138788fec1SOlivier Matz 		cq_ci += n;
3148788fec1SOlivier Matz 		used += n;
3158788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3168788fec1SOlivier Matz 	}
3178788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
3188788fec1SOlivier Matz 	if (offset < used)
3198788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
3208788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
3218788fec1SOlivier Matz }
3228788fec1SOlivier Matz 
3238788fec1SOlivier Matz /**
3242e22920bSAdrien Mazarguil  * DPDK callback for TX.
3252e22920bSAdrien Mazarguil  *
3262e22920bSAdrien Mazarguil  * @param dpdk_txq
3272e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
3282e22920bSAdrien Mazarguil  * @param[in] pkts
3292e22920bSAdrien Mazarguil  *   Packets to transmit.
3302e22920bSAdrien Mazarguil  * @param pkts_n
3312e22920bSAdrien Mazarguil  *   Number of packets in array.
3322e22920bSAdrien Mazarguil  *
3332e22920bSAdrien Mazarguil  * @return
3342e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
3352e22920bSAdrien Mazarguil  */
3362e22920bSAdrien Mazarguil uint16_t
3372e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
3382e22920bSAdrien Mazarguil {
339991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
3401d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
3418c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
3428c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
343c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
344a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
3453f13f8c2SShahaf Shuler 	unsigned int k = 0;
3468c819a69SYongseok Koh 	uint16_t max_elts;
347ab76eab3SYongseok Koh 	unsigned int max_inline = txq->max_inline;
348ab76eab3SYongseok Koh 	const unsigned int inline_en = !!max_inline && txq->inline_en;
349f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
350c305090bSAdrien Mazarguil 	unsigned int comp;
3519a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
352ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
3536579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
3546579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
3556579c27cSNélio Laranjeiro 	uint8_t *raw;
3562e22920bSAdrien Mazarguil 
3571d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
3581d88ba17SNélio Laranjeiro 		return 0;
3595e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
360c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
3611d88ba17SNélio Laranjeiro 	/* Start processing. */
3626cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
3638c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
364f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
365f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
366f04f1d51SNélio Laranjeiro 		return 0;
367c3d62cc9SAdrien Mazarguil 	do {
3689a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
369573f54afSNélio Laranjeiro 		uint32_t length;
3708688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
371ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
3726579c27cSNélio Laranjeiro 		uintptr_t addr;
3739a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
3740d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
3753f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
376eef822ddSNélio Laranjeiro 		uint16_t ehdr;
3779a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
3783f13f8c2SShahaf Shuler 		uint64_t tso = 0;
37983daf156SShahaf Shuler 		uint16_t tso_segsz = 0;
3806579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
3816579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
3826579c27cSNélio Laranjeiro #endif
3832e22920bSAdrien Mazarguil 
3846579c27cSNélio Laranjeiro 		/* first_seg */
3853730e6c6SYongseok Koh 		buf = *pkts;
3866579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
387c3d62cc9SAdrien Mazarguil 		/*
388c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
389c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
390c3d62cc9SAdrien Mazarguil 		 */
391a5bf6af9SAdrien Mazarguil 		assert(segs_n);
3928c819a69SYongseok Koh 		if (max_elts < segs_n)
393c3d62cc9SAdrien Mazarguil 			break;
3948c819a69SYongseok Koh 		max_elts -= segs_n;
3956579c27cSNélio Laranjeiro 		--segs_n;
396f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
397f04f1d51SNélio Laranjeiro 			break;
3989a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
399fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
400fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
4013730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4023730e6c6SYongseok Koh 			rte_prefetch0(*(pkts + 1));
4036579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
4042e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
405eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
406eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
4076579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
4086579c27cSNélio Laranjeiro 		total_length = length;
4096579c27cSNélio Laranjeiro #endif
41024c14430SShahaf Shuler 		if (length < (MLX5_WQE_DWORD_SIZE + 2)) {
41124c14430SShahaf Shuler 			txq->stats.oerrors++;
412959be52eSNélio Laranjeiro 			break;
41324c14430SShahaf Shuler 		}
4142e22920bSAdrien Mazarguil 		/* Update element. */
4158c819a69SYongseok Koh 		(*txq->elts)[elts_head & elts_m] = buf;
4165e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
4173730e6c6SYongseok Koh 		if (pkts_n - i > 1)
4183730e6c6SYongseok Koh 			rte_prefetch0(
4193730e6c6SYongseok Koh 			    rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
4201d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
4211d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
4221d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
423f5fde520SShahaf Shuler 			const uint64_t is_tunneled = buf->ol_flags &
424f5fde520SShahaf Shuler 						     (PKT_TX_TUNNEL_GRE |
425f5fde520SShahaf Shuler 						      PKT_TX_TUNNEL_VXLAN);
426f5fde520SShahaf Shuler 
427f5fde520SShahaf Shuler 			if (is_tunneled && txq->tunnel_en) {
428f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM |
429f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_INNER_CSUM;
430f5fde520SShahaf Shuler 				if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
431f5fde520SShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L3_CSUM;
432f5fde520SShahaf Shuler 			} else {
433f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_CSUM |
434f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_CSUM;
435f5fde520SShahaf Shuler 			}
4361d88ba17SNélio Laranjeiro 		}
437b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
4386579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
4396579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
4406b30a6a8SShachar Beiser 			uint32_t vlan = rte_cpu_to_be_32(0x81000000 |
4416b30a6a8SShachar Beiser 							 buf->vlan_tci);
4420d637a34SNélio Laranjeiro 			unsigned int len = 2 * ETHER_ADDR_LEN - 2;
4436579c27cSNélio Laranjeiro 
4440d637a34SNélio Laranjeiro 			addr += 2;
4450d637a34SNélio Laranjeiro 			length -= 2;
4460d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
4470d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
4480d637a34SNélio Laranjeiro 			/* Copy VLAN. */
4490d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
4500d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
4510d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
4520d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
4530d637a34SNélio Laranjeiro 			addr += len + 2;
4540d637a34SNélio Laranjeiro 			length -= (len + 2);
4550d637a34SNélio Laranjeiro 		} else {
4560d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
4570d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
4580d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
4590d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
4606579c27cSNélio Laranjeiro 		}
461d8292497SYongseok Koh 		raw += MLX5_WQE_DWORD_SIZE;
4623f13f8c2SShahaf Shuler 		if (txq->tso_en) {
4633f13f8c2SShahaf Shuler 			tso = buf->ol_flags & PKT_TX_TCP_SEG;
4643f13f8c2SShahaf Shuler 			if (tso) {
4653f13f8c2SShahaf Shuler 				uintptr_t end = (uintptr_t)
4663f13f8c2SShahaf Shuler 						(((uintptr_t)txq->wqes) +
4673f13f8c2SShahaf Shuler 						(1 << txq->wqe_n) *
4683f13f8c2SShahaf Shuler 						MLX5_WQE_SIZE);
4693f13f8c2SShahaf Shuler 				unsigned int copy_b;
4703f13f8c2SShahaf Shuler 				uint8_t vlan_sz = (buf->ol_flags &
4713f13f8c2SShahaf Shuler 						  PKT_TX_VLAN_PKT) ? 4 : 0;
472b247f346SShahaf Shuler 				const uint64_t is_tunneled =
473b247f346SShahaf Shuler 							buf->ol_flags &
474b247f346SShahaf Shuler 							(PKT_TX_TUNNEL_GRE |
475b247f346SShahaf Shuler 							 PKT_TX_TUNNEL_VXLAN);
4763f13f8c2SShahaf Shuler 
4773f13f8c2SShahaf Shuler 				tso_header_sz = buf->l2_len + vlan_sz +
4783f13f8c2SShahaf Shuler 						buf->l3_len + buf->l4_len;
47983daf156SShahaf Shuler 				tso_segsz = buf->tso_segsz;
48096fc8d65SShahaf Shuler 				if (unlikely(tso_segsz == 0)) {
48196fc8d65SShahaf Shuler 					txq->stats.oerrors++;
48296fc8d65SShahaf Shuler 					break;
48396fc8d65SShahaf Shuler 				}
484b247f346SShahaf Shuler 				if (is_tunneled	&& txq->tunnel_en) {
485b247f346SShahaf Shuler 					tso_header_sz += buf->outer_l2_len +
486b247f346SShahaf Shuler 							 buf->outer_l3_len;
4872a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
4882a6c96beSShahaf Shuler 				} else {
4892a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_CSUM;
490b247f346SShahaf Shuler 				}
4913f13f8c2SShahaf Shuler 				if (unlikely(tso_header_sz >
49224c14430SShahaf Shuler 					     MLX5_MAX_TSO_HEADER)) {
49324c14430SShahaf Shuler 					txq->stats.oerrors++;
4943f13f8c2SShahaf Shuler 					break;
49524c14430SShahaf Shuler 				}
4963f13f8c2SShahaf Shuler 				copy_b = tso_header_sz - pkt_inline_sz;
4973f13f8c2SShahaf Shuler 				/* First seg must contain all headers. */
4983f13f8c2SShahaf Shuler 				assert(copy_b <= length);
4993f13f8c2SShahaf Shuler 				if (copy_b &&
5003f13f8c2SShahaf Shuler 				   ((end - (uintptr_t)raw) > copy_b)) {
5013f13f8c2SShahaf Shuler 					uint16_t n = (MLX5_WQE_DS(copy_b) -
5023f13f8c2SShahaf Shuler 						      1 + 3) / 4;
5033f13f8c2SShahaf Shuler 
5043f13f8c2SShahaf Shuler 					if (unlikely(max_wqe < n))
5053f13f8c2SShahaf Shuler 						break;
5063f13f8c2SShahaf Shuler 					max_wqe -= n;
5073f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5083f13f8c2SShahaf Shuler 						   (void *)addr, copy_b);
5093f13f8c2SShahaf Shuler 					addr += copy_b;
5103f13f8c2SShahaf Shuler 					length -= copy_b;
511d8292497SYongseok Koh 					/* Include padding for TSO header. */
512d8292497SYongseok Koh 					copy_b = MLX5_WQE_DS(copy_b) *
5133f13f8c2SShahaf Shuler 						 MLX5_WQE_DWORD_SIZE;
514d8292497SYongseok Koh 					pkt_inline_sz += copy_b;
515d8292497SYongseok Koh 					raw += copy_b;
5163f13f8c2SShahaf Shuler 				} else {
5173f13f8c2SShahaf Shuler 					/* NOP WQE. */
5183f13f8c2SShahaf Shuler 					wqe->ctrl = (rte_v128u32_t){
5196b30a6a8SShachar Beiser 						     rte_cpu_to_be_32(
5206b30a6a8SShachar Beiser 							txq->wqe_ci << 8),
5216b30a6a8SShachar Beiser 						     rte_cpu_to_be_32(
5226b30a6a8SShachar Beiser 							txq->qp_num_8s | 1),
5233f13f8c2SShahaf Shuler 						     0,
5243f13f8c2SShahaf Shuler 						     0,
5253f13f8c2SShahaf Shuler 					};
5263f13f8c2SShahaf Shuler 					ds = 1;
5273f13f8c2SShahaf Shuler 					total_length = 0;
5283f13f8c2SShahaf Shuler 					k++;
5293f13f8c2SShahaf Shuler 					goto next_wqe;
5303f13f8c2SShahaf Shuler 				}
5313f13f8c2SShahaf Shuler 			}
5323f13f8c2SShahaf Shuler 		}
5336579c27cSNélio Laranjeiro 		/* Inline if enough room. */
534ab76eab3SYongseok Koh 		if (inline_en || tso) {
535d8292497SYongseok Koh 			uint32_t inl;
536fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
537fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
538fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
539ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
5408fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
541d8292497SYongseok Koh 						   (pkt_inline_sz - 2) -
542d8292497SYongseok Koh 						   !!tso * sizeof(inl);
543ab76eab3SYongseok Koh 			uintptr_t addr_end = (addr + inline_room) &
5446579c27cSNélio Laranjeiro 					     ~(RTE_CACHE_LINE_SIZE - 1);
5458fcd6c2cSNélio Laranjeiro 			unsigned int copy_b = (addr_end > addr) ?
5468fcd6c2cSNélio Laranjeiro 				RTE_MIN((addr_end - addr), length) :
5478fcd6c2cSNélio Laranjeiro 				0;
5486579c27cSNélio Laranjeiro 
5498fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
550f04f1d51SNélio Laranjeiro 				/*
551f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
552f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
553f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
554f04f1d51SNélio Laranjeiro 				 */
5558fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
5568fcd6c2cSNélio Laranjeiro 
557f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
558f04f1d51SNélio Laranjeiro 					break;
559f04f1d51SNélio Laranjeiro 				max_wqe -= n;
5603f13f8c2SShahaf Shuler 				if (tso) {
5616b30a6a8SShachar Beiser 					uint32_t inl =
5626b30a6a8SShachar Beiser 					rte_cpu_to_be_32(copy_b |
5636b30a6a8SShachar Beiser 							 MLX5_INLINE_SEG);
5646b30a6a8SShachar Beiser 
5656b30a6a8SShachar Beiser 					pkt_inline_sz =
5666b30a6a8SShachar Beiser 						MLX5_WQE_DS(tso_header_sz) *
5676b30a6a8SShachar Beiser 						MLX5_WQE_DWORD_SIZE;
5686b30a6a8SShachar Beiser 
5693f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5703f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
5713f13f8c2SShahaf Shuler 					raw += sizeof(inl);
5723f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
5733f13f8c2SShahaf Shuler 				}
5746579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
5756579c27cSNélio Laranjeiro 				addr += copy_b;
5766579c27cSNélio Laranjeiro 				length -= copy_b;
5776579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
5786579c27cSNélio Laranjeiro 			}
5796579c27cSNélio Laranjeiro 			/*
580786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
5816579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
5826579c27cSNélio Laranjeiro 			 */
5836579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
5846579c27cSNélio Laranjeiro 			if (length > 0) {
585f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
586f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
587f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
588f04f1d51SNélio Laranjeiro 						break;
589f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
590f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
591f04f1d51SNélio Laranjeiro 							   ds / 4);
592f04f1d51SNélio Laranjeiro 				} else {
5939a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
5946579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
5956579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
596f04f1d51SNélio Laranjeiro 				}
5976579c27cSNélio Laranjeiro 				goto use_dseg;
5986579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5996579c27cSNélio Laranjeiro 				goto next_pkt;
6006579c27cSNélio Laranjeiro 			} else {
601786b5c2dSShahaf Shuler 				/* dseg will be advance as part of next_seg */
602786b5c2dSShahaf Shuler 				dseg = (volatile rte_v128u32_t *)
603786b5c2dSShahaf Shuler 					((uintptr_t)wqe +
604786b5c2dSShahaf Shuler 					 ((ds - 1) * MLX5_WQE_DWORD_SIZE));
6056579c27cSNélio Laranjeiro 				goto next_seg;
6066579c27cSNélio Laranjeiro 			}
6076579c27cSNélio Laranjeiro 		} else {
6086579c27cSNélio Laranjeiro 			/*
6096579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
6106579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
6116579c27cSNélio Laranjeiro 			 */
6129a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
6136579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
6146579c27cSNélio Laranjeiro 			ds = 3;
6156579c27cSNélio Laranjeiro use_dseg:
6166579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
6176b30a6a8SShachar Beiser 			naddr = rte_cpu_to_be_64(addr);
6189a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
6196b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
6206cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
6219a7fa9f7SNélio Laranjeiro 				naddr,
6229a7fa9f7SNélio Laranjeiro 				naddr >> 32,
6236579c27cSNélio Laranjeiro 			};
6246579c27cSNélio Laranjeiro 			++ds;
6256579c27cSNélio Laranjeiro 			if (!segs_n)
6266579c27cSNélio Laranjeiro 				goto next_pkt;
6276579c27cSNélio Laranjeiro 		}
6286579c27cSNélio Laranjeiro next_seg:
6296579c27cSNélio Laranjeiro 		assert(buf);
6306579c27cSNélio Laranjeiro 		assert(ds);
6316579c27cSNélio Laranjeiro 		assert(wqe);
632a5bf6af9SAdrien Mazarguil 		/*
633a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
634a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
635a5bf6af9SAdrien Mazarguil 		 * of data segment size.
636a5bf6af9SAdrien Mazarguil 		 */
6378688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
6386579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
639f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
640f04f1d51SNélio Laranjeiro 				break;
6419a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
642f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
643f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
644f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
6456579c27cSNélio Laranjeiro 		} else {
646a5bf6af9SAdrien Mazarguil 			++dseg;
6476579c27cSNélio Laranjeiro 		}
648a5bf6af9SAdrien Mazarguil 		++ds;
649a5bf6af9SAdrien Mazarguil 		buf = buf->next;
650a5bf6af9SAdrien Mazarguil 		assert(buf);
6516579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
652a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
6536579c27cSNélio Laranjeiro 		total_length += length;
654a5bf6af9SAdrien Mazarguil #endif
6556579c27cSNélio Laranjeiro 		/* Store segment information. */
6566b30a6a8SShachar Beiser 		naddr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t));
6579a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
6586b30a6a8SShachar Beiser 			rte_cpu_to_be_32(length),
6596cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
6609a7fa9f7SNélio Laranjeiro 			naddr,
6619a7fa9f7SNélio Laranjeiro 			naddr >> 32,
6626579c27cSNélio Laranjeiro 		};
6638c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
664ac180a21SYongseok Koh 		++sg;
665ac180a21SYongseok Koh 		/* Advance counter only if all segs are successfully posted. */
6663730e6c6SYongseok Koh 		if (sg < segs_n)
6676579c27cSNélio Laranjeiro 			goto next_seg;
6683730e6c6SYongseok Koh 		else
669ac180a21SYongseok Koh 			j += sg;
6706579c27cSNélio Laranjeiro next_pkt:
671883ce172SShahaf Shuler 		if (ds > MLX5_DSEG_MAX) {
672883ce172SShahaf Shuler 			txq->stats.oerrors++;
673883ce172SShahaf Shuler 			break;
674883ce172SShahaf Shuler 		}
6758c819a69SYongseok Koh 		++elts_head;
6763730e6c6SYongseok Koh 		++pkts;
6776579c27cSNélio Laranjeiro 		++i;
678b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
6793f13f8c2SShahaf Shuler 		if (tso) {
6803f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
6816b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6826b30a6a8SShachar Beiser 						 MLX5_OPCODE_TSO),
6836b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6843f13f8c2SShahaf Shuler 				0,
6853f13f8c2SShahaf Shuler 				0,
6863f13f8c2SShahaf Shuler 			};
6873f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
6883f13f8c2SShahaf Shuler 				0,
6896b30a6a8SShachar Beiser 				cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16),
6903f13f8c2SShahaf Shuler 				0,
6916b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(tso_header_sz),
6923f13f8c2SShahaf Shuler 			};
6933f13f8c2SShahaf Shuler 		} else {
6949a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
6956b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6966b30a6a8SShachar Beiser 						 MLX5_OPCODE_SEND),
6976b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6989a7fa9f7SNélio Laranjeiro 				0,
6999a7fa9f7SNélio Laranjeiro 				0,
7009a7fa9f7SNélio Laranjeiro 			};
7019a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
7029a7fa9f7SNélio Laranjeiro 				0,
7039a7fa9f7SNélio Laranjeiro 				cs_flags,
7049a7fa9f7SNélio Laranjeiro 				0,
7056b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz),
7069a7fa9f7SNélio Laranjeiro 			};
7073f13f8c2SShahaf Shuler 		}
7083f13f8c2SShahaf Shuler next_wqe:
7096579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
710ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
711ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
71287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
713573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
7146579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
71587011737SAdrien Mazarguil #endif
7163730e6c6SYongseok Koh 	} while (i < pkts_n);
7172e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
7183f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
7192e22920bSAdrien Mazarguil 		return 0;
7208c819a69SYongseok Koh 	txq->elts_head += (i + j);
721c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
7223f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
723c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
724c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
7256b30a6a8SShachar Beiser 		last_wqe->ctrl2 = rte_cpu_to_be_32(8);
726c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
727ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
728c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
729c305090bSAdrien Mazarguil 	} else {
730c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
731c305090bSAdrien Mazarguil 	}
73287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
73387011737SAdrien Mazarguil 	/* Increment sent packets counter. */
73487011737SAdrien Mazarguil 	txq->stats.opackets += i;
73587011737SAdrien Mazarguil #endif
7362e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
737ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
7382e22920bSAdrien Mazarguil 	return i;
7392e22920bSAdrien Mazarguil }
7402e22920bSAdrien Mazarguil 
7412e22920bSAdrien Mazarguil /**
742230189d9SNélio Laranjeiro  * Open a MPW session.
743230189d9SNélio Laranjeiro  *
744230189d9SNélio Laranjeiro  * @param txq
745230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
746230189d9SNélio Laranjeiro  * @param mpw
747230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
748230189d9SNélio Laranjeiro  * @param length
749230189d9SNélio Laranjeiro  *   Packet length.
750230189d9SNélio Laranjeiro  */
751230189d9SNélio Laranjeiro static inline void
752991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length)
753230189d9SNélio Laranjeiro {
754a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
755230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
756230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
757fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
758230189d9SNélio Laranjeiro 
759230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
760230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
761230189d9SNélio Laranjeiro 	mpw->len = length;
762230189d9SNélio Laranjeiro 	mpw->total_len = 0;
763fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
7646b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
7658688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
7668688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
7678688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
7688688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
7696b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
7706b30a6a8SShachar Beiser 					     (txq->wqe_ci << 8) |
7716b30a6a8SShachar Beiser 					     MLX5_OPCODE_TSO);
7728688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
7738688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
7748688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
7758688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
7768688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
7778688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
778230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
779230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
780230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
781230189d9SNélio Laranjeiro }
782230189d9SNélio Laranjeiro 
783230189d9SNélio Laranjeiro /**
784230189d9SNélio Laranjeiro  * Close a MPW session.
785230189d9SNélio Laranjeiro  *
786230189d9SNélio Laranjeiro  * @param txq
787230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
788230189d9SNélio Laranjeiro  * @param mpw
789230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
790230189d9SNélio Laranjeiro  */
791230189d9SNélio Laranjeiro static inline void
792991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
793230189d9SNélio Laranjeiro {
794230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
795230189d9SNélio Laranjeiro 
796230189d9SNélio Laranjeiro 	/*
797230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
798230189d9SNélio Laranjeiro 	 * count as 2.
799230189d9SNélio Laranjeiro 	 */
8006b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num));
801230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
802230189d9SNélio Laranjeiro 	if (num < 3)
803230189d9SNélio Laranjeiro 		++txq->wqe_ci;
804230189d9SNélio Laranjeiro 	else
805230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
806fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
807fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
808230189d9SNélio Laranjeiro }
809230189d9SNélio Laranjeiro 
810230189d9SNélio Laranjeiro /**
811230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
812230189d9SNélio Laranjeiro  *
813230189d9SNélio Laranjeiro  * @param dpdk_txq
814230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
815230189d9SNélio Laranjeiro  * @param[in] pkts
816230189d9SNélio Laranjeiro  *   Packets to transmit.
817230189d9SNélio Laranjeiro  * @param pkts_n
818230189d9SNélio Laranjeiro  *   Number of packets in array.
819230189d9SNélio Laranjeiro  *
820230189d9SNélio Laranjeiro  * @return
821230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
822230189d9SNélio Laranjeiro  */
823230189d9SNélio Laranjeiro uint16_t
824230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
825230189d9SNélio Laranjeiro {
826991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
827230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
8288c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
8298c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
830c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
831a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
8328c819a69SYongseok Koh 	uint16_t max_elts;
833f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
834230189d9SNélio Laranjeiro 	unsigned int comp;
835230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
836230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
837230189d9SNélio Laranjeiro 	};
838230189d9SNélio Laranjeiro 
839c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
840c3d62cc9SAdrien Mazarguil 		return 0;
841230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
842fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
843fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
844230189d9SNélio Laranjeiro 	/* Start processing. */
8456cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
8468c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
847f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
848f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
849f04f1d51SNélio Laranjeiro 		return 0;
850c3d62cc9SAdrien Mazarguil 	do {
851a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
852230189d9SNélio Laranjeiro 		uint32_t length;
853a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
854230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
855230189d9SNélio Laranjeiro 
856c3d62cc9SAdrien Mazarguil 		/*
857c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
858c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
859c3d62cc9SAdrien Mazarguil 		 */
860a5bf6af9SAdrien Mazarguil 		assert(segs_n);
8618c819a69SYongseok Koh 		if (max_elts < segs_n)
862c3d62cc9SAdrien Mazarguil 			break;
863a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
86424c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
86524c14430SShahaf Shuler 			txq->stats.oerrors++;
866a5bf6af9SAdrien Mazarguil 			break;
86724c14430SShahaf Shuler 		}
8688c819a69SYongseok Koh 		max_elts -= segs_n;
869c3d62cc9SAdrien Mazarguil 		--pkts_n;
870230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
871230189d9SNélio Laranjeiro 		if (buf->ol_flags &
872230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
873230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
874a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
875a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
876a5bf6af9SAdrien Mazarguil 		assert(length);
877230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
878230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
879230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
880a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
8818688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
882230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
883230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
884f04f1d51SNélio Laranjeiro 			/*
885f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
886f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
887f04f1d51SNélio Laranjeiro 			 * resources.
888f04f1d51SNélio Laranjeiro 			 */
889f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
890f04f1d51SNélio Laranjeiro 				break;
891f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
892230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
8938688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
894230189d9SNélio Laranjeiro 		}
895a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
896a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
897a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
898a5bf6af9SAdrien Mazarguil 		length = 0;
899a5bf6af9SAdrien Mazarguil #endif
900a5bf6af9SAdrien Mazarguil 		do {
901a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
902a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
903a5bf6af9SAdrien Mazarguil 
904a5bf6af9SAdrien Mazarguil 			assert(buf);
9058c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
906230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
907a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
908230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
9096b30a6a8SShachar Beiser 				.byte_count = rte_cpu_to_be_32(DATA_LEN(buf)),
9106cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
9116b30a6a8SShachar Beiser 				.addr = rte_cpu_to_be_64(addr),
912230189d9SNélio Laranjeiro 			};
913a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
914a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
915a5bf6af9SAdrien Mazarguil #endif
916a5bf6af9SAdrien Mazarguil 			buf = buf->next;
917230189d9SNélio Laranjeiro 			++mpw.pkts_n;
918a5bf6af9SAdrien Mazarguil 			++j;
919a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
920a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
921230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
922230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
923230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
924230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
925230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
926230189d9SNélio Laranjeiro #endif
927c3d62cc9SAdrien Mazarguil 		++i;
928c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
929230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
930230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
931230189d9SNélio Laranjeiro 		return 0;
932230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
933a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
934a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
935230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
9368688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
937230189d9SNélio Laranjeiro 
938230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
9396b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
940230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
9418688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
942230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
943230189d9SNélio Laranjeiro 	} else {
944230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
945230189d9SNélio Laranjeiro 	}
946230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
947230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
948230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
949230189d9SNélio Laranjeiro #endif
950230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
951230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
952230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
95330807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
954230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
955230189d9SNélio Laranjeiro 	return i;
956230189d9SNélio Laranjeiro }
957230189d9SNélio Laranjeiro 
958230189d9SNélio Laranjeiro /**
959230189d9SNélio Laranjeiro  * Open a MPW inline session.
960230189d9SNélio Laranjeiro  *
961230189d9SNélio Laranjeiro  * @param txq
962230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
963230189d9SNélio Laranjeiro  * @param mpw
964230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
965230189d9SNélio Laranjeiro  * @param length
966230189d9SNélio Laranjeiro  *   Packet length.
967230189d9SNélio Laranjeiro  */
968230189d9SNélio Laranjeiro static inline void
969991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw,
970991b04f6SNélio Laranjeiro 		    uint32_t length)
971230189d9SNélio Laranjeiro {
972a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
9738688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
974230189d9SNélio Laranjeiro 
975230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
976230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
977230189d9SNélio Laranjeiro 	mpw->len = length;
978230189d9SNélio Laranjeiro 	mpw->total_len = 0;
979fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9806b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
981230189d9SNélio Laranjeiro 					     (txq->wqe_ci << 8) |
982c904ae25SNélio Laranjeiro 					     MLX5_OPCODE_TSO);
9838688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9848688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9856b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
9868688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9878688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
9888688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9898688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9908688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
9918688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
9928688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
9938688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
994230189d9SNélio Laranjeiro }
995230189d9SNélio Laranjeiro 
996230189d9SNélio Laranjeiro /**
997230189d9SNélio Laranjeiro  * Close a MPW inline session.
998230189d9SNélio Laranjeiro  *
999230189d9SNélio Laranjeiro  * @param txq
1000230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
1001230189d9SNélio Laranjeiro  * @param mpw
1002230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1003230189d9SNélio Laranjeiro  */
1004230189d9SNélio Laranjeiro static inline void
1005991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
1006230189d9SNélio Laranjeiro {
1007230189d9SNélio Laranjeiro 	unsigned int size;
10088688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
10098688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
1010230189d9SNélio Laranjeiro 
10118688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
1012230189d9SNélio Laranjeiro 	/*
1013230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
1014230189d9SNélio Laranjeiro 	 * count as 2.
1015230189d9SNélio Laranjeiro 	 */
10166b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
10176b30a6a8SShachar Beiser 					     MLX5_WQE_DS(size));
1018230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
10196b30a6a8SShachar Beiser 	inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG);
10208688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1021230189d9SNélio Laranjeiro }
1022230189d9SNélio Laranjeiro 
1023230189d9SNélio Laranjeiro /**
1024230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1025230189d9SNélio Laranjeiro  *
1026230189d9SNélio Laranjeiro  * @param dpdk_txq
1027230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1028230189d9SNélio Laranjeiro  * @param[in] pkts
1029230189d9SNélio Laranjeiro  *   Packets to transmit.
1030230189d9SNélio Laranjeiro  * @param pkts_n
1031230189d9SNélio Laranjeiro  *   Number of packets in array.
1032230189d9SNélio Laranjeiro  *
1033230189d9SNélio Laranjeiro  * @return
1034230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1035230189d9SNélio Laranjeiro  */
1036230189d9SNélio Laranjeiro uint16_t
1037230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1038230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1039230189d9SNélio Laranjeiro {
1040991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
1041230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
10428c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
10438c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1044c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1045a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
10468c819a69SYongseok Koh 	uint16_t max_elts;
1047f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1048230189d9SNélio Laranjeiro 	unsigned int comp;
10490e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1050230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1051230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1052230189d9SNélio Laranjeiro 	};
1053f04f1d51SNélio Laranjeiro 	/*
1054f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1055f04f1d51SNélio Laranjeiro 	 * code.
1056f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1057f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1058f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1059f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1060f04f1d51SNélio Laranjeiro 	 */
1061f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1062f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1063f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1064f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1065230189d9SNélio Laranjeiro 
1066c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1067c3d62cc9SAdrien Mazarguil 		return 0;
1068230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1069fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1070fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1071230189d9SNélio Laranjeiro 	/* Start processing. */
10726cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
10738c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
1074c3d62cc9SAdrien Mazarguil 	do {
1075a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1076230189d9SNélio Laranjeiro 		uintptr_t addr;
1077230189d9SNélio Laranjeiro 		uint32_t length;
1078a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
1079230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
1080230189d9SNélio Laranjeiro 
1081c3d62cc9SAdrien Mazarguil 		/*
1082c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1083c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1084c3d62cc9SAdrien Mazarguil 		 */
1085a5bf6af9SAdrien Mazarguil 		assert(segs_n);
10868c819a69SYongseok Koh 		if (max_elts < segs_n)
1087c3d62cc9SAdrien Mazarguil 			break;
1088a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
108924c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
109024c14430SShahaf Shuler 			txq->stats.oerrors++;
1091a5bf6af9SAdrien Mazarguil 			break;
109224c14430SShahaf Shuler 		}
10938c819a69SYongseok Koh 		max_elts -= segs_n;
1094c3d62cc9SAdrien Mazarguil 		--pkts_n;
1095f04f1d51SNélio Laranjeiro 		/*
1096f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1097f04f1d51SNélio Laranjeiro 		 * iteration.
1098f04f1d51SNélio Laranjeiro 		 */
1099f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
1100230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
1101230189d9SNélio Laranjeiro 		if (buf->ol_flags &
1102230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
1103230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
1104a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1105a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1106230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1107230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1108230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1109a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
11108688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1111230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1112230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1113230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1114a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1115230189d9SNélio Laranjeiro 			    (length > inline_room) ||
11168688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1117230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11180e8679fcSNélio Laranjeiro 				inline_room =
11190e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1120230189d9SNélio Laranjeiro 			}
1121230189d9SNélio Laranjeiro 		}
1122230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1123a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1124a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1125f04f1d51SNélio Laranjeiro 				/*
1126f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1127f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1128f04f1d51SNélio Laranjeiro 				 * such resources.
1129f04f1d51SNélio Laranjeiro 				 */
1130f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1131f04f1d51SNélio Laranjeiro 					break;
1132f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1133230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
11348688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1135230189d9SNélio Laranjeiro 			} else {
1136f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1137f04f1d51SNélio Laranjeiro 					break;
1138f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1139230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
11408688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1141230189d9SNélio Laranjeiro 			}
1142230189d9SNélio Laranjeiro 		}
1143a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1144a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1145230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
11460e8679fcSNélio Laranjeiro 			assert(inline_room ==
11470e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1148a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1149a5bf6af9SAdrien Mazarguil 			length = 0;
1150a5bf6af9SAdrien Mazarguil #endif
1151a5bf6af9SAdrien Mazarguil 			do {
1152230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1153230189d9SNélio Laranjeiro 
1154a5bf6af9SAdrien Mazarguil 				assert(buf);
11558c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1156230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1157a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1158230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
11596b30a6a8SShachar Beiser 					.byte_count =
11606b30a6a8SShachar Beiser 					       rte_cpu_to_be_32(DATA_LEN(buf)),
11616cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
11626b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
1163230189d9SNélio Laranjeiro 				};
1164a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1165a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1166a5bf6af9SAdrien Mazarguil #endif
1167a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1168230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1169a5bf6af9SAdrien Mazarguil 				++j;
1170a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1171a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1172230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1173230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1174230189d9SNélio Laranjeiro 		} else {
1175230189d9SNélio Laranjeiro 			unsigned int max;
1176230189d9SNélio Laranjeiro 
1177230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1178230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1179a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1180a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
11818c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1182230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1183fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1184fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1185fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1186230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1187230189d9SNélio Laranjeiro 			if (length > max) {
1188230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1189230189d9SNélio Laranjeiro 					   (void *)addr,
1190230189d9SNélio Laranjeiro 					   max);
1191fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1192230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1193230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1194230189d9SNélio Laranjeiro 					   length - max);
1195230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1196230189d9SNélio Laranjeiro 			} else {
1197230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1198230189d9SNélio Laranjeiro 					   (void *)addr,
1199230189d9SNélio Laranjeiro 					   length);
120016c64768SYongseok Koh 
120116c64768SYongseok Koh 				if (length == max)
120216c64768SYongseok Koh 					mpw.data.raw =
120316c64768SYongseok Koh 						(volatile void *)txq->wqes;
120416c64768SYongseok Koh 				else
1205230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1206230189d9SNélio Laranjeiro 			}
1207230189d9SNélio Laranjeiro 			++mpw.pkts_n;
120876bf1574SYongseok Koh 			mpw.total_len += length;
1209a5bf6af9SAdrien Mazarguil 			++j;
1210230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1211230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
12120e8679fcSNélio Laranjeiro 				inline_room =
12130e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1214230189d9SNélio Laranjeiro 			} else {
1215230189d9SNélio Laranjeiro 				inline_room -= length;
1216230189d9SNélio Laranjeiro 			}
1217230189d9SNélio Laranjeiro 		}
1218230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1219230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1220230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1221230189d9SNélio Laranjeiro #endif
1222c3d62cc9SAdrien Mazarguil 		++i;
1223c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1224230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1225230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1226230189d9SNélio Laranjeiro 		return 0;
1227230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1228a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1229a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1230230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
12318688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1232230189d9SNélio Laranjeiro 
1233230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
12346b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
1235230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
12368688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1237230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1238230189d9SNélio Laranjeiro 	} else {
1239230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1240230189d9SNélio Laranjeiro 	}
1241230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1242230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1243230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1244230189d9SNélio Laranjeiro #endif
1245230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1246230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1247230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1248230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1249230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
125030807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1251230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1252230189d9SNélio Laranjeiro 	return i;
1253230189d9SNélio Laranjeiro }
1254230189d9SNélio Laranjeiro 
1255230189d9SNélio Laranjeiro /**
12566ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
12576ce84bd8SYongseok Koh  *
12586ce84bd8SYongseok Koh  * @param txq
12596ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12606ce84bd8SYongseok Koh  * @param mpw
12616ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12626ce84bd8SYongseok Koh  * @param length
12636ce84bd8SYongseok Koh  *   Packet length.
12646ce84bd8SYongseok Koh  */
12656ce84bd8SYongseok Koh static inline void
1266991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding)
12676ce84bd8SYongseok Koh {
12686ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
12696ce84bd8SYongseok Koh 
12706ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
12716ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
12726ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
12736ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
12746b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] =
12756b30a6a8SShachar Beiser 		rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
12766ce84bd8SYongseok Koh 				 (txq->wqe_ci << 8) |
12776ce84bd8SYongseok Koh 				 MLX5_OPCODE_ENHANCED_MPSW);
12786ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
12796ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
12806ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
12816ce84bd8SYongseok Koh 	if (unlikely(padding)) {
12826ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
12836ce84bd8SYongseok Koh 
12846ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
12856b30a6a8SShachar Beiser 		*(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG);
12866ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
12876b30a6a8SShachar Beiser 			rte_cpu_to_be_32(MLX5_INLINE_SEG);
12886ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
12896ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
12906ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
12916ce84bd8SYongseok Koh 	} else {
12926ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
12936ce84bd8SYongseok Koh 	}
12946ce84bd8SYongseok Koh }
12956ce84bd8SYongseok Koh 
12966ce84bd8SYongseok Koh /**
12976ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
12986ce84bd8SYongseok Koh  *
12996ce84bd8SYongseok Koh  * @param txq
13006ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
13016ce84bd8SYongseok Koh  * @param mpw
13026ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
13036ce84bd8SYongseok Koh  *
13046ce84bd8SYongseok Koh  * @return
13056ce84bd8SYongseok Koh  *   Number of consumed WQEs.
13066ce84bd8SYongseok Koh  */
13076ce84bd8SYongseok Koh static inline uint16_t
1308991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
13096ce84bd8SYongseok Koh {
13106ce84bd8SYongseok Koh 	uint16_t ret;
13116ce84bd8SYongseok Koh 
13126ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
13136ce84bd8SYongseok Koh 	 * count as 2.
13146ce84bd8SYongseok Koh 	 */
13156b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
13166b30a6a8SShachar Beiser 					     MLX5_WQE_DS(mpw->total_len));
13176ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
13186ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
13196ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
13206ce84bd8SYongseok Koh 	return ret;
13216ce84bd8SYongseok Koh }
13226ce84bd8SYongseok Koh 
13236ce84bd8SYongseok Koh /**
13246ce84bd8SYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
13256ce84bd8SYongseok Koh  *
13266ce84bd8SYongseok Koh  * @param dpdk_txq
13276ce84bd8SYongseok Koh  *   Generic pointer to TX queue structure.
13286ce84bd8SYongseok Koh  * @param[in] pkts
13296ce84bd8SYongseok Koh  *   Packets to transmit.
13306ce84bd8SYongseok Koh  * @param pkts_n
13316ce84bd8SYongseok Koh  *   Number of packets in array.
13326ce84bd8SYongseok Koh  *
13336ce84bd8SYongseok Koh  * @return
13346ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
13356ce84bd8SYongseok Koh  */
13366ce84bd8SYongseok Koh uint16_t
13376ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
13386ce84bd8SYongseok Koh {
1339991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
13406ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
13418c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
13428c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
13436ce84bd8SYongseok Koh 	unsigned int i = 0;
13446ce84bd8SYongseok Koh 	unsigned int j = 0;
13458c819a69SYongseok Koh 	uint16_t max_elts;
13466ce84bd8SYongseok Koh 	uint16_t max_wqe;
13476ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
13486ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
13496ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
13506ce84bd8SYongseok Koh 	uint32_t inl_hdr;
13516ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
13526ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
13536ce84bd8SYongseok Koh 	};
13546ce84bd8SYongseok Koh 
13556ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
13566ce84bd8SYongseok Koh 		return 0;
13576ce84bd8SYongseok Koh 	/* Start processing. */
13586cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
13596ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
13606ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
13616ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
13626ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
13636ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
13646ce84bd8SYongseok Koh 		return 0;
13656ce84bd8SYongseok Koh 	do {
13666ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
13676ce84bd8SYongseok Koh 		uintptr_t addr;
13686ce84bd8SYongseok Koh 		uint64_t naddr;
13696ce84bd8SYongseok Koh 		unsigned int n;
13706ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
13716ce84bd8SYongseok Koh 		uint32_t length;
13726ce84bd8SYongseok Koh 		unsigned int segs_n = buf->nb_segs;
13736ce84bd8SYongseok Koh 		uint32_t cs_flags = 0;
13746ce84bd8SYongseok Koh 
13756ce84bd8SYongseok Koh 		/*
13766ce84bd8SYongseok Koh 		 * Make sure there is enough room to store this packet and
13776ce84bd8SYongseok Koh 		 * that one ring entry remains unused.
13786ce84bd8SYongseok Koh 		 */
13796ce84bd8SYongseok Koh 		assert(segs_n);
13808c819a69SYongseok Koh 		if (max_elts - j < segs_n)
13816ce84bd8SYongseok Koh 			break;
13826ce84bd8SYongseok Koh 		/* Do not bother with large packets MPW cannot handle. */
138324c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
138424c14430SShahaf Shuler 			txq->stats.oerrors++;
13856ce84bd8SYongseok Koh 			break;
138624c14430SShahaf Shuler 		}
13876ce84bd8SYongseok Koh 		/* Should we enable HW CKSUM offload. */
13886ce84bd8SYongseok Koh 		if (buf->ol_flags &
13896ce84bd8SYongseok Koh 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
13906ce84bd8SYongseok Koh 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
13916ce84bd8SYongseok Koh 		/* Retrieve packet information. */
13926ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
13936ce84bd8SYongseok Koh 		/* Start new session if:
13946ce84bd8SYongseok Koh 		 * - multi-segment packet
13956ce84bd8SYongseok Koh 		 * - no space left even for a dseg
13966ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
13976ce84bd8SYongseok Koh 		 * - cs_flag differs
13986ce84bd8SYongseok Koh 		 * It can't be MLX5_MPW_STATE_OPENED as always have a single
13996ce84bd8SYongseok Koh 		 * segmented packet.
14006ce84bd8SYongseok Koh 		 */
14016ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
14026ce84bd8SYongseok Koh 			if ((segs_n != 1) ||
14036ce84bd8SYongseok Koh 			    (inl_pad + sizeof(struct mlx5_wqe_data_seg) >
14046ce84bd8SYongseok Koh 			      mpw_room) ||
14056ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
14066ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
14076ce84bd8SYongseok Koh 			      mpw_room) ||
14086ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
14096ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
14106ce84bd8SYongseok Koh 		}
14116ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
14126ce84bd8SYongseok Koh 			if (unlikely(segs_n != 1)) {
14136ce84bd8SYongseok Koh 				/* Fall back to legacy MPW.
14146ce84bd8SYongseok Koh 				 * A MPW session consumes 2 WQEs at most to
14156ce84bd8SYongseok Koh 				 * include MLX5_MPW_DSEG_MAX pointers.
14166ce84bd8SYongseok Koh 				 */
14176ce84bd8SYongseok Koh 				if (unlikely(max_wqe < 2))
14186ce84bd8SYongseok Koh 					break;
14196ce84bd8SYongseok Koh 				mlx5_mpw_new(txq, &mpw, length);
14206ce84bd8SYongseok Koh 			} else {
14216ce84bd8SYongseok Koh 				/* In Enhanced MPW, inline as much as the budget
14226ce84bd8SYongseok Koh 				 * is allowed. The remaining space is to be
14236ce84bd8SYongseok Koh 				 * filled with dsegs. If the title WQEBB isn't
14246ce84bd8SYongseok Koh 				 * padded, it will have 2 dsegs there.
14256ce84bd8SYongseok Koh 				 */
14266ce84bd8SYongseok Koh 				mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
14276ce84bd8SYongseok Koh 					    (max_inline ? max_inline :
14286ce84bd8SYongseok Koh 					     pkts_n * MLX5_WQE_DWORD_SIZE) +
14296ce84bd8SYongseok Koh 					    MLX5_WQE_SIZE);
14306ce84bd8SYongseok Koh 				if (unlikely(max_wqe * MLX5_WQE_SIZE <
14316ce84bd8SYongseok Koh 					      mpw_room))
14326ce84bd8SYongseok Koh 					break;
14336ce84bd8SYongseok Koh 				/* Don't pad the title WQEBB to not waste WQ. */
14346ce84bd8SYongseok Koh 				mlx5_empw_new(txq, &mpw, 0);
14356ce84bd8SYongseok Koh 				mpw_room -= mpw.total_len;
14366ce84bd8SYongseok Koh 				inl_pad = 0;
14376ce84bd8SYongseok Koh 				do_inline =
14386ce84bd8SYongseok Koh 					length <= txq->inline_max_packet_sz &&
14396ce84bd8SYongseok Koh 					sizeof(inl_hdr) + length <= mpw_room &&
14406ce84bd8SYongseok Koh 					!txq->mpw_hdr_dseg;
14416ce84bd8SYongseok Koh 			}
14426ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
14436ce84bd8SYongseok Koh 		} else {
14446ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
14456ce84bd8SYongseok Koh 			 * Inlininig is possible when:
14466ce84bd8SYongseok Koh 			 * - length is less than configured value
14476ce84bd8SYongseok Koh 			 * - length fits for remaining space
14486ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
14496ce84bd8SYongseok Koh 			 */
14506ce84bd8SYongseok Koh 			do_inline =
14516ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
14526ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
14536ce84bd8SYongseok Koh 				 mpw_room &&
14546ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
14556ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
14566ce84bd8SYongseok Koh 		}
14576ce84bd8SYongseok Koh 		/* Multi-segment packets must be alone in their MPW. */
14586ce84bd8SYongseok Koh 		assert((segs_n == 1) || (mpw.pkts_n == 0));
14596ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) {
14606ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14616ce84bd8SYongseok Koh 			length = 0;
14626ce84bd8SYongseok Koh #endif
14636ce84bd8SYongseok Koh 			do {
14646ce84bd8SYongseok Koh 				volatile struct mlx5_wqe_data_seg *dseg;
14656ce84bd8SYongseok Koh 
14666ce84bd8SYongseok Koh 				assert(buf);
14678c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
14686ce84bd8SYongseok Koh 				dseg = mpw.data.dseg[mpw.pkts_n];
14696ce84bd8SYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
14706ce84bd8SYongseok Koh 				*dseg = (struct mlx5_wqe_data_seg){
14716b30a6a8SShachar Beiser 					.byte_count = rte_cpu_to_be_32(
14726b30a6a8SShachar Beiser 								DATA_LEN(buf)),
14736cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
14746b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
14756ce84bd8SYongseok Koh 				};
14766ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
14776ce84bd8SYongseok Koh 				length += DATA_LEN(buf);
14786ce84bd8SYongseok Koh #endif
14796ce84bd8SYongseok Koh 				buf = buf->next;
14806ce84bd8SYongseok Koh 				++j;
14816ce84bd8SYongseok Koh 				++mpw.pkts_n;
14826ce84bd8SYongseok Koh 			} while (--segs_n);
14836ce84bd8SYongseok Koh 			/* A multi-segmented packet takes one MPW session.
14846ce84bd8SYongseok Koh 			 * TODO: Pack more multi-segmented packets if possible.
14856ce84bd8SYongseok Koh 			 */
14866ce84bd8SYongseok Koh 			mlx5_mpw_close(txq, &mpw);
14876ce84bd8SYongseok Koh 			if (mpw.pkts_n < 3)
14886ce84bd8SYongseok Koh 				max_wqe--;
14896ce84bd8SYongseok Koh 			else
14906ce84bd8SYongseok Koh 				max_wqe -= 2;
14916ce84bd8SYongseok Koh 		} else if (do_inline) {
14926ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
14936ce84bd8SYongseok Koh 			unsigned int max;
14946ce84bd8SYongseok Koh 
14956ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14966ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14976b30a6a8SShachar Beiser 			inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG);
14986ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14996ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
15006ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
15016ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
15026ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
15036ce84bd8SYongseok Koh 			/* Copy inline header. */
15046ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
15056ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
15066ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
15076ce84bd8SYongseok Koh 					  &inl_hdr,
15086ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
15096ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
15106ce84bd8SYongseok Koh 					  max);
15116ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
15126ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
15136ce84bd8SYongseok Koh 			/* Copy packet data. */
15146ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
15156ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
15166ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
15176ce84bd8SYongseok Koh 					  (void *)addr,
15186ce84bd8SYongseok Koh 					  length,
15196ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
15206ce84bd8SYongseok Koh 					  max);
15216ce84bd8SYongseok Koh 			++mpw.pkts_n;
15226ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
15236ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
15246ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
15256ce84bd8SYongseok Koh 			 */
15266ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
15276ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
15286ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
15296ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
15306ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
15316ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
15326ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
15336ce84bd8SYongseok Koh 		} else {
15346ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
15356ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
15366ce84bd8SYongseok Koh 
15376ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
15386ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
15396ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
15406ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
15416ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
15426ce84bd8SYongseok Koh 						+ inl_pad)))
15436ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
15446ce84bd8SYongseok Koh 			else
15456ce84bd8SYongseok Koh 				dseg = (volatile void *)
15466ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
15476ce84bd8SYongseok Koh 					 inl_pad);
15488c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
15496ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
15506ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
15516ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
15526ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
15536b30a6a8SShachar Beiser 			naddr = rte_cpu_to_be_64(addr);
15546ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
15556b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
15566cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
15576ce84bd8SYongseok Koh 				naddr,
15586ce84bd8SYongseok Koh 				naddr >> 32,
15596ce84bd8SYongseok Koh 			};
15606ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
15616ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
15626ce84bd8SYongseok Koh 			++j;
15636ce84bd8SYongseok Koh 			++mpw.pkts_n;
15646ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
15656ce84bd8SYongseok Koh 			inl_pad = 0;
15666ce84bd8SYongseok Koh 		}
15676ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15686ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
15696ce84bd8SYongseok Koh 		txq->stats.obytes += length;
15706ce84bd8SYongseok Koh #endif
15716ce84bd8SYongseok Koh 		++i;
15726ce84bd8SYongseok Koh 	} while (i < pkts_n);
15736ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
15746ce84bd8SYongseok Koh 	if (unlikely(i == 0))
15756ce84bd8SYongseok Koh 		return 0;
15766ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
15776ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
15786ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
15796ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
15806ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
15816ce84bd8SYongseok Koh 
15826ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
15836b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
15846ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
15856ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
15866ce84bd8SYongseok Koh 		txq->elts_comp = 0;
15876ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
15886ce84bd8SYongseok Koh 		txq->cq_pi++;
15896ce84bd8SYongseok Koh 	} else {
15906ce84bd8SYongseok Koh 		txq->elts_comp += j;
15916ce84bd8SYongseok Koh 	}
15926ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15936ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
15946ce84bd8SYongseok Koh 	txq->stats.opackets += i;
15956ce84bd8SYongseok Koh #endif
15966ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
15976ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
15986ce84bd8SYongseok Koh 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
15996ce84bd8SYongseok Koh 		mlx5_mpw_close(txq, &mpw);
16006ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
16016ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
16026ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
16036ce84bd8SYongseok Koh 	return i;
16046ce84bd8SYongseok Koh }
16056ce84bd8SYongseok Koh 
16066ce84bd8SYongseok Koh /**
160767fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
160867fa62bcSAdrien Mazarguil  *
16096218063bSNélio Laranjeiro  * @param[in] cqe
16106218063bSNélio Laranjeiro  *   Pointer to CQE.
161167fa62bcSAdrien Mazarguil  *
161278a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
161378a38edfSJianfeng Tan  *
161467fa62bcSAdrien Mazarguil  * @return
161567fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
161667fa62bcSAdrien Mazarguil  */
161767fa62bcSAdrien Mazarguil static inline uint32_t
161897267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
161967fa62bcSAdrien Mazarguil {
1620ea16068cSYongseok Koh 	uint8_t idx;
1621ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
1622ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
162367fa62bcSAdrien Mazarguil 
1624ea16068cSYongseok Koh 	/*
1625ea16068cSYongseok Koh 	 * The index to the array should have:
1626ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
1627ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
1628ea16068cSYongseok Koh 	 * bit[5] = ip_frag
1629ea16068cSYongseok Koh 	 * bit[6] = tunneled
1630ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
1631ea16068cSYongseok Koh 	 */
1632ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
1633ea16068cSYongseok Koh 	return mlx5_ptype_table[idx];
163467fa62bcSAdrien Mazarguil }
163567fa62bcSAdrien Mazarguil 
163667fa62bcSAdrien Mazarguil /**
163799c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
163899c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
163999c12dccSNélio Laranjeiro  * been processed.
164099c12dccSNélio Laranjeiro  *
164199c12dccSNélio Laranjeiro  * @param rxq
164299c12dccSNélio Laranjeiro  *   Pointer to RX queue.
164399c12dccSNélio Laranjeiro  * @param cqe
164499c12dccSNélio Laranjeiro  *   CQE to process.
1645ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1646ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
164799c12dccSNélio Laranjeiro  *
164899c12dccSNélio Laranjeiro  * @return
164999c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
165099c12dccSNélio Laranjeiro  *   with error.
165199c12dccSNélio Laranjeiro  */
165299c12dccSNélio Laranjeiro static inline int
165378142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
1654ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
165599c12dccSNélio Laranjeiro {
165699c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
165799c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
165899c12dccSNélio Laranjeiro 	int len = 0;
1659d2e842d0SYongseok Koh 	uint16_t idx, end;
166099c12dccSNélio Laranjeiro 
166199c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
166299c12dccSNélio Laranjeiro 	if (zip->ai) {
166399c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
166499c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
16654aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
166699c12dccSNélio Laranjeiro 
16676b30a6a8SShachar Beiser 		len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
16686b30a6a8SShachar Beiser 		*rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result);
166999c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1670d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1671d2e842d0SYongseok Koh 			idx = zip->ca;
1672d2e842d0SYongseok Koh 			end = zip->na;
1673d2e842d0SYongseok Koh 			while (idx != end) {
1674d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1675d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1676d2e842d0SYongseok Koh 				++idx;
1677d2e842d0SYongseok Koh 			}
167899c12dccSNélio Laranjeiro 			/*
167999c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
168099c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
168199c12dccSNélio Laranjeiro 			 * ring for software use.
168299c12dccSNélio Laranjeiro 			 */
168399c12dccSNélio Laranjeiro 			zip->ca = zip->na;
168499c12dccSNélio Laranjeiro 			zip->na += 8;
168599c12dccSNélio Laranjeiro 		}
168699c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1687d2e842d0SYongseok Koh 			/* Invalidate the rest */
1688d2e842d0SYongseok Koh 			idx = zip->ca;
1689d2e842d0SYongseok Koh 			end = zip->cq_ci;
169099c12dccSNélio Laranjeiro 
169199c12dccSNélio Laranjeiro 			while (idx != end) {
169297267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
169399c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
169499c12dccSNélio Laranjeiro 				++idx;
169599c12dccSNélio Laranjeiro 			}
169699c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
169799c12dccSNélio Laranjeiro 			zip->ai = 0;
169899c12dccSNélio Laranjeiro 		}
169999c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
170099c12dccSNélio Laranjeiro 	} else {
170199c12dccSNélio Laranjeiro 		int ret;
170299c12dccSNélio Laranjeiro 		int8_t op_own;
170399c12dccSNélio Laranjeiro 
170497267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
170599c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
170699c12dccSNélio Laranjeiro 			return 0;
170799c12dccSNélio Laranjeiro 		++rxq->cq_ci;
170899c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
170999c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
171099c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
171199c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
171299c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
17134aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
171499c12dccSNélio Laranjeiro 
171599c12dccSNélio Laranjeiro 			/* Fix endianness. */
17166b30a6a8SShachar Beiser 			zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
171799c12dccSNélio Laranjeiro 			/*
171899c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
171999c12dccSNélio Laranjeiro 			 * check_cqe64().
172099c12dccSNélio Laranjeiro 			 *
172199c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
172299c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
172399c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
172499c12dccSNélio Laranjeiro 			 */
1725d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
172699c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
172799c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
172899c12dccSNélio Laranjeiro 			--rxq->cq_ci;
172999c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
173099c12dccSNélio Laranjeiro 			/* Get packet size to return. */
17316b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
17326b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result);
173399c12dccSNélio Laranjeiro 			zip->ai = 1;
1734d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1735d2e842d0SYongseok Koh 			idx = zip->ca;
1736d2e842d0SYongseok Koh 			end = zip->cq_ci;
1737d2e842d0SYongseok Koh 			while (idx != end) {
1738d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1739d2e842d0SYongseok Koh 				++idx;
1740d2e842d0SYongseok Koh 			}
174199c12dccSNélio Laranjeiro 		} else {
17426b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32(cqe->byte_cnt);
17436b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res);
174499c12dccSNélio Laranjeiro 		}
174599c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
174699c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
174799c12dccSNélio Laranjeiro 			return -1;
174899c12dccSNélio Laranjeiro 	}
174999c12dccSNélio Laranjeiro 	return len;
175099c12dccSNélio Laranjeiro }
175199c12dccSNélio Laranjeiro 
175299c12dccSNélio Laranjeiro /**
175367fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
175467fa62bcSAdrien Mazarguil  *
175567fa62bcSAdrien Mazarguil  * @param[in] rxq
175667fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
17576218063bSNélio Laranjeiro  * @param[in] cqe
17586218063bSNélio Laranjeiro  *   Pointer to CQE.
175967fa62bcSAdrien Mazarguil  *
176067fa62bcSAdrien Mazarguil  * @return
176167fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
176267fa62bcSAdrien Mazarguil  */
176367fa62bcSAdrien Mazarguil static inline uint32_t
176478142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe)
176567fa62bcSAdrien Mazarguil {
176667fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
17676b30a6a8SShachar Beiser 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
176867fa62bcSAdrien Mazarguil 
17690603df73SNélio Laranjeiro 	ol_flags =
17700603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17710603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
17720603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
17730603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17740603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
177583e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
177697267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
177767fa62bcSAdrien Mazarguil 		ol_flags |=
17780603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17790603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
178083e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
17810603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17820603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
178383e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
178467fa62bcSAdrien Mazarguil 	return ol_flags;
178567fa62bcSAdrien Mazarguil }
178667fa62bcSAdrien Mazarguil 
178767fa62bcSAdrien Mazarguil /**
17882e22920bSAdrien Mazarguil  * DPDK callback for RX.
17892e22920bSAdrien Mazarguil  *
17902e22920bSAdrien Mazarguil  * @param dpdk_rxq
17912e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
17922e22920bSAdrien Mazarguil  * @param[out] pkts
17932e22920bSAdrien Mazarguil  *   Array to store received packets.
17942e22920bSAdrien Mazarguil  * @param pkts_n
17952e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
17962e22920bSAdrien Mazarguil  *
17972e22920bSAdrien Mazarguil  * @return
17982e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
17992e22920bSAdrien Mazarguil  */
18002e22920bSAdrien Mazarguil uint16_t
18012e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
18022e22920bSAdrien Mazarguil {
180378142aacSNélio Laranjeiro 	struct mlx5_rxq_data *rxq = dpdk_rxq;
1804b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1805e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
18069964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
18079964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
18089964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
180997267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
181097267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
18119964b965SNélio Laranjeiro 	unsigned int i = 0;
18129964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
18134e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
18142e22920bSAdrien Mazarguil 
18159964b965SNélio Laranjeiro 	while (pkts_n) {
18169964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
18179964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
18189964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1819ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
18209964b965SNélio Laranjeiro 
18219964b965SNélio Laranjeiro 		if (pkt)
18229964b965SNélio Laranjeiro 			NEXT(seg) = rep;
18239964b965SNélio Laranjeiro 		seg = rep;
18249964b965SNélio Laranjeiro 		rte_prefetch0(seg);
18256218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
18269964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1827fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
18282e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
182915a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
183015a756b6SSagi Grimberg 			if (!pkt) {
183115a756b6SSagi Grimberg 				/*
183215a756b6SSagi Grimberg 				 * no buffers before we even started,
183315a756b6SSagi Grimberg 				 * bail out silently.
183415a756b6SSagi Grimberg 				 */
183515a756b6SSagi Grimberg 				break;
183615a756b6SSagi Grimberg 			}
1837a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1838a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1839fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
18408f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
18418f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
18421f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1843fe5fe382SNélio Laranjeiro 				pkt = rep;
18449964b965SNélio Laranjeiro 			}
18456218063bSNélio Laranjeiro 			break;
18462e22920bSAdrien Mazarguil 		}
18479964b965SNélio Laranjeiro 		if (!pkt) {
184897267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1849ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1850ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1851ecf60761SNélio Laranjeiro 			if (!len) {
18521f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
18536218063bSNélio Laranjeiro 				break;
18546218063bSNélio Laranjeiro 			}
185599c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
185699c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
18571f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
185899c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
185999c12dccSNélio Laranjeiro 				goto skip;
186099c12dccSNélio Laranjeiro 			}
18619964b965SNélio Laranjeiro 			pkt = seg;
18629964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
18639964b965SNélio Laranjeiro 			/* Update packet information. */
186448dfc20fSYongseok Koh 			pkt->packet_type = rxq_cq_to_pkt_type(cqe);
18650ac64846SMaxime Leroy 			pkt->ol_flags = 0;
186636ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1867ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1868ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1869ecf60761SNélio Laranjeiro 			}
1870c604f619SNélio Laranjeiro 			if (rxq->mark &&
1871c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1872b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
1873b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
18746b30a6a8SShachar Beiser 				    rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
1875b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
1876b268a3eeSNélio Laranjeiro 
1877b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
1878ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
1879b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
1880b268a3eeSNélio Laranjeiro 				}
1881ea3bc3b1SNélio Laranjeiro 			}
188248dfc20fSYongseok Koh 			if (rxq->csum | rxq->csum_l2tun)
18836703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
18846703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
18856703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
18866b30a6a8SShachar Beiser 			     rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
18876218063bSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_VLAN_PKT |
1888b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
18896b30a6a8SShachar Beiser 				pkt->vlan_tci =
18906b30a6a8SShachar Beiser 					rte_be_to_cpu_16(cqe->vlan_info);
1891f3db9489SYaacov Hazan 			}
189278c7406bSRaslan Darawsheh 			if (rxq->hw_timestamp) {
189378c7406bSRaslan Darawsheh 				pkt->timestamp =
189478c7406bSRaslan Darawsheh 					rte_be_to_cpu_64(cqe->timestamp);
189578c7406bSRaslan Darawsheh 				pkt->ol_flags |= PKT_RX_TIMESTAMP;
189678c7406bSRaslan Darawsheh 			}
18976218063bSNélio Laranjeiro 			if (rxq->crc_present)
18986218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
18996218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
19009964b965SNélio Laranjeiro 		}
19019964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
19029964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
19039964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
19049964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
19059964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
19069964b965SNélio Laranjeiro 		/*
19079964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
19089964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
19099964b965SNélio Laranjeiro 		 * changes.
19109964b965SNélio Laranjeiro 		 */
19116b30a6a8SShachar Beiser 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
19129964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
19139964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
19149964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
19159964b965SNélio Laranjeiro 			++rq_ci;
19169964b965SNélio Laranjeiro 			continue;
19179964b965SNélio Laranjeiro 		}
19189964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
191987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
192087011737SAdrien Mazarguil 		/* Increment bytes counter. */
19219964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
192287011737SAdrien Mazarguil #endif
19236218063bSNélio Laranjeiro 		/* Return packet. */
19246218063bSNélio Laranjeiro 		*(pkts++) = pkt;
19259964b965SNélio Laranjeiro 		pkt = NULL;
19269964b965SNélio Laranjeiro 		--pkts_n;
19279964b965SNélio Laranjeiro 		++i;
192899c12dccSNélio Laranjeiro skip:
19299964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
19309964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
19316218063bSNélio Laranjeiro 		++rq_ci;
19329964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
19332e22920bSAdrien Mazarguil 	}
19349964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
19352e22920bSAdrien Mazarguil 		return 0;
19366218063bSNélio Laranjeiro 	/* Update the consumer index. */
19379964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
19389afa3f74SYongseok Koh 	rte_io_wmb();
19396b30a6a8SShachar Beiser 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
19409afa3f74SYongseok Koh 	rte_io_wmb();
19416b30a6a8SShachar Beiser 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
194287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
194387011737SAdrien Mazarguil 	/* Increment packets counter. */
19449964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
194587011737SAdrien Mazarguil #endif
19469964b965SNélio Laranjeiro 	return i;
19472e22920bSAdrien Mazarguil }
19482e22920bSAdrien Mazarguil 
19492e22920bSAdrien Mazarguil /**
19502e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
19512e22920bSAdrien Mazarguil  *
19522e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19532e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19542e22920bSAdrien Mazarguil  *
19552e22920bSAdrien Mazarguil  * @param dpdk_txq
19562e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
19572e22920bSAdrien Mazarguil  * @param[in] pkts
19582e22920bSAdrien Mazarguil  *   Packets to transmit.
19592e22920bSAdrien Mazarguil  * @param pkts_n
19602e22920bSAdrien Mazarguil  *   Number of packets in array.
19612e22920bSAdrien Mazarguil  *
19622e22920bSAdrien Mazarguil  * @return
19632e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
19642e22920bSAdrien Mazarguil  */
19652e22920bSAdrien Mazarguil uint16_t
19662e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19672e22920bSAdrien Mazarguil {
19682e22920bSAdrien Mazarguil 	(void)dpdk_txq;
19692e22920bSAdrien Mazarguil 	(void)pkts;
19702e22920bSAdrien Mazarguil 	(void)pkts_n;
19712e22920bSAdrien Mazarguil 	return 0;
19722e22920bSAdrien Mazarguil }
19732e22920bSAdrien Mazarguil 
19742e22920bSAdrien Mazarguil /**
19752e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
19762e22920bSAdrien Mazarguil  *
19772e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19782e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19792e22920bSAdrien Mazarguil  *
19802e22920bSAdrien Mazarguil  * @param dpdk_rxq
19812e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
19822e22920bSAdrien Mazarguil  * @param[out] pkts
19832e22920bSAdrien Mazarguil  *   Array to store received packets.
19842e22920bSAdrien Mazarguil  * @param pkts_n
19852e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
19862e22920bSAdrien Mazarguil  *
19872e22920bSAdrien Mazarguil  * @return
19882e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
19892e22920bSAdrien Mazarguil  */
19902e22920bSAdrien Mazarguil uint16_t
19912e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19922e22920bSAdrien Mazarguil {
19932e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
19942e22920bSAdrien Mazarguil 	(void)pkts;
19952e22920bSAdrien Mazarguil 	(void)pkts_n;
19962e22920bSAdrien Mazarguil 	return 0;
19972e22920bSAdrien Mazarguil }
19986cb559d6SYongseok Koh 
19996cb559d6SYongseok Koh /*
20006cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
20016cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
20026cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
20036cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
20046cb559d6SYongseok Koh  */
20056cb559d6SYongseok Koh 
20066cb559d6SYongseok Koh uint16_t __attribute__((weak))
20076cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
20086cb559d6SYongseok Koh {
20096cb559d6SYongseok Koh 	(void)dpdk_txq;
20106cb559d6SYongseok Koh 	(void)pkts;
20116cb559d6SYongseok Koh 	(void)pkts_n;
20126cb559d6SYongseok Koh 	return 0;
20136cb559d6SYongseok Koh }
20146cb559d6SYongseok Koh 
20156cb559d6SYongseok Koh uint16_t __attribute__((weak))
20166cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
20176cb559d6SYongseok Koh {
20186cb559d6SYongseok Koh 	(void)dpdk_txq;
20196cb559d6SYongseok Koh 	(void)pkts;
20206cb559d6SYongseok Koh 	(void)pkts_n;
20216cb559d6SYongseok Koh 	return 0;
20226cb559d6SYongseok Koh }
20236cb559d6SYongseok Koh 
20246cb559d6SYongseok Koh uint16_t __attribute__((weak))
20256cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
20266cb559d6SYongseok Koh {
20276cb559d6SYongseok Koh 	(void)dpdk_rxq;
20286cb559d6SYongseok Koh 	(void)pkts;
20296cb559d6SYongseok Koh 	(void)pkts_n;
20306cb559d6SYongseok Koh 	return 0;
20316cb559d6SYongseok Koh }
20326cb559d6SYongseok Koh 
20336cb559d6SYongseok Koh int __attribute__((weak))
20346cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv)
20356cb559d6SYongseok Koh {
20366cb559d6SYongseok Koh 	(void)priv;
20376cb559d6SYongseok Koh 	return -ENOTSUP;
20386cb559d6SYongseok Koh }
20396cb559d6SYongseok Koh 
20406cb559d6SYongseok Koh int __attribute__((weak))
20416cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv)
20426cb559d6SYongseok Koh {
20436cb559d6SYongseok Koh 	(void)priv;
20446cb559d6SYongseok Koh 	return -ENOTSUP;
20456cb559d6SYongseok Koh }
20466cb559d6SYongseok Koh 
20476cb559d6SYongseok Koh int __attribute__((weak))
204878142aacSNélio Laranjeiro rxq_check_vec_support(struct mlx5_rxq_data *rxq)
20496cb559d6SYongseok Koh {
20506cb559d6SYongseok Koh 	(void)rxq;
20516cb559d6SYongseok Koh 	return -ENOTSUP;
20526cb559d6SYongseok Koh }
20536cb559d6SYongseok Koh 
20546cb559d6SYongseok Koh int __attribute__((weak))
20556cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv)
20566cb559d6SYongseok Koh {
20576cb559d6SYongseok Koh 	(void)priv;
20586cb559d6SYongseok Koh 	return -ENOTSUP;
20596cb559d6SYongseok Koh }
2060