xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision dbccb4cddcd2f7cff7d6ddcf11f5aeedc6245ab3)
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 	 */
1003ca63b88SShahaf Shuler 	/* L2 */
1013ca63b88SShahaf 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 |
1686c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
169ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
170ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1716c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
172ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
173ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1746c897093SYongseok Koh 		     RTE_PTYPE_INNER_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 |
1776c897093SYongseok Koh 		     RTE_PTYPE_INNER_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 |
1816c897093SYongseok Koh 		     RTE_PTYPE_INNER_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 |
1846c897093SYongseok Koh 		     RTE_PTYPE_INNER_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 |
1876c897093SYongseok Koh 		     RTE_PTYPE_INNER_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 |
1906c897093SYongseok Koh 		     RTE_PTYPE_INNER_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;
347f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
348c305090bSAdrien Mazarguil 	unsigned int comp;
349ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
3506579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
35127a6b2d6SNélio Laranjeiro 	const unsigned int max_inline = txq->max_inline;
3522e22920bSAdrien Mazarguil 
3531d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
3541d88ba17SNélio Laranjeiro 		return 0;
3555e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
356c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
3571d88ba17SNélio Laranjeiro 	/* Start processing. */
3586cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
3598c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
3602eefbec5SYongseok Koh 	/* A CQE slot must always be available. */
3612eefbec5SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
362f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
363f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
364f04f1d51SNélio Laranjeiro 		return 0;
365c3d62cc9SAdrien Mazarguil 	do {
3663bbae1ebSNélio Laranjeiro 		struct rte_mbuf *buf = NULL;
3673bbae1ebSNélio Laranjeiro 		uint8_t *raw;
3683bbae1ebSNélio Laranjeiro 		volatile struct mlx5_wqe_v *wqe = NULL;
3699a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
370573f54afSNélio Laranjeiro 		uint32_t length;
3718688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
372ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
3736579c27cSNélio Laranjeiro 		uintptr_t addr;
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;
3774aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
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;
395f895536bSYongseok Koh 		sg = --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 *));
4204aa15eb1SNélio Laranjeiro 		cs_flags = txq_ol_cksum_to_cs(txq, buf);
421b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
4226579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
4236579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
4246b30a6a8SShachar Beiser 			uint32_t vlan = rte_cpu_to_be_32(0x81000000 |
4256b30a6a8SShachar Beiser 							 buf->vlan_tci);
4260d637a34SNélio Laranjeiro 			unsigned int len = 2 * ETHER_ADDR_LEN - 2;
4276579c27cSNélio Laranjeiro 
4280d637a34SNélio Laranjeiro 			addr += 2;
4290d637a34SNélio Laranjeiro 			length -= 2;
4300d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
4310d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
4320d637a34SNélio Laranjeiro 			/* Copy VLAN. */
4330d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
4340d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
4350d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
4360d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
4370d637a34SNélio Laranjeiro 			addr += len + 2;
4380d637a34SNélio Laranjeiro 			length -= (len + 2);
4390d637a34SNélio Laranjeiro 		} else {
4400d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
4410d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
4420d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
4430d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
4446579c27cSNélio Laranjeiro 		}
445d8292497SYongseok Koh 		raw += MLX5_WQE_DWORD_SIZE;
44636aa55eaSYongseok Koh 		tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG);
4473f13f8c2SShahaf Shuler 		if (tso) {
44836aa55eaSYongseok Koh 			uintptr_t end =
44936aa55eaSYongseok Koh 				(uintptr_t)(((uintptr_t)txq->wqes) +
45036aa55eaSYongseok Koh 					    (1 << txq->wqe_n) * MLX5_WQE_SIZE);
4513f13f8c2SShahaf Shuler 			unsigned int copy_b;
45236aa55eaSYongseok Koh 			uint8_t vlan_sz =
45336aa55eaSYongseok Koh 				(buf->ol_flags & PKT_TX_VLAN_PKT) ? 4 : 0;
454b247f346SShahaf Shuler 			const uint64_t is_tunneled =
45536aa55eaSYongseok Koh 				buf->ol_flags & (PKT_TX_TUNNEL_GRE |
456b247f346SShahaf Shuler 						 PKT_TX_TUNNEL_VXLAN);
4573f13f8c2SShahaf Shuler 
4583f13f8c2SShahaf Shuler 			tso_header_sz = buf->l2_len + vlan_sz +
4593f13f8c2SShahaf Shuler 					buf->l3_len + buf->l4_len;
46083daf156SShahaf Shuler 			tso_segsz = buf->tso_segsz;
46196fc8d65SShahaf Shuler 			if (unlikely(tso_segsz == 0)) {
46296fc8d65SShahaf Shuler 				txq->stats.oerrors++;
46396fc8d65SShahaf Shuler 				break;
46496fc8d65SShahaf Shuler 			}
465b247f346SShahaf Shuler 			if (is_tunneled	&& txq->tunnel_en) {
466b247f346SShahaf Shuler 				tso_header_sz += buf->outer_l2_len +
467b247f346SShahaf Shuler 						 buf->outer_l3_len;
4682a6c96beSShahaf Shuler 				cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
4692a6c96beSShahaf Shuler 			} else {
4702a6c96beSShahaf Shuler 				cs_flags |= MLX5_ETH_WQE_L4_CSUM;
471b247f346SShahaf Shuler 			}
47236aa55eaSYongseok Koh 			if (unlikely(tso_header_sz > MLX5_MAX_TSO_HEADER)) {
47324c14430SShahaf Shuler 				txq->stats.oerrors++;
4743f13f8c2SShahaf Shuler 				break;
47524c14430SShahaf Shuler 			}
4763f13f8c2SShahaf Shuler 			copy_b = tso_header_sz - pkt_inline_sz;
4773f13f8c2SShahaf Shuler 			/* First seg must contain all headers. */
4783f13f8c2SShahaf Shuler 			assert(copy_b <= length);
47936aa55eaSYongseok Koh 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
48036aa55eaSYongseok Koh 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
4813f13f8c2SShahaf Shuler 
4823f13f8c2SShahaf Shuler 				if (unlikely(max_wqe < n))
4833f13f8c2SShahaf Shuler 					break;
4843f13f8c2SShahaf Shuler 				max_wqe -= n;
48536aa55eaSYongseok Koh 				rte_memcpy((void *)raw, (void *)addr, copy_b);
4863f13f8c2SShahaf Shuler 				addr += copy_b;
4873f13f8c2SShahaf Shuler 				length -= copy_b;
488d8292497SYongseok Koh 				/* Include padding for TSO header. */
489d8292497SYongseok Koh 				copy_b = MLX5_WQE_DS(copy_b) *
4903f13f8c2SShahaf Shuler 					 MLX5_WQE_DWORD_SIZE;
491d8292497SYongseok Koh 				pkt_inline_sz += copy_b;
492d8292497SYongseok Koh 				raw += copy_b;
4933f13f8c2SShahaf Shuler 			} else {
4943f13f8c2SShahaf Shuler 				/* NOP WQE. */
4953f13f8c2SShahaf Shuler 				wqe->ctrl = (rte_v128u32_t){
49636aa55eaSYongseok Koh 					rte_cpu_to_be_32(txq->wqe_ci << 8),
49736aa55eaSYongseok Koh 					rte_cpu_to_be_32(txq->qp_num_8s | 1),
4983f13f8c2SShahaf Shuler 					0,
4993f13f8c2SShahaf Shuler 					0,
5003f13f8c2SShahaf Shuler 				};
5013f13f8c2SShahaf Shuler 				ds = 1;
502cb98affeSThierry Herbelot #ifdef MLX5_PMD_SOFT_COUNTERS
5033f13f8c2SShahaf Shuler 				total_length = 0;
504cb98affeSThierry Herbelot #endif
5053f13f8c2SShahaf Shuler 				k++;
5063f13f8c2SShahaf Shuler 				goto next_wqe;
5073f13f8c2SShahaf Shuler 			}
5083f13f8c2SShahaf Shuler 		}
5096579c27cSNélio Laranjeiro 		/* Inline if enough room. */
51027a6b2d6SNélio Laranjeiro 		if (max_inline || tso) {
511f895536bSYongseok Koh 			uint32_t inl = 0;
512fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
513fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
514fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
515ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
5168fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
517d8292497SYongseok Koh 						   (pkt_inline_sz - 2) -
518d8292497SYongseok Koh 						   !!tso * sizeof(inl);
519f895536bSYongseok Koh 			uintptr_t addr_end;
520f895536bSYongseok Koh 			unsigned int copy_b;
5216579c27cSNélio Laranjeiro 
522f895536bSYongseok Koh pkt_inline:
523f895536bSYongseok Koh 			addr_end = RTE_ALIGN_FLOOR(addr + inline_room,
524f895536bSYongseok Koh 						   RTE_CACHE_LINE_SIZE);
525f895536bSYongseok Koh 			copy_b = (addr_end > addr) ?
526f895536bSYongseok Koh 				 RTE_MIN((addr_end - addr), length) : 0;
5278fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
528f04f1d51SNélio Laranjeiro 				/*
529f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
530f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
531f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
532f04f1d51SNélio Laranjeiro 				 */
5338fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
5348fcd6c2cSNélio Laranjeiro 
535f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
536f04f1d51SNélio Laranjeiro 					break;
537f04f1d51SNélio Laranjeiro 				max_wqe -= n;
538f895536bSYongseok Koh 				if (tso && !inl) {
5396963ae8bSYongseok Koh 					inl = rte_cpu_to_be_32(copy_b |
5406b30a6a8SShachar Beiser 							       MLX5_INLINE_SEG);
5413f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
5423f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
5433f13f8c2SShahaf Shuler 					raw += sizeof(inl);
5443f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
5453f13f8c2SShahaf Shuler 				}
5466579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
5476579c27cSNélio Laranjeiro 				addr += copy_b;
5486579c27cSNélio Laranjeiro 				length -= copy_b;
5496579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
5506579c27cSNélio Laranjeiro 			}
5516579c27cSNélio Laranjeiro 			/*
552786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
5536579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
5546579c27cSNélio Laranjeiro 			 */
5556579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
5566579c27cSNélio Laranjeiro 			if (length > 0) {
557f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
558f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
559f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
560f04f1d51SNélio Laranjeiro 						break;
561f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
562f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
563f04f1d51SNélio Laranjeiro 							   ds / 4);
564f04f1d51SNélio Laranjeiro 				} else {
5659a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
5666579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
5676579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
568f04f1d51SNélio Laranjeiro 				}
5696579c27cSNélio Laranjeiro 				goto use_dseg;
5706579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5716579c27cSNélio Laranjeiro 				goto next_pkt;
5726579c27cSNélio Laranjeiro 			} else {
573f895536bSYongseok Koh 				raw += copy_b;
574f895536bSYongseok Koh 				inline_room -= copy_b;
575f895536bSYongseok Koh 				--segs_n;
576f895536bSYongseok Koh 				buf = buf->next;
577f895536bSYongseok Koh 				assert(buf);
578f895536bSYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
579f895536bSYongseok Koh 				length = DATA_LEN(buf);
580f895536bSYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
581f895536bSYongseok Koh 				total_length += length;
582f895536bSYongseok Koh #endif
583f895536bSYongseok Koh 				(*txq->elts)[++elts_head & elts_m] = buf;
584f895536bSYongseok Koh 				goto pkt_inline;
5856579c27cSNélio Laranjeiro 			}
5866579c27cSNélio Laranjeiro 		} else {
5876579c27cSNélio Laranjeiro 			/*
5886579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
5896579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
5906579c27cSNélio Laranjeiro 			 */
5919a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
5926579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
5936579c27cSNélio Laranjeiro 			ds = 3;
5946579c27cSNélio Laranjeiro use_dseg:
5956579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
596ebbb81ebSNélio Laranjeiro 			addr = rte_cpu_to_be_64(addr);
5979a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
5986b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
5996cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
600ebbb81ebSNélio Laranjeiro 				addr,
601ebbb81ebSNélio Laranjeiro 				addr >> 32,
6026579c27cSNélio Laranjeiro 			};
6036579c27cSNélio Laranjeiro 			++ds;
6046579c27cSNélio Laranjeiro 			if (!segs_n)
6056579c27cSNélio Laranjeiro 				goto next_pkt;
6066579c27cSNélio Laranjeiro 		}
6076579c27cSNélio Laranjeiro next_seg:
6086579c27cSNélio Laranjeiro 		assert(buf);
6096579c27cSNélio Laranjeiro 		assert(ds);
6106579c27cSNélio Laranjeiro 		assert(wqe);
611a5bf6af9SAdrien Mazarguil 		/*
612a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
613a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
614a5bf6af9SAdrien Mazarguil 		 * of data segment size.
615a5bf6af9SAdrien Mazarguil 		 */
6168688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
6176579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
618f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
619f04f1d51SNélio Laranjeiro 				break;
6209a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
621f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
622f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
623f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
6246579c27cSNélio Laranjeiro 		} else {
625a5bf6af9SAdrien Mazarguil 			++dseg;
6266579c27cSNélio Laranjeiro 		}
627a5bf6af9SAdrien Mazarguil 		++ds;
628a5bf6af9SAdrien Mazarguil 		buf = buf->next;
629a5bf6af9SAdrien Mazarguil 		assert(buf);
6306579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
631a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
6326579c27cSNélio Laranjeiro 		total_length += length;
633a5bf6af9SAdrien Mazarguil #endif
6346579c27cSNélio Laranjeiro 		/* Store segment information. */
635ebbb81ebSNélio Laranjeiro 		addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t));
6369a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
6376b30a6a8SShachar Beiser 			rte_cpu_to_be_32(length),
6386cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
639ebbb81ebSNélio Laranjeiro 			addr,
640ebbb81ebSNélio Laranjeiro 			addr >> 32,
6416579c27cSNélio Laranjeiro 		};
6428c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
643f895536bSYongseok Koh 		if (--segs_n)
6446579c27cSNélio Laranjeiro 			goto next_seg;
6456579c27cSNélio Laranjeiro next_pkt:
646883ce172SShahaf Shuler 		if (ds > MLX5_DSEG_MAX) {
647883ce172SShahaf Shuler 			txq->stats.oerrors++;
648883ce172SShahaf Shuler 			break;
649883ce172SShahaf Shuler 		}
6508c819a69SYongseok Koh 		++elts_head;
6513730e6c6SYongseok Koh 		++pkts;
6526579c27cSNélio Laranjeiro 		++i;
653f895536bSYongseok Koh 		j += sg;
654b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
6553f13f8c2SShahaf Shuler 		if (tso) {
6563f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
6576b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6586b30a6a8SShachar Beiser 						 MLX5_OPCODE_TSO),
6596b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6603f13f8c2SShahaf Shuler 				0,
6613f13f8c2SShahaf Shuler 				0,
6623f13f8c2SShahaf Shuler 			};
6633f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
6643f13f8c2SShahaf Shuler 				0,
6656b30a6a8SShachar Beiser 				cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16),
6663f13f8c2SShahaf Shuler 				0,
6676b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(tso_header_sz),
6683f13f8c2SShahaf Shuler 			};
6693f13f8c2SShahaf Shuler 		} else {
6709a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
6716b30a6a8SShachar Beiser 				rte_cpu_to_be_32((txq->wqe_ci << 8) |
6726b30a6a8SShachar Beiser 						 MLX5_OPCODE_SEND),
6736b30a6a8SShachar Beiser 				rte_cpu_to_be_32(txq->qp_num_8s | ds),
6749a7fa9f7SNélio Laranjeiro 				0,
6759a7fa9f7SNélio Laranjeiro 				0,
6769a7fa9f7SNélio Laranjeiro 			};
6779a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
6789a7fa9f7SNélio Laranjeiro 				0,
6799a7fa9f7SNélio Laranjeiro 				cs_flags,
6809a7fa9f7SNélio Laranjeiro 				0,
6816b30a6a8SShachar Beiser 				(ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz),
6829a7fa9f7SNélio Laranjeiro 			};
6833f13f8c2SShahaf Shuler 		}
6843f13f8c2SShahaf Shuler next_wqe:
6856579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
686ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
687ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
68887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
689573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
6906579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
69187011737SAdrien Mazarguil #endif
6923730e6c6SYongseok Koh 	} while (i < pkts_n);
6932e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
6943f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
6952e22920bSAdrien Mazarguil 		return 0;
6968c819a69SYongseok Koh 	txq->elts_head += (i + j);
697c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
6983f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
699c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
700c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
7016b30a6a8SShachar Beiser 		last_wqe->ctrl2 = rte_cpu_to_be_32(8);
702c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
703ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
704c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
7052eefbec5SYongseok Koh #ifndef NDEBUG
7062eefbec5SYongseok Koh 		++txq->cq_pi;
7072eefbec5SYongseok Koh #endif
708c305090bSAdrien Mazarguil 	} else {
709c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
710c305090bSAdrien Mazarguil 	}
71187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
71287011737SAdrien Mazarguil 	/* Increment sent packets counter. */
71387011737SAdrien Mazarguil 	txq->stats.opackets += i;
71487011737SAdrien Mazarguil #endif
7152e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
716ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
7172e22920bSAdrien Mazarguil 	return i;
7182e22920bSAdrien Mazarguil }
7192e22920bSAdrien Mazarguil 
7202e22920bSAdrien Mazarguil /**
721230189d9SNélio Laranjeiro  * Open a MPW session.
722230189d9SNélio Laranjeiro  *
723230189d9SNélio Laranjeiro  * @param txq
724230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
725230189d9SNélio Laranjeiro  * @param mpw
726230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
727230189d9SNélio Laranjeiro  * @param length
728230189d9SNélio Laranjeiro  *   Packet length.
729230189d9SNélio Laranjeiro  */
730230189d9SNélio Laranjeiro static inline void
731991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length)
732230189d9SNélio Laranjeiro {
733a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
734230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
735230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
736fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
737230189d9SNélio Laranjeiro 
738230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
739230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
740230189d9SNélio Laranjeiro 	mpw->len = length;
741230189d9SNélio Laranjeiro 	mpw->total_len = 0;
742fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
7436b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
7448688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
7458688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
7468688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
7478688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
7486b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
7496b30a6a8SShachar Beiser 					     (txq->wqe_ci << 8) |
7506b30a6a8SShachar Beiser 					     MLX5_OPCODE_TSO);
7518688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
7528688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
7538688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
7548688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
7558688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
7568688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
757230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
758230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
759230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
760230189d9SNélio Laranjeiro }
761230189d9SNélio Laranjeiro 
762230189d9SNélio Laranjeiro /**
763230189d9SNélio Laranjeiro  * Close a MPW session.
764230189d9SNélio Laranjeiro  *
765230189d9SNélio Laranjeiro  * @param txq
766230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
767230189d9SNélio Laranjeiro  * @param mpw
768230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
769230189d9SNélio Laranjeiro  */
770230189d9SNélio Laranjeiro static inline void
771991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
772230189d9SNélio Laranjeiro {
773230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
774230189d9SNélio Laranjeiro 
775230189d9SNélio Laranjeiro 	/*
776230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
777230189d9SNélio Laranjeiro 	 * count as 2.
778230189d9SNélio Laranjeiro 	 */
7796b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num));
780230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
781230189d9SNélio Laranjeiro 	if (num < 3)
782230189d9SNélio Laranjeiro 		++txq->wqe_ci;
783230189d9SNélio Laranjeiro 	else
784230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
785fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
786fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
787230189d9SNélio Laranjeiro }
788230189d9SNélio Laranjeiro 
789230189d9SNélio Laranjeiro /**
790230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
791230189d9SNélio Laranjeiro  *
792230189d9SNélio Laranjeiro  * @param dpdk_txq
793230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
794230189d9SNélio Laranjeiro  * @param[in] pkts
795230189d9SNélio Laranjeiro  *   Packets to transmit.
796230189d9SNélio Laranjeiro  * @param pkts_n
797230189d9SNélio Laranjeiro  *   Number of packets in array.
798230189d9SNélio Laranjeiro  *
799230189d9SNélio Laranjeiro  * @return
800230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
801230189d9SNélio Laranjeiro  */
802230189d9SNélio Laranjeiro uint16_t
803230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
804230189d9SNélio Laranjeiro {
805991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
806230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
8078c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
8088c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
809c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
810a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
8118c819a69SYongseok Koh 	uint16_t max_elts;
812f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
813230189d9SNélio Laranjeiro 	unsigned int comp;
814230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
815230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
816230189d9SNélio Laranjeiro 	};
817230189d9SNélio Laranjeiro 
818c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
819c3d62cc9SAdrien Mazarguil 		return 0;
820230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
821fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
822fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
823230189d9SNélio Laranjeiro 	/* Start processing. */
8246cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
8258c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
8262eefbec5SYongseok Koh 	/* A CQE slot must always be available. */
8272eefbec5SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
828f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
829f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
830f04f1d51SNélio Laranjeiro 		return 0;
831c3d62cc9SAdrien Mazarguil 	do {
832a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
833230189d9SNélio Laranjeiro 		uint32_t length;
834a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
8354aa15eb1SNélio Laranjeiro 		uint32_t cs_flags;
836230189d9SNélio Laranjeiro 
837c3d62cc9SAdrien Mazarguil 		/*
838c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
839c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
840c3d62cc9SAdrien Mazarguil 		 */
841a5bf6af9SAdrien Mazarguil 		assert(segs_n);
8428c819a69SYongseok Koh 		if (max_elts < segs_n)
843c3d62cc9SAdrien Mazarguil 			break;
844a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
84524c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
84624c14430SShahaf Shuler 			txq->stats.oerrors++;
847a5bf6af9SAdrien Mazarguil 			break;
84824c14430SShahaf Shuler 		}
8498c819a69SYongseok Koh 		max_elts -= segs_n;
850c3d62cc9SAdrien Mazarguil 		--pkts_n;
8514aa15eb1SNélio Laranjeiro 		cs_flags = txq_ol_cksum_to_cs(txq, buf);
852a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
853a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
854a5bf6af9SAdrien Mazarguil 		assert(length);
855230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
856230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
857230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
858a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
8598688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
860230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
861230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
862f04f1d51SNélio Laranjeiro 			/*
863f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
864f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
865f04f1d51SNélio Laranjeiro 			 * resources.
866f04f1d51SNélio Laranjeiro 			 */
867f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
868f04f1d51SNélio Laranjeiro 				break;
869f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
870230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
8718688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
872230189d9SNélio Laranjeiro 		}
873a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
874a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
875a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
876a5bf6af9SAdrien Mazarguil 		length = 0;
877a5bf6af9SAdrien Mazarguil #endif
878a5bf6af9SAdrien Mazarguil 		do {
879a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
880a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
881a5bf6af9SAdrien Mazarguil 
882a5bf6af9SAdrien Mazarguil 			assert(buf);
8838c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
884230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
885a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
886230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
8876b30a6a8SShachar Beiser 				.byte_count = rte_cpu_to_be_32(DATA_LEN(buf)),
8886cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
8896b30a6a8SShachar Beiser 				.addr = rte_cpu_to_be_64(addr),
890230189d9SNélio Laranjeiro 			};
891a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
892a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
893a5bf6af9SAdrien Mazarguil #endif
894a5bf6af9SAdrien Mazarguil 			buf = buf->next;
895230189d9SNélio Laranjeiro 			++mpw.pkts_n;
896a5bf6af9SAdrien Mazarguil 			++j;
897a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
898a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
899230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
900230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
901230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
902230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
903230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
904230189d9SNélio Laranjeiro #endif
905c3d62cc9SAdrien Mazarguil 		++i;
906c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
907230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
908230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
909230189d9SNélio Laranjeiro 		return 0;
910230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
911a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
912a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
913230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
9148688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
915230189d9SNélio Laranjeiro 
916230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
9176b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
918230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
9198688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
920230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
9212eefbec5SYongseok Koh #ifndef NDEBUG
9222eefbec5SYongseok Koh 		++txq->cq_pi;
9232eefbec5SYongseok Koh #endif
924230189d9SNélio Laranjeiro 	} else {
925230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
926230189d9SNélio Laranjeiro 	}
927230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
928230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
929230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
930230189d9SNélio Laranjeiro #endif
931230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
932230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
933230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
93430807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
935230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
936230189d9SNélio Laranjeiro 	return i;
937230189d9SNélio Laranjeiro }
938230189d9SNélio Laranjeiro 
939230189d9SNélio Laranjeiro /**
940230189d9SNélio Laranjeiro  * Open a MPW inline session.
941230189d9SNélio Laranjeiro  *
942230189d9SNélio Laranjeiro  * @param txq
943230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
944230189d9SNélio Laranjeiro  * @param mpw
945230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
946230189d9SNélio Laranjeiro  * @param length
947230189d9SNélio Laranjeiro  *   Packet length.
948230189d9SNélio Laranjeiro  */
949230189d9SNélio Laranjeiro static inline void
950991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw,
951991b04f6SNélio Laranjeiro 		    uint32_t length)
952230189d9SNélio Laranjeiro {
953a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
9548688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
955230189d9SNélio Laranjeiro 
956230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
957230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
958230189d9SNélio Laranjeiro 	mpw->len = length;
959230189d9SNélio Laranjeiro 	mpw->total_len = 0;
960fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9616b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) |
962230189d9SNélio Laranjeiro 					     (txq->wqe_ci << 8) |
963c904ae25SNélio Laranjeiro 					     MLX5_OPCODE_TSO);
9648688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9658688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9666b30a6a8SShachar Beiser 	mpw->wqe->eseg.mss = rte_cpu_to_be_16(length);
9678688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9688688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
9698688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9708688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9718688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
9728688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
9738688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
9748688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
975230189d9SNélio Laranjeiro }
976230189d9SNélio Laranjeiro 
977230189d9SNélio Laranjeiro /**
978230189d9SNélio Laranjeiro  * Close a MPW inline session.
979230189d9SNélio Laranjeiro  *
980230189d9SNélio Laranjeiro  * @param txq
981230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
982230189d9SNélio Laranjeiro  * @param mpw
983230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
984230189d9SNélio Laranjeiro  */
985230189d9SNélio Laranjeiro static inline void
986991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
987230189d9SNélio Laranjeiro {
988230189d9SNélio Laranjeiro 	unsigned int size;
9898688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
9908688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
991230189d9SNélio Laranjeiro 
9928688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
993230189d9SNélio Laranjeiro 	/*
994230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
995230189d9SNélio Laranjeiro 	 * count as 2.
996230189d9SNélio Laranjeiro 	 */
9976b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
9986b30a6a8SShachar Beiser 					     MLX5_WQE_DS(size));
999230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
10006b30a6a8SShachar Beiser 	inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG);
10018688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1002230189d9SNélio Laranjeiro }
1003230189d9SNélio Laranjeiro 
1004230189d9SNélio Laranjeiro /**
1005230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1006230189d9SNélio Laranjeiro  *
1007230189d9SNélio Laranjeiro  * @param dpdk_txq
1008230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1009230189d9SNélio Laranjeiro  * @param[in] pkts
1010230189d9SNélio Laranjeiro  *   Packets to transmit.
1011230189d9SNélio Laranjeiro  * @param pkts_n
1012230189d9SNélio Laranjeiro  *   Number of packets in array.
1013230189d9SNélio Laranjeiro  *
1014230189d9SNélio Laranjeiro  * @return
1015230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1016230189d9SNélio Laranjeiro  */
1017230189d9SNélio Laranjeiro uint16_t
1018230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1019230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1020230189d9SNélio Laranjeiro {
1021991b04f6SNélio Laranjeiro 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
1022230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
10238c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
10248c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
1025c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1026a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
10278c819a69SYongseok Koh 	uint16_t max_elts;
1028f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1029230189d9SNélio Laranjeiro 	unsigned int comp;
10300e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1031230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1032230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1033230189d9SNélio Laranjeiro 	};
1034f04f1d51SNélio Laranjeiro 	/*
1035f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1036f04f1d51SNélio Laranjeiro 	 * code.
1037f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1038f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1039f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1040f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1041f04f1d51SNélio Laranjeiro 	 */
1042f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1043f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1044f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1045f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1046230189d9SNélio Laranjeiro 
1047c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1048c3d62cc9SAdrien Mazarguil 		return 0;
1049230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1050fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1051fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1052230189d9SNélio Laranjeiro 	/* Start processing. */
10536cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
10548c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
10552eefbec5SYongseok Koh 	/* A CQE slot must always be available. */
10562eefbec5SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
1057c3d62cc9SAdrien Mazarguil 	do {
1058a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1059230189d9SNélio Laranjeiro 		uintptr_t addr;
1060230189d9SNélio Laranjeiro 		uint32_t length;
1061a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
10624aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
1063230189d9SNélio Laranjeiro 
1064c3d62cc9SAdrien Mazarguil 		/*
1065c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1066c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1067c3d62cc9SAdrien Mazarguil 		 */
1068a5bf6af9SAdrien Mazarguil 		assert(segs_n);
10698c819a69SYongseok Koh 		if (max_elts < segs_n)
1070c3d62cc9SAdrien Mazarguil 			break;
1071a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
107224c14430SShahaf Shuler 		if (segs_n > MLX5_MPW_DSEG_MAX) {
107324c14430SShahaf Shuler 			txq->stats.oerrors++;
1074a5bf6af9SAdrien Mazarguil 			break;
107524c14430SShahaf Shuler 		}
10768c819a69SYongseok Koh 		max_elts -= segs_n;
1077c3d62cc9SAdrien Mazarguil 		--pkts_n;
1078f04f1d51SNélio Laranjeiro 		/*
1079f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1080f04f1d51SNélio Laranjeiro 		 * iteration.
1081f04f1d51SNélio Laranjeiro 		 */
1082f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
10834aa15eb1SNélio Laranjeiro 		cs_flags = txq_ol_cksum_to_cs(txq, buf);
1084a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1085a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1086230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1087230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1088230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1089a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
10908688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1091230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1092230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1093230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1094a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1095230189d9SNélio Laranjeiro 			    (length > inline_room) ||
10968688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1097230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
10980e8679fcSNélio Laranjeiro 				inline_room =
10990e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1100230189d9SNélio Laranjeiro 			}
1101230189d9SNélio Laranjeiro 		}
1102230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1103a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1104a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1105f04f1d51SNélio Laranjeiro 				/*
1106f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1107f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1108f04f1d51SNélio Laranjeiro 				 * such resources.
1109f04f1d51SNélio Laranjeiro 				 */
1110f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1111f04f1d51SNélio Laranjeiro 					break;
1112f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1113230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
11148688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1115230189d9SNélio Laranjeiro 			} else {
1116f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1117f04f1d51SNélio Laranjeiro 					break;
1118f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1119230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
11208688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1121230189d9SNélio Laranjeiro 			}
1122230189d9SNélio Laranjeiro 		}
1123a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1124a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1125230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
11260e8679fcSNélio Laranjeiro 			assert(inline_room ==
11270e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1128a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1129a5bf6af9SAdrien Mazarguil 			length = 0;
1130a5bf6af9SAdrien Mazarguil #endif
1131a5bf6af9SAdrien Mazarguil 			do {
1132230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1133230189d9SNélio Laranjeiro 
1134a5bf6af9SAdrien Mazarguil 				assert(buf);
11358c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1136230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1137a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1138230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
11396b30a6a8SShachar Beiser 					.byte_count =
11406b30a6a8SShachar Beiser 					       rte_cpu_to_be_32(DATA_LEN(buf)),
11416cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
11426b30a6a8SShachar Beiser 					.addr = rte_cpu_to_be_64(addr),
1143230189d9SNélio Laranjeiro 				};
1144a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1145a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1146a5bf6af9SAdrien Mazarguil #endif
1147a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1148230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1149a5bf6af9SAdrien Mazarguil 				++j;
1150a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1151a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1152230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1153230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1154230189d9SNélio Laranjeiro 		} else {
1155230189d9SNélio Laranjeiro 			unsigned int max;
1156230189d9SNélio Laranjeiro 
1157230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1158230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1159a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1160a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
11618c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1162230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1163fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1164fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1165fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1166230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1167230189d9SNélio Laranjeiro 			if (length > max) {
1168230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1169230189d9SNélio Laranjeiro 					   (void *)addr,
1170230189d9SNélio Laranjeiro 					   max);
1171fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1172230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1173230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1174230189d9SNélio Laranjeiro 					   length - max);
1175230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1176230189d9SNélio Laranjeiro 			} else {
1177230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1178230189d9SNélio Laranjeiro 					   (void *)addr,
1179230189d9SNélio Laranjeiro 					   length);
118016c64768SYongseok Koh 
118116c64768SYongseok Koh 				if (length == max)
118216c64768SYongseok Koh 					mpw.data.raw =
118316c64768SYongseok Koh 						(volatile void *)txq->wqes;
118416c64768SYongseok Koh 				else
1185230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1186230189d9SNélio Laranjeiro 			}
1187230189d9SNélio Laranjeiro 			++mpw.pkts_n;
118876bf1574SYongseok Koh 			mpw.total_len += length;
1189a5bf6af9SAdrien Mazarguil 			++j;
1190230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1191230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11920e8679fcSNélio Laranjeiro 				inline_room =
11930e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1194230189d9SNélio Laranjeiro 			} else {
1195230189d9SNélio Laranjeiro 				inline_room -= length;
1196230189d9SNélio Laranjeiro 			}
1197230189d9SNélio Laranjeiro 		}
1198230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1199230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1200230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1201230189d9SNélio Laranjeiro #endif
1202c3d62cc9SAdrien Mazarguil 		++i;
1203c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1204230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1205230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1206230189d9SNélio Laranjeiro 		return 0;
1207230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1208a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1209a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1210230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
12118688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1212230189d9SNélio Laranjeiro 
1213230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
12146b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
1215230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
12168688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1217230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
12182eefbec5SYongseok Koh #ifndef NDEBUG
12192eefbec5SYongseok Koh 		++txq->cq_pi;
12202eefbec5SYongseok Koh #endif
1221230189d9SNélio Laranjeiro 	} else {
1222230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1223230189d9SNélio Laranjeiro 	}
1224230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1225230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1226230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1227230189d9SNélio Laranjeiro #endif
1228230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1229230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1230230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1231230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1232230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
123330807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1234230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1235230189d9SNélio Laranjeiro 	return i;
1236230189d9SNélio Laranjeiro }
1237230189d9SNélio Laranjeiro 
1238230189d9SNélio Laranjeiro /**
12396ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
12406ce84bd8SYongseok Koh  *
12416ce84bd8SYongseok Koh  * @param txq
12426ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12436ce84bd8SYongseok Koh  * @param mpw
12446ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12456ce84bd8SYongseok Koh  * @param length
12466ce84bd8SYongseok Koh  *   Packet length.
12476ce84bd8SYongseok Koh  */
12486ce84bd8SYongseok Koh static inline void
1249991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding)
12506ce84bd8SYongseok Koh {
12516ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
12526ce84bd8SYongseok Koh 
12536ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
12546ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
12556ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
12566ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
12576b30a6a8SShachar Beiser 	mpw->wqe->ctrl[0] =
12586b30a6a8SShachar Beiser 		rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
12596ce84bd8SYongseok Koh 				 (txq->wqe_ci << 8) |
12606ce84bd8SYongseok Koh 				 MLX5_OPCODE_ENHANCED_MPSW);
12616ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
12626ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
12636ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
12646ce84bd8SYongseok Koh 	if (unlikely(padding)) {
12656ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
12666ce84bd8SYongseok Koh 
12676ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
12686b30a6a8SShachar Beiser 		*(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG);
12696ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
12706b30a6a8SShachar Beiser 			rte_cpu_to_be_32(MLX5_INLINE_SEG);
12716ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
12726ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
12736ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
12746ce84bd8SYongseok Koh 	} else {
12756ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
12766ce84bd8SYongseok Koh 	}
12776ce84bd8SYongseok Koh }
12786ce84bd8SYongseok Koh 
12796ce84bd8SYongseok Koh /**
12806ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
12816ce84bd8SYongseok Koh  *
12826ce84bd8SYongseok Koh  * @param txq
12836ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
12846ce84bd8SYongseok Koh  * @param mpw
12856ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
12866ce84bd8SYongseok Koh  *
12876ce84bd8SYongseok Koh  * @return
12886ce84bd8SYongseok Koh  *   Number of consumed WQEs.
12896ce84bd8SYongseok Koh  */
12906ce84bd8SYongseok Koh static inline uint16_t
1291991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw)
12926ce84bd8SYongseok Koh {
12936ce84bd8SYongseok Koh 	uint16_t ret;
12946ce84bd8SYongseok Koh 
12956ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
12966ce84bd8SYongseok Koh 	 * count as 2.
12976ce84bd8SYongseok Koh 	 */
12986b30a6a8SShachar Beiser 	mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s |
12996b30a6a8SShachar Beiser 					     MLX5_WQE_DS(mpw->total_len));
13006ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
13016ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
13026ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
13036ce84bd8SYongseok Koh 	return ret;
13046ce84bd8SYongseok Koh }
13056ce84bd8SYongseok Koh 
13066ce84bd8SYongseok Koh /**
13074b0d7b7fSYongseok Koh  * TX with Enhanced MPW support.
13086ce84bd8SYongseok Koh  *
13094b0d7b7fSYongseok Koh  * @param txq
13104b0d7b7fSYongseok Koh  *   Pointer to TX queue structure.
13116ce84bd8SYongseok Koh  * @param[in] pkts
13126ce84bd8SYongseok Koh  *   Packets to transmit.
13136ce84bd8SYongseok Koh  * @param pkts_n
13146ce84bd8SYongseok Koh  *   Number of packets in array.
13156ce84bd8SYongseok Koh  *
13166ce84bd8SYongseok Koh  * @return
13176ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
13186ce84bd8SYongseok Koh  */
13194b0d7b7fSYongseok Koh static inline uint16_t
13204b0d7b7fSYongseok Koh txq_burst_empw(struct mlx5_txq_data *txq, struct rte_mbuf **pkts,
13214b0d7b7fSYongseok Koh 	       uint16_t pkts_n)
13226ce84bd8SYongseok Koh {
13236ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
13248c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
13258c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
13266ce84bd8SYongseok Koh 	unsigned int i = 0;
13276ce84bd8SYongseok Koh 	unsigned int j = 0;
13288c819a69SYongseok Koh 	uint16_t max_elts;
13296ce84bd8SYongseok Koh 	uint16_t max_wqe;
13306ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
13316ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
13326ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
13336ce84bd8SYongseok Koh 	uint32_t inl_hdr;
13346ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
13356ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
13366ce84bd8SYongseok Koh 	};
13376ce84bd8SYongseok Koh 
13386ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
13396ce84bd8SYongseok Koh 		return 0;
13406ce84bd8SYongseok Koh 	/* Start processing. */
13416cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
13426ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
13436ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
13446ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
13456ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
13466ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
13476ce84bd8SYongseok Koh 		return 0;
13486ce84bd8SYongseok Koh 	do {
13496ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
13506ce84bd8SYongseok Koh 		uintptr_t addr;
13516ce84bd8SYongseok Koh 		unsigned int n;
13526ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
13536ce84bd8SYongseok Koh 		uint32_t length;
13544aa15eb1SNélio Laranjeiro 		uint8_t cs_flags;
13556ce84bd8SYongseok Koh 
135648642ec5SYongseok Koh 		/* Multi-segmented packet is handled in slow-path outside. */
135748642ec5SYongseok Koh 		assert(NB_SEGS(buf) == 1);
135848642ec5SYongseok Koh 		/* Make sure there is enough room to store this packet. */
135948642ec5SYongseok Koh 		if (max_elts - j == 0)
13606ce84bd8SYongseok Koh 			break;
13614aa15eb1SNélio Laranjeiro 		cs_flags = txq_ol_cksum_to_cs(txq, buf);
13626ce84bd8SYongseok Koh 		/* Retrieve packet information. */
13636ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
13646ce84bd8SYongseok Koh 		/* Start new session if:
13656ce84bd8SYongseok Koh 		 * - multi-segment packet
13666ce84bd8SYongseok Koh 		 * - no space left even for a dseg
13676ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
13686ce84bd8SYongseok Koh 		 * - cs_flag differs
13696ce84bd8SYongseok Koh 		 */
13706ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
137148642ec5SYongseok Koh 			if ((inl_pad + sizeof(struct mlx5_wqe_data_seg) >
13726ce84bd8SYongseok Koh 			     mpw_room) ||
13736ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
13746ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
13756ce84bd8SYongseok Koh 			     mpw_room) ||
13766ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
13776ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
13786ce84bd8SYongseok Koh 		}
13796ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
138048642ec5SYongseok Koh 			/* In Enhanced MPW, inline as much as the budget is
138148642ec5SYongseok Koh 			 * allowed. The remaining space is to be filled with
138248642ec5SYongseok Koh 			 * dsegs. If the title WQEBB isn't padded, it will have
138348642ec5SYongseok Koh 			 * 2 dsegs there.
13846ce84bd8SYongseok Koh 			 */
13856ce84bd8SYongseok Koh 			mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
13866ce84bd8SYongseok Koh 					   (max_inline ? max_inline :
13876ce84bd8SYongseok Koh 					    pkts_n * MLX5_WQE_DWORD_SIZE) +
13886ce84bd8SYongseok Koh 					   MLX5_WQE_SIZE);
138948642ec5SYongseok Koh 			if (unlikely(max_wqe * MLX5_WQE_SIZE < mpw_room))
13906ce84bd8SYongseok Koh 				break;
13916ce84bd8SYongseok Koh 			/* Don't pad the title WQEBB to not waste WQ. */
13926ce84bd8SYongseok Koh 			mlx5_empw_new(txq, &mpw, 0);
13936ce84bd8SYongseok Koh 			mpw_room -= mpw.total_len;
13946ce84bd8SYongseok Koh 			inl_pad = 0;
139548642ec5SYongseok Koh 			do_inline = length <= txq->inline_max_packet_sz &&
13966ce84bd8SYongseok Koh 				    sizeof(inl_hdr) + length <= mpw_room &&
13976ce84bd8SYongseok Koh 				    !txq->mpw_hdr_dseg;
13986ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
13996ce84bd8SYongseok Koh 		} else {
14006ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
14016ce84bd8SYongseok Koh 			 * Inlininig is possible when:
14026ce84bd8SYongseok Koh 			 * - length is less than configured value
14036ce84bd8SYongseok Koh 			 * - length fits for remaining space
14046ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
14056ce84bd8SYongseok Koh 			 */
14066ce84bd8SYongseok Koh 			do_inline =
14076ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
14086ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
14096ce84bd8SYongseok Koh 				 mpw_room &&
14106ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
14116ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
14126ce84bd8SYongseok Koh 		}
141348642ec5SYongseok Koh 		if (do_inline) {
14146ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
14156ce84bd8SYongseok Koh 			unsigned int max;
14166ce84bd8SYongseok Koh 
14176ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14186ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14196b30a6a8SShachar Beiser 			inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG);
14206ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14216ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14226ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
14236ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
14246ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
14256ce84bd8SYongseok Koh 			/* Copy inline header. */
14266ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14276ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
14286ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
14296ce84bd8SYongseok Koh 					  &inl_hdr,
14306ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
14316ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
14326ce84bd8SYongseok Koh 					  max);
14336ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
14346ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
14356ce84bd8SYongseok Koh 			/* Copy packet data. */
14366ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
14376ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
14386ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
14396ce84bd8SYongseok Koh 					  (void *)addr,
14406ce84bd8SYongseok Koh 					  length,
14416ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
14426ce84bd8SYongseok Koh 					  max);
14436ce84bd8SYongseok Koh 			++mpw.pkts_n;
14446ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
14456ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
14466ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
14476ce84bd8SYongseok Koh 			 */
14486ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
14496ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
14506ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
14516ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
14526ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
14536ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
14546ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
14556ce84bd8SYongseok Koh 		} else {
14566ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
14576ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
14586ce84bd8SYongseok Koh 
14596ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14606ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
14616ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14626ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
14636ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
14646ce84bd8SYongseok Koh 						+ inl_pad)))
14656ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
14666ce84bd8SYongseok Koh 			else
14676ce84bd8SYongseok Koh 				dseg = (volatile void *)
14686ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
14696ce84bd8SYongseok Koh 					 inl_pad);
14708c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
14716ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14726ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
14736ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
14746ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
1475ebbb81ebSNélio Laranjeiro 			addr = rte_cpu_to_be_64(addr);
14766ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
14776b30a6a8SShachar Beiser 				rte_cpu_to_be_32(length),
14786cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
1479ebbb81ebSNélio Laranjeiro 				addr,
1480ebbb81ebSNélio Laranjeiro 				addr >> 32,
14816ce84bd8SYongseok Koh 			};
14826ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
14836ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
14846ce84bd8SYongseok Koh 			++j;
14856ce84bd8SYongseok Koh 			++mpw.pkts_n;
14866ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
14876ce84bd8SYongseok Koh 			inl_pad = 0;
14886ce84bd8SYongseok Koh 		}
14896ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
14906ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
14916ce84bd8SYongseok Koh 		txq->stats.obytes += length;
14926ce84bd8SYongseok Koh #endif
14936ce84bd8SYongseok Koh 		++i;
14946ce84bd8SYongseok Koh 	} while (i < pkts_n);
14956ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
14966ce84bd8SYongseok Koh 	if (unlikely(i == 0))
14976ce84bd8SYongseok Koh 		return 0;
14986ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
14996ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
15006ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
15016ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
15026ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
15036ce84bd8SYongseok Koh 
15046ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
15056b30a6a8SShachar Beiser 		wqe->ctrl[2] = rte_cpu_to_be_32(8);
15066ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
15076ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
15086ce84bd8SYongseok Koh 		txq->elts_comp = 0;
15096ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
15102eefbec5SYongseok Koh #ifndef NDEBUG
15112eefbec5SYongseok Koh 		++txq->cq_pi;
15122eefbec5SYongseok Koh #endif
15136ce84bd8SYongseok Koh 	} else {
15146ce84bd8SYongseok Koh 		txq->elts_comp += j;
15156ce84bd8SYongseok Koh 	}
15166ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
15176ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
15186ce84bd8SYongseok Koh 	txq->stats.opackets += i;
15196ce84bd8SYongseok Koh #endif
15206ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
15216ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
15226ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
15236ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
15246ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
15256ce84bd8SYongseok Koh 	return i;
15266ce84bd8SYongseok Koh }
15276ce84bd8SYongseok Koh 
15286ce84bd8SYongseok Koh /**
15294b0d7b7fSYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
15304b0d7b7fSYongseok Koh  *
15314b0d7b7fSYongseok Koh  * @param dpdk_txq
15324b0d7b7fSYongseok Koh  *   Generic pointer to TX queue structure.
15334b0d7b7fSYongseok Koh  * @param[in] pkts
15344b0d7b7fSYongseok Koh  *   Packets to transmit.
15354b0d7b7fSYongseok Koh  * @param pkts_n
15364b0d7b7fSYongseok Koh  *   Number of packets in array.
15374b0d7b7fSYongseok Koh  *
15384b0d7b7fSYongseok Koh  * @return
15394b0d7b7fSYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
15404b0d7b7fSYongseok Koh  */
15414b0d7b7fSYongseok Koh uint16_t
15424b0d7b7fSYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
15434b0d7b7fSYongseok Koh {
15444b0d7b7fSYongseok Koh 	struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq;
15454b0d7b7fSYongseok Koh 	uint16_t nb_tx = 0;
15464b0d7b7fSYongseok Koh 
15474b0d7b7fSYongseok Koh 	while (pkts_n > nb_tx) {
15484b0d7b7fSYongseok Koh 		uint16_t n;
15494b0d7b7fSYongseok Koh 		uint16_t ret;
15504b0d7b7fSYongseok Koh 
15514b0d7b7fSYongseok Koh 		n = txq_count_contig_multi_seg(&pkts[nb_tx], pkts_n - nb_tx);
15524b0d7b7fSYongseok Koh 		if (n) {
15534b0d7b7fSYongseok Koh 			ret = mlx5_tx_burst(dpdk_txq, &pkts[nb_tx], n);
15544b0d7b7fSYongseok Koh 			if (!ret)
15554b0d7b7fSYongseok Koh 				break;
15564b0d7b7fSYongseok Koh 			nb_tx += ret;
15574b0d7b7fSYongseok Koh 		}
15584b0d7b7fSYongseok Koh 		n = txq_count_contig_single_seg(&pkts[nb_tx], pkts_n - nb_tx);
15594b0d7b7fSYongseok Koh 		if (n) {
15604b0d7b7fSYongseok Koh 			ret = txq_burst_empw(txq, &pkts[nb_tx], n);
15614b0d7b7fSYongseok Koh 			if (!ret)
15624b0d7b7fSYongseok Koh 				break;
15634b0d7b7fSYongseok Koh 			nb_tx += ret;
15644b0d7b7fSYongseok Koh 		}
15654b0d7b7fSYongseok Koh 	}
15664b0d7b7fSYongseok Koh 	return nb_tx;
15674b0d7b7fSYongseok Koh }
15684b0d7b7fSYongseok Koh 
15694b0d7b7fSYongseok Koh /**
157067fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
157167fa62bcSAdrien Mazarguil  *
15726218063bSNélio Laranjeiro  * @param[in] cqe
15736218063bSNélio Laranjeiro  *   Pointer to CQE.
157467fa62bcSAdrien Mazarguil  *
157578a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
157678a38edfSJianfeng Tan  *
157767fa62bcSAdrien Mazarguil  * @return
157867fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
157967fa62bcSAdrien Mazarguil  */
158067fa62bcSAdrien Mazarguil static inline uint32_t
158197267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
158267fa62bcSAdrien Mazarguil {
1583ea16068cSYongseok Koh 	uint8_t idx;
1584ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
1585ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
158667fa62bcSAdrien Mazarguil 
1587ea16068cSYongseok Koh 	/*
1588ea16068cSYongseok Koh 	 * The index to the array should have:
1589ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
1590ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
1591ea16068cSYongseok Koh 	 * bit[5] = ip_frag
1592ea16068cSYongseok Koh 	 * bit[6] = tunneled
1593ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
1594ea16068cSYongseok Koh 	 */
1595ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
1596ea16068cSYongseok Koh 	return mlx5_ptype_table[idx];
159767fa62bcSAdrien Mazarguil }
159867fa62bcSAdrien Mazarguil 
159967fa62bcSAdrien Mazarguil /**
160099c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
160199c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
160299c12dccSNélio Laranjeiro  * been processed.
160399c12dccSNélio Laranjeiro  *
160499c12dccSNélio Laranjeiro  * @param rxq
160599c12dccSNélio Laranjeiro  *   Pointer to RX queue.
160699c12dccSNélio Laranjeiro  * @param cqe
160799c12dccSNélio Laranjeiro  *   CQE to process.
1608ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1609ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
161099c12dccSNélio Laranjeiro  *
161199c12dccSNélio Laranjeiro  * @return
161299c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
161399c12dccSNélio Laranjeiro  *   with error.
161499c12dccSNélio Laranjeiro  */
161599c12dccSNélio Laranjeiro static inline int
161678142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
1617ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
161899c12dccSNélio Laranjeiro {
161999c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
162099c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
162199c12dccSNélio Laranjeiro 	int len = 0;
1622d2e842d0SYongseok Koh 	uint16_t idx, end;
162399c12dccSNélio Laranjeiro 
162499c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
162599c12dccSNélio Laranjeiro 	if (zip->ai) {
162699c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
162799c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
16284aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
162999c12dccSNélio Laranjeiro 
16306b30a6a8SShachar Beiser 		len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
16316b30a6a8SShachar Beiser 		*rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result);
163299c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1633d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1634d2e842d0SYongseok Koh 			idx = zip->ca;
1635d2e842d0SYongseok Koh 			end = zip->na;
1636d2e842d0SYongseok Koh 			while (idx != end) {
1637d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1638d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1639d2e842d0SYongseok Koh 				++idx;
1640d2e842d0SYongseok Koh 			}
164199c12dccSNélio Laranjeiro 			/*
164299c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
164399c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
164499c12dccSNélio Laranjeiro 			 * ring for software use.
164599c12dccSNélio Laranjeiro 			 */
164699c12dccSNélio Laranjeiro 			zip->ca = zip->na;
164799c12dccSNélio Laranjeiro 			zip->na += 8;
164899c12dccSNélio Laranjeiro 		}
164999c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1650d2e842d0SYongseok Koh 			/* Invalidate the rest */
1651d2e842d0SYongseok Koh 			idx = zip->ca;
1652d2e842d0SYongseok Koh 			end = zip->cq_ci;
165399c12dccSNélio Laranjeiro 
165499c12dccSNélio Laranjeiro 			while (idx != end) {
165597267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
165699c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
165799c12dccSNélio Laranjeiro 				++idx;
165899c12dccSNélio Laranjeiro 			}
165999c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
166099c12dccSNélio Laranjeiro 			zip->ai = 0;
166199c12dccSNélio Laranjeiro 		}
166299c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
166399c12dccSNélio Laranjeiro 	} else {
166499c12dccSNélio Laranjeiro 		int ret;
166599c12dccSNélio Laranjeiro 		int8_t op_own;
166699c12dccSNélio Laranjeiro 
166797267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
166899c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
166999c12dccSNélio Laranjeiro 			return 0;
167099c12dccSNélio Laranjeiro 		++rxq->cq_ci;
167199c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
167299c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
167399c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
167499c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
167599c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
16764aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
167799c12dccSNélio Laranjeiro 
167899c12dccSNélio Laranjeiro 			/* Fix endianness. */
16796b30a6a8SShachar Beiser 			zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
168099c12dccSNélio Laranjeiro 			/*
168199c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
168299c12dccSNélio Laranjeiro 			 * check_cqe64().
168399c12dccSNélio Laranjeiro 			 *
168499c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
168599c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
168699c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
168799c12dccSNélio Laranjeiro 			 */
1688d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
168999c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
169099c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
169199c12dccSNélio Laranjeiro 			--rxq->cq_ci;
169299c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
169399c12dccSNélio Laranjeiro 			/* Get packet size to return. */
16946b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
16956b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result);
169699c12dccSNélio Laranjeiro 			zip->ai = 1;
1697d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1698d2e842d0SYongseok Koh 			idx = zip->ca;
1699d2e842d0SYongseok Koh 			end = zip->cq_ci;
1700d2e842d0SYongseok Koh 			while (idx != end) {
1701d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1702d2e842d0SYongseok Koh 				++idx;
1703d2e842d0SYongseok Koh 			}
170499c12dccSNélio Laranjeiro 		} else {
17056b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32(cqe->byte_cnt);
17066b30a6a8SShachar Beiser 			*rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res);
170799c12dccSNélio Laranjeiro 		}
170899c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
170999c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
171099c12dccSNélio Laranjeiro 			return -1;
171199c12dccSNélio Laranjeiro 	}
171299c12dccSNélio Laranjeiro 	return len;
171399c12dccSNélio Laranjeiro }
171499c12dccSNélio Laranjeiro 
171599c12dccSNélio Laranjeiro /**
171667fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
171767fa62bcSAdrien Mazarguil  *
171867fa62bcSAdrien Mazarguil  * @param[in] rxq
171967fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
17206218063bSNélio Laranjeiro  * @param[in] cqe
17216218063bSNélio Laranjeiro  *   Pointer to CQE.
172267fa62bcSAdrien Mazarguil  *
172367fa62bcSAdrien Mazarguil  * @return
172467fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
172567fa62bcSAdrien Mazarguil  */
172667fa62bcSAdrien Mazarguil static inline uint32_t
172778142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe)
172867fa62bcSAdrien Mazarguil {
172967fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
17306b30a6a8SShachar Beiser 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
173167fa62bcSAdrien Mazarguil 
17320603df73SNélio Laranjeiro 	ol_flags =
17330603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17340603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
17350603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
17360603df73SNélio Laranjeiro 		TRANSPOSE(flags,
17370603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
173883e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
173997267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
174067fa62bcSAdrien Mazarguil 		ol_flags |=
17410603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17420603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
174383e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
17440603df73SNélio Laranjeiro 			TRANSPOSE(flags,
17450603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
174683e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
174767fa62bcSAdrien Mazarguil 	return ol_flags;
174867fa62bcSAdrien Mazarguil }
174967fa62bcSAdrien Mazarguil 
175067fa62bcSAdrien Mazarguil /**
17512e22920bSAdrien Mazarguil  * DPDK callback for RX.
17522e22920bSAdrien Mazarguil  *
17532e22920bSAdrien Mazarguil  * @param dpdk_rxq
17542e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
17552e22920bSAdrien Mazarguil  * @param[out] pkts
17562e22920bSAdrien Mazarguil  *   Array to store received packets.
17572e22920bSAdrien Mazarguil  * @param pkts_n
17582e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
17592e22920bSAdrien Mazarguil  *
17602e22920bSAdrien Mazarguil  * @return
17612e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
17622e22920bSAdrien Mazarguil  */
17632e22920bSAdrien Mazarguil uint16_t
17642e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
17652e22920bSAdrien Mazarguil {
176678142aacSNélio Laranjeiro 	struct mlx5_rxq_data *rxq = dpdk_rxq;
1767b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1768e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
17699964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
17709964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
17719964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
177297267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
177397267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
17749964b965SNélio Laranjeiro 	unsigned int i = 0;
17759964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
17764e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
17772e22920bSAdrien Mazarguil 
17789964b965SNélio Laranjeiro 	while (pkts_n) {
17799964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
17809964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
17819964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1782ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
17839964b965SNélio Laranjeiro 
17849964b965SNélio Laranjeiro 		if (pkt)
17859964b965SNélio Laranjeiro 			NEXT(seg) = rep;
17869964b965SNélio Laranjeiro 		seg = rep;
17879964b965SNélio Laranjeiro 		rte_prefetch0(seg);
17886218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
17899964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1790fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
17912e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
179215a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
179315a756b6SSagi Grimberg 			if (!pkt) {
179415a756b6SSagi Grimberg 				/*
179515a756b6SSagi Grimberg 				 * no buffers before we even started,
179615a756b6SSagi Grimberg 				 * bail out silently.
179715a756b6SSagi Grimberg 				 */
179815a756b6SSagi Grimberg 				break;
179915a756b6SSagi Grimberg 			}
1800a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1801a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1802fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
18038f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
18048f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
18051f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1806fe5fe382SNélio Laranjeiro 				pkt = rep;
18079964b965SNélio Laranjeiro 			}
18086218063bSNélio Laranjeiro 			break;
18092e22920bSAdrien Mazarguil 		}
18109964b965SNélio Laranjeiro 		if (!pkt) {
181197267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1812ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1813ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1814ecf60761SNélio Laranjeiro 			if (!len) {
18151f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
18166218063bSNélio Laranjeiro 				break;
18176218063bSNélio Laranjeiro 			}
181899c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
181999c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
18201f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
182199c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
182299c12dccSNélio Laranjeiro 				goto skip;
182399c12dccSNélio Laranjeiro 			}
18249964b965SNélio Laranjeiro 			pkt = seg;
18259964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
18269964b965SNélio Laranjeiro 			/* Update packet information. */
182748dfc20fSYongseok Koh 			pkt->packet_type = rxq_cq_to_pkt_type(cqe);
18280ac64846SMaxime Leroy 			pkt->ol_flags = 0;
182936ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1830ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1831ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1832ecf60761SNélio Laranjeiro 			}
1833c604f619SNélio Laranjeiro 			if (rxq->mark &&
1834c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1835b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
1836b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
18376b30a6a8SShachar Beiser 				    rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
1838b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
1839b268a3eeSNélio Laranjeiro 
1840b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
1841ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
1842b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
1843b268a3eeSNélio Laranjeiro 				}
1844ea3bc3b1SNélio Laranjeiro 			}
184548dfc20fSYongseok Koh 			if (rxq->csum | rxq->csum_l2tun)
18466703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
18476703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
18486703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
18496b30a6a8SShachar Beiser 			     rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
1850380a7aabSOlivier Matz 				pkt->ol_flags |= PKT_RX_VLAN |
1851b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
18526b30a6a8SShachar Beiser 				pkt->vlan_tci =
18536b30a6a8SShachar Beiser 					rte_be_to_cpu_16(cqe->vlan_info);
1854f3db9489SYaacov Hazan 			}
185578c7406bSRaslan Darawsheh 			if (rxq->hw_timestamp) {
185678c7406bSRaslan Darawsheh 				pkt->timestamp =
185778c7406bSRaslan Darawsheh 					rte_be_to_cpu_64(cqe->timestamp);
185878c7406bSRaslan Darawsheh 				pkt->ol_flags |= PKT_RX_TIMESTAMP;
185978c7406bSRaslan Darawsheh 			}
18606218063bSNélio Laranjeiro 			if (rxq->crc_present)
18616218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
18626218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
18639964b965SNélio Laranjeiro 		}
18649964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
18659964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
18669964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
18679964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
18689964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
18699964b965SNélio Laranjeiro 		/*
18709964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
18719964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
18729964b965SNélio Laranjeiro 		 * changes.
18739964b965SNélio Laranjeiro 		 */
18746b30a6a8SShachar Beiser 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
18759964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
18769964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
18779964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
18789964b965SNélio Laranjeiro 			++rq_ci;
18799964b965SNélio Laranjeiro 			continue;
18809964b965SNélio Laranjeiro 		}
18819964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
188287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
188387011737SAdrien Mazarguil 		/* Increment bytes counter. */
18849964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
188587011737SAdrien Mazarguil #endif
18866218063bSNélio Laranjeiro 		/* Return packet. */
18876218063bSNélio Laranjeiro 		*(pkts++) = pkt;
18889964b965SNélio Laranjeiro 		pkt = NULL;
18899964b965SNélio Laranjeiro 		--pkts_n;
18909964b965SNélio Laranjeiro 		++i;
189199c12dccSNélio Laranjeiro skip:
18929964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
18939964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
18946218063bSNélio Laranjeiro 		++rq_ci;
18959964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
18962e22920bSAdrien Mazarguil 	}
18979964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
18982e22920bSAdrien Mazarguil 		return 0;
18996218063bSNélio Laranjeiro 	/* Update the consumer index. */
19009964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
19019afa3f74SYongseok Koh 	rte_io_wmb();
19026b30a6a8SShachar Beiser 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
19039afa3f74SYongseok Koh 	rte_io_wmb();
19046b30a6a8SShachar Beiser 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
190587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
190687011737SAdrien Mazarguil 	/* Increment packets counter. */
19079964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
190887011737SAdrien Mazarguil #endif
19099964b965SNélio Laranjeiro 	return i;
19102e22920bSAdrien Mazarguil }
19112e22920bSAdrien Mazarguil 
19122e22920bSAdrien Mazarguil /**
19132e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
19142e22920bSAdrien Mazarguil  *
19152e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19162e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19172e22920bSAdrien Mazarguil  *
19182e22920bSAdrien Mazarguil  * @param dpdk_txq
19192e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
19202e22920bSAdrien Mazarguil  * @param[in] pkts
19212e22920bSAdrien Mazarguil  *   Packets to transmit.
19222e22920bSAdrien Mazarguil  * @param pkts_n
19232e22920bSAdrien Mazarguil  *   Number of packets in array.
19242e22920bSAdrien Mazarguil  *
19252e22920bSAdrien Mazarguil  * @return
19262e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
19272e22920bSAdrien Mazarguil  */
19282e22920bSAdrien Mazarguil uint16_t
19292e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19302e22920bSAdrien Mazarguil {
19312e22920bSAdrien Mazarguil 	(void)dpdk_txq;
19322e22920bSAdrien Mazarguil 	(void)pkts;
19332e22920bSAdrien Mazarguil 	(void)pkts_n;
19342e22920bSAdrien Mazarguil 	return 0;
19352e22920bSAdrien Mazarguil }
19362e22920bSAdrien Mazarguil 
19372e22920bSAdrien Mazarguil /**
19382e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
19392e22920bSAdrien Mazarguil  *
19402e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
19412e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
19422e22920bSAdrien Mazarguil  *
19432e22920bSAdrien Mazarguil  * @param dpdk_rxq
19442e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
19452e22920bSAdrien Mazarguil  * @param[out] pkts
19462e22920bSAdrien Mazarguil  *   Array to store received packets.
19472e22920bSAdrien Mazarguil  * @param pkts_n
19482e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
19492e22920bSAdrien Mazarguil  *
19502e22920bSAdrien Mazarguil  * @return
19512e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
19522e22920bSAdrien Mazarguil  */
19532e22920bSAdrien Mazarguil uint16_t
19542e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19552e22920bSAdrien Mazarguil {
19562e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
19572e22920bSAdrien Mazarguil 	(void)pkts;
19582e22920bSAdrien Mazarguil 	(void)pkts_n;
19592e22920bSAdrien Mazarguil 	return 0;
19602e22920bSAdrien Mazarguil }
19616cb559d6SYongseok Koh 
19626cb559d6SYongseok Koh /*
19636cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
19646cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
19656cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
19666cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
19676cb559d6SYongseok Koh  */
19686cb559d6SYongseok Koh 
19696cb559d6SYongseok Koh uint16_t __attribute__((weak))
19706cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19716cb559d6SYongseok Koh {
19726cb559d6SYongseok Koh 	(void)dpdk_txq;
19736cb559d6SYongseok Koh 	(void)pkts;
19746cb559d6SYongseok Koh 	(void)pkts_n;
19756cb559d6SYongseok Koh 	return 0;
19766cb559d6SYongseok Koh }
19776cb559d6SYongseok Koh 
19786cb559d6SYongseok Koh uint16_t __attribute__((weak))
19796cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19806cb559d6SYongseok Koh {
19816cb559d6SYongseok Koh 	(void)dpdk_txq;
19826cb559d6SYongseok Koh 	(void)pkts;
19836cb559d6SYongseok Koh 	(void)pkts_n;
19846cb559d6SYongseok Koh 	return 0;
19856cb559d6SYongseok Koh }
19866cb559d6SYongseok Koh 
19876cb559d6SYongseok Koh uint16_t __attribute__((weak))
19886cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19896cb559d6SYongseok Koh {
19906cb559d6SYongseok Koh 	(void)dpdk_rxq;
19916cb559d6SYongseok Koh 	(void)pkts;
19926cb559d6SYongseok Koh 	(void)pkts_n;
19936cb559d6SYongseok Koh 	return 0;
19946cb559d6SYongseok Koh }
19956cb559d6SYongseok Koh 
19966cb559d6SYongseok Koh int __attribute__((weak))
1997*dbccb4cdSShahaf Shuler priv_check_raw_vec_tx_support(struct priv *priv, struct rte_eth_dev *dev)
19986cb559d6SYongseok Koh {
19996cb559d6SYongseok Koh 	(void)priv;
2000*dbccb4cdSShahaf Shuler 	(void)dev;
20016cb559d6SYongseok Koh 	return -ENOTSUP;
20026cb559d6SYongseok Koh }
20036cb559d6SYongseok Koh 
20046cb559d6SYongseok Koh int __attribute__((weak))
2005*dbccb4cdSShahaf Shuler priv_check_vec_tx_support(struct priv *priv, struct rte_eth_dev *dev)
20066cb559d6SYongseok Koh {
20076cb559d6SYongseok Koh 	(void)priv;
2008*dbccb4cdSShahaf Shuler 	(void)dev;
20096cb559d6SYongseok Koh 	return -ENOTSUP;
20106cb559d6SYongseok Koh }
20116cb559d6SYongseok Koh 
20126cb559d6SYongseok Koh int __attribute__((weak))
201378142aacSNélio Laranjeiro rxq_check_vec_support(struct mlx5_rxq_data *rxq)
20146cb559d6SYongseok Koh {
20156cb559d6SYongseok Koh 	(void)rxq;
20166cb559d6SYongseok Koh 	return -ENOTSUP;
20176cb559d6SYongseok Koh }
20186cb559d6SYongseok Koh 
20196cb559d6SYongseok Koh int __attribute__((weak))
20206cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv)
20216cb559d6SYongseok Koh {
20226cb559d6SYongseok Koh 	(void)priv;
20236cb559d6SYongseok Koh 	return -ENOTSUP;
20246cb559d6SYongseok Koh }
2025