xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 48dfc20f1e456a69ec3f7c7a06319107d0f78e8e)
12e22920bSAdrien Mazarguil /*-
22e22920bSAdrien Mazarguil  *   BSD LICENSE
32e22920bSAdrien Mazarguil  *
42e22920bSAdrien Mazarguil  *   Copyright 2015 6WIND S.A.
52e22920bSAdrien Mazarguil  *   Copyright 2015 Mellanox.
62e22920bSAdrien Mazarguil  *
72e22920bSAdrien Mazarguil  *   Redistribution and use in source and binary forms, with or without
82e22920bSAdrien Mazarguil  *   modification, are permitted provided that the following conditions
92e22920bSAdrien Mazarguil  *   are met:
102e22920bSAdrien Mazarguil  *
112e22920bSAdrien Mazarguil  *     * Redistributions of source code must retain the above copyright
122e22920bSAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer.
132e22920bSAdrien Mazarguil  *     * Redistributions in binary form must reproduce the above copyright
142e22920bSAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer in
152e22920bSAdrien Mazarguil  *       the documentation and/or other materials provided with the
162e22920bSAdrien Mazarguil  *       distribution.
172e22920bSAdrien Mazarguil  *     * Neither the name of 6WIND S.A. nor the names of its
182e22920bSAdrien Mazarguil  *       contributors may be used to endorse or promote products derived
192e22920bSAdrien Mazarguil  *       from this software without specific prior written permission.
202e22920bSAdrien Mazarguil  *
212e22920bSAdrien Mazarguil  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
222e22920bSAdrien Mazarguil  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
232e22920bSAdrien Mazarguil  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
242e22920bSAdrien Mazarguil  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
252e22920bSAdrien Mazarguil  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
262e22920bSAdrien Mazarguil  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
272e22920bSAdrien Mazarguil  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
282e22920bSAdrien Mazarguil  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
292e22920bSAdrien Mazarguil  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
302e22920bSAdrien Mazarguil  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
312e22920bSAdrien Mazarguil  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322e22920bSAdrien Mazarguil  */
332e22920bSAdrien Mazarguil 
342e22920bSAdrien Mazarguil #include <assert.h>
352e22920bSAdrien Mazarguil #include <stdint.h>
362e22920bSAdrien Mazarguil #include <string.h>
372e22920bSAdrien Mazarguil #include <stdlib.h>
382e22920bSAdrien Mazarguil 
392e22920bSAdrien Mazarguil /* Verbs header. */
402e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
412e22920bSAdrien Mazarguil #ifdef PEDANTIC
42fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic"
432e22920bSAdrien Mazarguil #endif
442e22920bSAdrien Mazarguil #include <infiniband/verbs.h>
456218063bSNélio Laranjeiro #include <infiniband/mlx5_hw.h>
466218063bSNélio Laranjeiro #include <infiniband/arch.h>
472e22920bSAdrien Mazarguil #ifdef PEDANTIC
48fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
492e22920bSAdrien Mazarguil #endif
502e22920bSAdrien Mazarguil 
512e22920bSAdrien Mazarguil /* DPDK headers don't like -pedantic. */
522e22920bSAdrien Mazarguil #ifdef PEDANTIC
53fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic"
542e22920bSAdrien Mazarguil #endif
552e22920bSAdrien Mazarguil #include <rte_mbuf.h>
562e22920bSAdrien Mazarguil #include <rte_mempool.h>
572e22920bSAdrien Mazarguil #include <rte_prefetch.h>
582e22920bSAdrien Mazarguil #include <rte_common.h>
592e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
606218063bSNélio Laranjeiro #include <rte_ether.h>
612e22920bSAdrien Mazarguil #ifdef PEDANTIC
62fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic"
632e22920bSAdrien Mazarguil #endif
642e22920bSAdrien Mazarguil 
652e22920bSAdrien Mazarguil #include "mlx5.h"
662e22920bSAdrien Mazarguil #include "mlx5_utils.h"
672e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
68f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
692e22920bSAdrien Mazarguil #include "mlx5_defs.h"
706218063bSNélio Laranjeiro #include "mlx5_prm.h"
716218063bSNélio Laranjeiro 
72c0583d98SJerin Jacob static __rte_always_inline uint32_t
73c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe);
74ff1807a3SNélio Laranjeiro 
75c0583d98SJerin Jacob static __rte_always_inline int
76ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
77c0583d98SJerin Jacob 		 uint16_t cqe_cnt, uint32_t *rss_hash);
78ff1807a3SNélio Laranjeiro 
79c0583d98SJerin Jacob static __rte_always_inline uint32_t
80c0583d98SJerin Jacob rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe);
81ff1807a3SNélio Laranjeiro 
826cb559d6SYongseok Koh /*
836cb559d6SYongseok Koh  * The index to the array should have:
846cb559d6SYongseok Koh  * bit[1:0] = l3_hdr_type, bit[2] = tunneled, bit[3] = outer_l3_type
8599c12dccSNélio Laranjeiro  */
866cb559d6SYongseok Koh const uint32_t mlx5_ptype_table[] = {
876cb559d6SYongseok Koh 	RTE_PTYPE_UNKNOWN,
886cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,               /* b0001 */
896cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,               /* b0010 */
906cb559d6SYongseok Koh 	RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN,
916cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
926cb559d6SYongseok Koh 		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, /* b0101 */
936cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
946cb559d6SYongseok Koh 		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, /* b0110 */
956cb559d6SYongseok Koh 	RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN,
966cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,               /* b1001 */
976cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,               /* b1010 */
986cb559d6SYongseok Koh 	RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN,
996cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1006cb559d6SYongseok Koh 		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, /* b1101 */
1016cb559d6SYongseok Koh 	RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1026cb559d6SYongseok Koh 		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, /* b1110 */
1036cb559d6SYongseok Koh 	RTE_PTYPE_ALL_MASK			     /* b1111 */
1046cb559d6SYongseok Koh };
105fdcb0f53SNélio Laranjeiro 
1062e22920bSAdrien Mazarguil /**
1076ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
1086ce84bd8SYongseok Koh  *
1096ce84bd8SYongseok Koh  * @param txq
1106ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
1116ce84bd8SYongseok Koh  * @param addr
1126ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
1136ce84bd8SYongseok Koh  *
1146ce84bd8SYongseok Koh  * @return
1156ce84bd8SYongseok Koh  *   Size of tailroom.
1166ce84bd8SYongseok Koh  */
1176ce84bd8SYongseok Koh static inline size_t
1186ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr)
1196ce84bd8SYongseok Koh {
1206ce84bd8SYongseok Koh 	size_t tailroom;
1216ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
1226ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
1236ce84bd8SYongseok Koh 		   (uintptr_t)addr;
1246ce84bd8SYongseok Koh 	return tailroom;
1256ce84bd8SYongseok Koh }
1266ce84bd8SYongseok Koh 
1276ce84bd8SYongseok Koh /**
1286ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
1296ce84bd8SYongseok Koh  *
1306ce84bd8SYongseok Koh  * @param dst
1316ce84bd8SYongseok Koh  *   Pointer to destination.
1326ce84bd8SYongseok Koh  * @param src
1336ce84bd8SYongseok Koh  *   Pointer to source.
1346ce84bd8SYongseok Koh  * @param n
1356ce84bd8SYongseok Koh  *   Number of bytes to copy.
1366ce84bd8SYongseok Koh  * @param base
1376ce84bd8SYongseok Koh  *   Pointer to head of queue.
1386ce84bd8SYongseok Koh  * @param tailroom
1396ce84bd8SYongseok Koh  *   Size of tailroom from dst.
1406ce84bd8SYongseok Koh  *
1416ce84bd8SYongseok Koh  * @return
1426ce84bd8SYongseok Koh  *   Pointer after copied data.
1436ce84bd8SYongseok Koh  */
1446ce84bd8SYongseok Koh static inline void *
1456ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
1466ce84bd8SYongseok Koh 		void *base, size_t tailroom)
1476ce84bd8SYongseok Koh {
1486ce84bd8SYongseok Koh 	void *ret;
1496ce84bd8SYongseok Koh 
1506ce84bd8SYongseok Koh 	if (n > tailroom) {
1516ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
1526ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
1536ce84bd8SYongseok Koh 			   n - tailroom);
1546ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
1556ce84bd8SYongseok Koh 	} else {
1566ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
1576ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
1586ce84bd8SYongseok Koh 	}
1596ce84bd8SYongseok Koh 	return ret;
1606ce84bd8SYongseok Koh }
1616ce84bd8SYongseok Koh 
1626ce84bd8SYongseok Koh /**
1638788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
1648788fec1SOlivier Matz  *
1658788fec1SOlivier Matz  * @param tx_queue
1668788fec1SOlivier Matz  *   The tx queue.
1678788fec1SOlivier Matz  * @param[in] offset
1688788fec1SOlivier Matz  *   The index of the descriptor in the ring.
1698788fec1SOlivier Matz  *
1708788fec1SOlivier Matz  * @return
1718788fec1SOlivier Matz  *   The status of the tx descriptor.
1728788fec1SOlivier Matz  */
1738788fec1SOlivier Matz int
1748788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
1758788fec1SOlivier Matz {
1768788fec1SOlivier Matz 	struct txq *txq = tx_queue;
1778c819a69SYongseok Koh 	uint16_t used;
1788788fec1SOlivier Matz 
1796cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
1808c819a69SYongseok Koh 	used = txq->elts_head - txq->elts_tail;
1818788fec1SOlivier Matz 	if (offset < used)
1828788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
1838788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
1848788fec1SOlivier Matz }
1858788fec1SOlivier Matz 
1868788fec1SOlivier Matz /**
1878788fec1SOlivier Matz  * DPDK callback to check the status of a rx descriptor.
1888788fec1SOlivier Matz  *
1898788fec1SOlivier Matz  * @param rx_queue
1908788fec1SOlivier Matz  *   The rx queue.
1918788fec1SOlivier Matz  * @param[in] offset
1928788fec1SOlivier Matz  *   The index of the descriptor in the ring.
1938788fec1SOlivier Matz  *
1948788fec1SOlivier Matz  * @return
1958788fec1SOlivier Matz  *   The status of the tx descriptor.
1968788fec1SOlivier Matz  */
1978788fec1SOlivier Matz int
1988788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
1998788fec1SOlivier Matz {
2008788fec1SOlivier Matz 	struct rxq *rxq = rx_queue;
2018788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
2028788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
2038788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
2048788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
2058788fec1SOlivier Matz 	unsigned int cq_ci;
2068788fec1SOlivier Matz 	unsigned int used;
2078788fec1SOlivier Matz 
2088788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
2098788fec1SOlivier Matz 	if (zip->ai) {
2108788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
2118788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
2128788fec1SOlivier Matz 	} else {
2138788fec1SOlivier Matz 		used = 0;
2148788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
2158788fec1SOlivier Matz 	}
2168788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
2178788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
2188788fec1SOlivier Matz 		int8_t op_own;
2198788fec1SOlivier Matz 		unsigned int n;
2208788fec1SOlivier Matz 
2218788fec1SOlivier Matz 		op_own = cqe->op_own;
2228788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
2238788fec1SOlivier Matz 			n = ntohl(cqe->byte_cnt);
2248788fec1SOlivier Matz 		else
2258788fec1SOlivier Matz 			n = 1;
2268788fec1SOlivier Matz 		cq_ci += n;
2278788fec1SOlivier Matz 		used += n;
2288788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
2298788fec1SOlivier Matz 	}
2308788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
2318788fec1SOlivier Matz 	if (offset < used)
2328788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
2338788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
2348788fec1SOlivier Matz }
2358788fec1SOlivier Matz 
2368788fec1SOlivier Matz /**
2372e22920bSAdrien Mazarguil  * DPDK callback for TX.
2382e22920bSAdrien Mazarguil  *
2392e22920bSAdrien Mazarguil  * @param dpdk_txq
2402e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
2412e22920bSAdrien Mazarguil  * @param[in] pkts
2422e22920bSAdrien Mazarguil  *   Packets to transmit.
2432e22920bSAdrien Mazarguil  * @param pkts_n
2442e22920bSAdrien Mazarguil  *   Number of packets in array.
2452e22920bSAdrien Mazarguil  *
2462e22920bSAdrien Mazarguil  * @return
2472e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
2482e22920bSAdrien Mazarguil  */
2492e22920bSAdrien Mazarguil uint16_t
2502e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
2512e22920bSAdrien Mazarguil {
2522e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
2531d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
2548c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
2558c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
256c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
257a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
2583f13f8c2SShahaf Shuler 	unsigned int k = 0;
2598c819a69SYongseok Koh 	uint16_t max_elts;
260ab76eab3SYongseok Koh 	unsigned int max_inline = txq->max_inline;
261ab76eab3SYongseok Koh 	const unsigned int inline_en = !!max_inline && txq->inline_en;
262f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
263c305090bSAdrien Mazarguil 	unsigned int comp;
2649a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
265ac180a21SYongseok Koh 	volatile struct mlx5_wqe_ctrl *last_wqe = NULL;
2666579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
2676579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
2686579c27cSNélio Laranjeiro 	uint8_t *raw;
2692e22920bSAdrien Mazarguil 
2701d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
2711d88ba17SNélio Laranjeiro 		return 0;
2725e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
273c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
2741d88ba17SNélio Laranjeiro 	/* Start processing. */
2756cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
2768c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
277f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
278f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
279f04f1d51SNélio Laranjeiro 		return 0;
280c3d62cc9SAdrien Mazarguil 	do {
2819a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
282573f54afSNélio Laranjeiro 		uint32_t length;
2838688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
284ac180a21SYongseok Koh 		unsigned int sg = 0; /* counter of additional segs attached. */
2856579c27cSNélio Laranjeiro 		uintptr_t addr;
2869a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
2870d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
2883f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
289eef822ddSNélio Laranjeiro 		uint16_t ehdr;
2909a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
2913f13f8c2SShahaf Shuler 		uint64_t tso = 0;
29283daf156SShahaf Shuler 		uint16_t tso_segsz = 0;
2936579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
2946579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
2956579c27cSNélio Laranjeiro #endif
2962e22920bSAdrien Mazarguil 
2976579c27cSNélio Laranjeiro 		/* first_seg */
2983730e6c6SYongseok Koh 		buf = *pkts;
2996579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
300c3d62cc9SAdrien Mazarguil 		/*
301c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
302c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
303c3d62cc9SAdrien Mazarguil 		 */
304a5bf6af9SAdrien Mazarguil 		assert(segs_n);
3058c819a69SYongseok Koh 		if (max_elts < segs_n)
306c3d62cc9SAdrien Mazarguil 			break;
3078c819a69SYongseok Koh 		max_elts -= segs_n;
3086579c27cSNélio Laranjeiro 		--segs_n;
309f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
310f04f1d51SNélio Laranjeiro 			break;
3119a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
312fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
313fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
3143730e6c6SYongseok Koh 		if (pkts_n - i > 1)
3153730e6c6SYongseok Koh 			rte_prefetch0(*(pkts + 1));
3166579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
3172e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
318eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
319eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
3206579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
3216579c27cSNélio Laranjeiro 		total_length = length;
3226579c27cSNélio Laranjeiro #endif
323959be52eSNélio Laranjeiro 		if (length < (MLX5_WQE_DWORD_SIZE + 2))
324959be52eSNélio Laranjeiro 			break;
3252e22920bSAdrien Mazarguil 		/* Update element. */
3268c819a69SYongseok Koh 		(*txq->elts)[elts_head & elts_m] = buf;
3275e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
3283730e6c6SYongseok Koh 		if (pkts_n - i > 1)
3293730e6c6SYongseok Koh 			rte_prefetch0(
3303730e6c6SYongseok Koh 			    rte_pktmbuf_mtod(*(pkts + 1), volatile void *));
3311d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
3321d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
3331d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
334f5fde520SShahaf Shuler 			const uint64_t is_tunneled = buf->ol_flags &
335f5fde520SShahaf Shuler 						     (PKT_TX_TUNNEL_GRE |
336f5fde520SShahaf Shuler 						      PKT_TX_TUNNEL_VXLAN);
337f5fde520SShahaf Shuler 
338f5fde520SShahaf Shuler 			if (is_tunneled && txq->tunnel_en) {
339f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM |
340f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_INNER_CSUM;
341f5fde520SShahaf Shuler 				if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
342f5fde520SShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L3_CSUM;
343f5fde520SShahaf Shuler 			} else {
344f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_CSUM |
345f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_CSUM;
346f5fde520SShahaf Shuler 			}
3471d88ba17SNélio Laranjeiro 		}
348b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
3496579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
3506579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
3516579c27cSNélio Laranjeiro 			uint32_t vlan = htonl(0x81000000 | buf->vlan_tci);
3520d637a34SNélio Laranjeiro 			unsigned int len = 2 * ETHER_ADDR_LEN - 2;
3536579c27cSNélio Laranjeiro 
3540d637a34SNélio Laranjeiro 			addr += 2;
3550d637a34SNélio Laranjeiro 			length -= 2;
3560d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
3570d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
3580d637a34SNélio Laranjeiro 			/* Copy VLAN. */
3590d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
3600d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
3610d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
3620d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
3630d637a34SNélio Laranjeiro 			addr += len + 2;
3640d637a34SNélio Laranjeiro 			length -= (len + 2);
3650d637a34SNélio Laranjeiro 		} else {
3660d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
3670d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
3680d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
3690d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
3706579c27cSNélio Laranjeiro 		}
3713f13f8c2SShahaf Shuler 		if (txq->tso_en) {
3723f13f8c2SShahaf Shuler 			tso = buf->ol_flags & PKT_TX_TCP_SEG;
3733f13f8c2SShahaf Shuler 			if (tso) {
3743f13f8c2SShahaf Shuler 				uintptr_t end = (uintptr_t)
3753f13f8c2SShahaf Shuler 						(((uintptr_t)txq->wqes) +
3763f13f8c2SShahaf Shuler 						(1 << txq->wqe_n) *
3773f13f8c2SShahaf Shuler 						MLX5_WQE_SIZE);
3783f13f8c2SShahaf Shuler 				unsigned int copy_b;
3793f13f8c2SShahaf Shuler 				uint8_t vlan_sz = (buf->ol_flags &
3803f13f8c2SShahaf Shuler 						  PKT_TX_VLAN_PKT) ? 4 : 0;
381b247f346SShahaf Shuler 				const uint64_t is_tunneled =
382b247f346SShahaf Shuler 							buf->ol_flags &
383b247f346SShahaf Shuler 							(PKT_TX_TUNNEL_GRE |
384b247f346SShahaf Shuler 							 PKT_TX_TUNNEL_VXLAN);
3853f13f8c2SShahaf Shuler 
3863f13f8c2SShahaf Shuler 				tso_header_sz = buf->l2_len + vlan_sz +
3873f13f8c2SShahaf Shuler 						buf->l3_len + buf->l4_len;
38883daf156SShahaf Shuler 				tso_segsz = buf->tso_segsz;
3893f13f8c2SShahaf Shuler 
390b247f346SShahaf Shuler 				if (is_tunneled	&& txq->tunnel_en) {
391b247f346SShahaf Shuler 					tso_header_sz += buf->outer_l2_len +
392b247f346SShahaf Shuler 							 buf->outer_l3_len;
3932a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
3942a6c96beSShahaf Shuler 				} else {
3952a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_CSUM;
396b247f346SShahaf Shuler 				}
3973f13f8c2SShahaf Shuler 				if (unlikely(tso_header_sz >
3983f13f8c2SShahaf Shuler 					     MLX5_MAX_TSO_HEADER))
3993f13f8c2SShahaf Shuler 					break;
4003f13f8c2SShahaf Shuler 				copy_b = tso_header_sz - pkt_inline_sz;
4013f13f8c2SShahaf Shuler 				/* First seg must contain all headers. */
4023f13f8c2SShahaf Shuler 				assert(copy_b <= length);
4033f13f8c2SShahaf Shuler 				raw += MLX5_WQE_DWORD_SIZE;
4043f13f8c2SShahaf Shuler 				if (copy_b &&
4053f13f8c2SShahaf Shuler 				   ((end - (uintptr_t)raw) > copy_b)) {
4063f13f8c2SShahaf Shuler 					uint16_t n = (MLX5_WQE_DS(copy_b) -
4073f13f8c2SShahaf Shuler 						      1 + 3) / 4;
4083f13f8c2SShahaf Shuler 
4093f13f8c2SShahaf Shuler 					if (unlikely(max_wqe < n))
4103f13f8c2SShahaf Shuler 						break;
4113f13f8c2SShahaf Shuler 					max_wqe -= n;
4123f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
4133f13f8c2SShahaf Shuler 						   (void *)addr, copy_b);
4143f13f8c2SShahaf Shuler 					addr += copy_b;
4153f13f8c2SShahaf Shuler 					length -= copy_b;
4163f13f8c2SShahaf Shuler 					pkt_inline_sz += copy_b;
4173f13f8c2SShahaf Shuler 					/*
4183f13f8c2SShahaf Shuler 					 * Another DWORD will be added
4193f13f8c2SShahaf Shuler 					 * in the inline part.
4203f13f8c2SShahaf Shuler 					 */
4213f13f8c2SShahaf Shuler 					raw += MLX5_WQE_DS(copy_b) *
4223f13f8c2SShahaf Shuler 					       MLX5_WQE_DWORD_SIZE -
4233f13f8c2SShahaf Shuler 					       MLX5_WQE_DWORD_SIZE;
4243f13f8c2SShahaf Shuler 				} else {
4253f13f8c2SShahaf Shuler 					/* NOP WQE. */
4263f13f8c2SShahaf Shuler 					wqe->ctrl = (rte_v128u32_t){
4273f13f8c2SShahaf Shuler 						     htonl(txq->wqe_ci << 8),
4283f13f8c2SShahaf Shuler 						     htonl(txq->qp_num_8s | 1),
4293f13f8c2SShahaf Shuler 						     0,
4303f13f8c2SShahaf Shuler 						     0,
4313f13f8c2SShahaf Shuler 					};
4323f13f8c2SShahaf Shuler 					ds = 1;
4333f13f8c2SShahaf Shuler 					total_length = 0;
4343f13f8c2SShahaf Shuler 					k++;
4353f13f8c2SShahaf Shuler 					goto next_wqe;
4363f13f8c2SShahaf Shuler 				}
4373f13f8c2SShahaf Shuler 			}
4383f13f8c2SShahaf Shuler 		}
4396579c27cSNélio Laranjeiro 		/* Inline if enough room. */
440ab76eab3SYongseok Koh 		if (inline_en || tso) {
441fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
442fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
443fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
444ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
4458fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
4463f13f8c2SShahaf Shuler 						   (pkt_inline_sz - 2);
447ab76eab3SYongseok Koh 			uintptr_t addr_end = (addr + inline_room) &
4486579c27cSNélio Laranjeiro 					     ~(RTE_CACHE_LINE_SIZE - 1);
4498fcd6c2cSNélio Laranjeiro 			unsigned int copy_b = (addr_end > addr) ?
4508fcd6c2cSNélio Laranjeiro 				RTE_MIN((addr_end - addr), length) :
4518fcd6c2cSNélio Laranjeiro 				0;
4526579c27cSNélio Laranjeiro 
4538fcd6c2cSNélio Laranjeiro 			raw += MLX5_WQE_DWORD_SIZE;
4548fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
455f04f1d51SNélio Laranjeiro 				/*
456f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
457f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
458f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
459f04f1d51SNélio Laranjeiro 				 */
4608fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
4618fcd6c2cSNélio Laranjeiro 
462f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
463f04f1d51SNélio Laranjeiro 					break;
464f04f1d51SNélio Laranjeiro 				max_wqe -= n;
4653f13f8c2SShahaf Shuler 				if (tso) {
4663f13f8c2SShahaf Shuler 					uint32_t inl =
4673f13f8c2SShahaf Shuler 						htonl(copy_b | MLX5_INLINE_SEG);
4683f13f8c2SShahaf Shuler 
4693f13f8c2SShahaf Shuler 					pkt_inline_sz =
4703f13f8c2SShahaf Shuler 						MLX5_WQE_DS(tso_header_sz) *
4713f13f8c2SShahaf Shuler 						MLX5_WQE_DWORD_SIZE;
4723f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
4733f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
4743f13f8c2SShahaf Shuler 					raw += sizeof(inl);
4753f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
4763f13f8c2SShahaf Shuler 				}
4776579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
4786579c27cSNélio Laranjeiro 				addr += copy_b;
4796579c27cSNélio Laranjeiro 				length -= copy_b;
4806579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
4816579c27cSNélio Laranjeiro 			}
4826579c27cSNélio Laranjeiro 			/*
483786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
4846579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
4856579c27cSNélio Laranjeiro 			 */
4866579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
4876579c27cSNélio Laranjeiro 			if (length > 0) {
488f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
489f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
490f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
491f04f1d51SNélio Laranjeiro 						break;
492f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
493f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
494f04f1d51SNélio Laranjeiro 							   ds / 4);
495f04f1d51SNélio Laranjeiro 				} else {
4969a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
4976579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
4986579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
499f04f1d51SNélio Laranjeiro 				}
5006579c27cSNélio Laranjeiro 				goto use_dseg;
5016579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5026579c27cSNélio Laranjeiro 				goto next_pkt;
5036579c27cSNélio Laranjeiro 			} else {
504786b5c2dSShahaf Shuler 				/* dseg will be advance as part of next_seg */
505786b5c2dSShahaf Shuler 				dseg = (volatile rte_v128u32_t *)
506786b5c2dSShahaf Shuler 					((uintptr_t)wqe +
507786b5c2dSShahaf Shuler 					 ((ds - 1) * MLX5_WQE_DWORD_SIZE));
5086579c27cSNélio Laranjeiro 				goto next_seg;
5096579c27cSNélio Laranjeiro 			}
5106579c27cSNélio Laranjeiro 		} else {
5116579c27cSNélio Laranjeiro 			/*
5126579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
5136579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
5146579c27cSNélio Laranjeiro 			 */
5159a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
5166579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
5176579c27cSNélio Laranjeiro 			ds = 3;
5186579c27cSNélio Laranjeiro use_dseg:
5196579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
5209a7fa9f7SNélio Laranjeiro 			naddr = htonll(addr);
5219a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
5229a7fa9f7SNélio Laranjeiro 				htonl(length),
5236cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
5249a7fa9f7SNélio Laranjeiro 				naddr,
5259a7fa9f7SNélio Laranjeiro 				naddr >> 32,
5266579c27cSNélio Laranjeiro 			};
5276579c27cSNélio Laranjeiro 			++ds;
5286579c27cSNélio Laranjeiro 			if (!segs_n)
5296579c27cSNélio Laranjeiro 				goto next_pkt;
5306579c27cSNélio Laranjeiro 		}
5316579c27cSNélio Laranjeiro next_seg:
5326579c27cSNélio Laranjeiro 		assert(buf);
5336579c27cSNélio Laranjeiro 		assert(ds);
5346579c27cSNélio Laranjeiro 		assert(wqe);
535a5bf6af9SAdrien Mazarguil 		/*
536a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
537a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
538a5bf6af9SAdrien Mazarguil 		 * of data segment size.
539a5bf6af9SAdrien Mazarguil 		 */
5408688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
5416579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
542f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
543f04f1d51SNélio Laranjeiro 				break;
5449a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
545f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
546f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
547f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
5486579c27cSNélio Laranjeiro 		} else {
549a5bf6af9SAdrien Mazarguil 			++dseg;
5506579c27cSNélio Laranjeiro 		}
551a5bf6af9SAdrien Mazarguil 		++ds;
552a5bf6af9SAdrien Mazarguil 		buf = buf->next;
553a5bf6af9SAdrien Mazarguil 		assert(buf);
5546579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
555a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
5566579c27cSNélio Laranjeiro 		total_length += length;
557a5bf6af9SAdrien Mazarguil #endif
5586579c27cSNélio Laranjeiro 		/* Store segment information. */
5599a7fa9f7SNélio Laranjeiro 		naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t));
5609a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
5619a7fa9f7SNélio Laranjeiro 			htonl(length),
5626cb559d6SYongseok Koh 			mlx5_tx_mb2mr(txq, buf),
5639a7fa9f7SNélio Laranjeiro 			naddr,
5649a7fa9f7SNélio Laranjeiro 			naddr >> 32,
5656579c27cSNélio Laranjeiro 		};
5668c819a69SYongseok Koh 		(*txq->elts)[++elts_head & elts_m] = buf;
567ac180a21SYongseok Koh 		++sg;
568ac180a21SYongseok Koh 		/* Advance counter only if all segs are successfully posted. */
5693730e6c6SYongseok Koh 		if (sg < segs_n)
5706579c27cSNélio Laranjeiro 			goto next_seg;
5713730e6c6SYongseok Koh 		else
572ac180a21SYongseok Koh 			j += sg;
5736579c27cSNélio Laranjeiro next_pkt:
5748c819a69SYongseok Koh 		++elts_head;
5753730e6c6SYongseok Koh 		++pkts;
5766579c27cSNélio Laranjeiro 		++i;
577b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
5783f13f8c2SShahaf Shuler 		if (tso) {
5793f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
5803f13f8c2SShahaf Shuler 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO),
5813f13f8c2SShahaf Shuler 				htonl(txq->qp_num_8s | ds),
5823f13f8c2SShahaf Shuler 				0,
5833f13f8c2SShahaf Shuler 				0,
5843f13f8c2SShahaf Shuler 			};
5853f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
5863f13f8c2SShahaf Shuler 				0,
58783daf156SShahaf Shuler 				cs_flags | (htons(tso_segsz) << 16),
5883f13f8c2SShahaf Shuler 				0,
5893f13f8c2SShahaf Shuler 				(ehdr << 16) | htons(tso_header_sz),
5903f13f8c2SShahaf Shuler 			};
5913f13f8c2SShahaf Shuler 		} else {
5929a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
5939a7fa9f7SNélio Laranjeiro 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
5949a7fa9f7SNélio Laranjeiro 				htonl(txq->qp_num_8s | ds),
5959a7fa9f7SNélio Laranjeiro 				0,
5969a7fa9f7SNélio Laranjeiro 				0,
5979a7fa9f7SNélio Laranjeiro 			};
5989a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
5999a7fa9f7SNélio Laranjeiro 				0,
6009a7fa9f7SNélio Laranjeiro 				cs_flags,
6019a7fa9f7SNélio Laranjeiro 				0,
602eef822ddSNélio Laranjeiro 				(ehdr << 16) | htons(pkt_inline_sz),
6039a7fa9f7SNélio Laranjeiro 			};
6043f13f8c2SShahaf Shuler 		}
6053f13f8c2SShahaf Shuler next_wqe:
6066579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
607ac180a21SYongseok Koh 		/* Save the last successful WQE for completion request */
608ac180a21SYongseok Koh 		last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe;
60987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
610573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
6116579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
61287011737SAdrien Mazarguil #endif
6133730e6c6SYongseok Koh 	} while (i < pkts_n);
6142e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
6153f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
6162e22920bSAdrien Mazarguil 		return 0;
6178c819a69SYongseok Koh 	txq->elts_head += (i + j);
618c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
6193f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
620c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
621c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
622ac180a21SYongseok Koh 		last_wqe->ctrl2 = htonl(8);
623c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
624ac180a21SYongseok Koh 		last_wqe->ctrl3 = txq->elts_head;
625c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
626c305090bSAdrien Mazarguil 	} else {
627c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
628c305090bSAdrien Mazarguil 	}
62987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
63087011737SAdrien Mazarguil 	/* Increment sent packets counter. */
63187011737SAdrien Mazarguil 	txq->stats.opackets += i;
63287011737SAdrien Mazarguil #endif
6332e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
634ac180a21SYongseok Koh 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe);
6352e22920bSAdrien Mazarguil 	return i;
6362e22920bSAdrien Mazarguil }
6372e22920bSAdrien Mazarguil 
6382e22920bSAdrien Mazarguil /**
639230189d9SNélio Laranjeiro  * Open a MPW session.
640230189d9SNélio Laranjeiro  *
641230189d9SNélio Laranjeiro  * @param txq
642230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
643230189d9SNélio Laranjeiro  * @param mpw
644230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
645230189d9SNélio Laranjeiro  * @param length
646230189d9SNélio Laranjeiro  *   Packet length.
647230189d9SNélio Laranjeiro  */
648230189d9SNélio Laranjeiro static inline void
649230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
650230189d9SNélio Laranjeiro {
651a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
652230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
653230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
654fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
655230189d9SNélio Laranjeiro 
656230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
657230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
658230189d9SNélio Laranjeiro 	mpw->len = length;
659230189d9SNélio Laranjeiro 	mpw->total_len = 0;
660fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
6618688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
6628688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
6638688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
6648688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
6658688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
6668688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
667c904ae25SNélio Laranjeiro 				  (txq->wqe_ci << 8) | MLX5_OPCODE_TSO);
6688688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
6698688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
6708688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
6718688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
6728688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
6738688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
674230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
675230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
676230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
677230189d9SNélio Laranjeiro }
678230189d9SNélio Laranjeiro 
679230189d9SNélio Laranjeiro /**
680230189d9SNélio Laranjeiro  * Close a MPW session.
681230189d9SNélio Laranjeiro  *
682230189d9SNélio Laranjeiro  * @param txq
683230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
684230189d9SNélio Laranjeiro  * @param mpw
685230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
686230189d9SNélio Laranjeiro  */
687230189d9SNélio Laranjeiro static inline void
688230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
689230189d9SNélio Laranjeiro {
690230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
691230189d9SNélio Laranjeiro 
692230189d9SNélio Laranjeiro 	/*
693230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
694230189d9SNélio Laranjeiro 	 * count as 2.
695230189d9SNélio Laranjeiro 	 */
6968688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num));
697230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
698230189d9SNélio Laranjeiro 	if (num < 3)
699230189d9SNélio Laranjeiro 		++txq->wqe_ci;
700230189d9SNélio Laranjeiro 	else
701230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
702fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
703fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
704230189d9SNélio Laranjeiro }
705230189d9SNélio Laranjeiro 
706230189d9SNélio Laranjeiro /**
707230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
708230189d9SNélio Laranjeiro  *
709230189d9SNélio Laranjeiro  * @param dpdk_txq
710230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
711230189d9SNélio Laranjeiro  * @param[in] pkts
712230189d9SNélio Laranjeiro  *   Packets to transmit.
713230189d9SNélio Laranjeiro  * @param pkts_n
714230189d9SNélio Laranjeiro  *   Number of packets in array.
715230189d9SNélio Laranjeiro  *
716230189d9SNélio Laranjeiro  * @return
717230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
718230189d9SNélio Laranjeiro  */
719230189d9SNélio Laranjeiro uint16_t
720230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
721230189d9SNélio Laranjeiro {
722230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
723230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
7248c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
7258c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
726c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
727a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
7288c819a69SYongseok Koh 	uint16_t max_elts;
729f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
730230189d9SNélio Laranjeiro 	unsigned int comp;
731230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
732230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
733230189d9SNélio Laranjeiro 	};
734230189d9SNélio Laranjeiro 
735c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
736c3d62cc9SAdrien Mazarguil 		return 0;
737230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
738fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
739fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
740230189d9SNélio Laranjeiro 	/* Start processing. */
7416cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
7428c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
743f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
744f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
745f04f1d51SNélio Laranjeiro 		return 0;
746c3d62cc9SAdrien Mazarguil 	do {
747a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
748230189d9SNélio Laranjeiro 		uint32_t length;
749a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
750230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
751230189d9SNélio Laranjeiro 
752c3d62cc9SAdrien Mazarguil 		/*
753c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
754c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
755c3d62cc9SAdrien Mazarguil 		 */
756a5bf6af9SAdrien Mazarguil 		assert(segs_n);
7578c819a69SYongseok Koh 		if (max_elts < segs_n)
758c3d62cc9SAdrien Mazarguil 			break;
759a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
760a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
761a5bf6af9SAdrien Mazarguil 			break;
7628c819a69SYongseok Koh 		max_elts -= segs_n;
763c3d62cc9SAdrien Mazarguil 		--pkts_n;
764230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
765230189d9SNélio Laranjeiro 		if (buf->ol_flags &
766230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
767230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
768a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
769a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
770a5bf6af9SAdrien Mazarguil 		assert(length);
771230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
772230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
773230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
774a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
7758688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
776230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
777230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
778f04f1d51SNélio Laranjeiro 			/*
779f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
780f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
781f04f1d51SNélio Laranjeiro 			 * resources.
782f04f1d51SNélio Laranjeiro 			 */
783f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
784f04f1d51SNélio Laranjeiro 				break;
785f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
786230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
7878688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
788230189d9SNélio Laranjeiro 		}
789a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
790a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
791a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
792a5bf6af9SAdrien Mazarguil 		length = 0;
793a5bf6af9SAdrien Mazarguil #endif
794a5bf6af9SAdrien Mazarguil 		do {
795a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
796a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
797a5bf6af9SAdrien Mazarguil 
798a5bf6af9SAdrien Mazarguil 			assert(buf);
7998c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
800230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
801a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
802230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
803a5bf6af9SAdrien Mazarguil 				.byte_count = htonl(DATA_LEN(buf)),
8046cb559d6SYongseok Koh 				.lkey = mlx5_tx_mb2mr(txq, buf),
805230189d9SNélio Laranjeiro 				.addr = htonll(addr),
806230189d9SNélio Laranjeiro 			};
807a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
808a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
809a5bf6af9SAdrien Mazarguil #endif
810a5bf6af9SAdrien Mazarguil 			buf = buf->next;
811230189d9SNélio Laranjeiro 			++mpw.pkts_n;
812a5bf6af9SAdrien Mazarguil 			++j;
813a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
814a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
815230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
816230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
817230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
818230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
819230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
820230189d9SNélio Laranjeiro #endif
821c3d62cc9SAdrien Mazarguil 		++i;
822c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
823230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
824230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
825230189d9SNélio Laranjeiro 		return 0;
826230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
827a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
828a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
829230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
8308688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
831230189d9SNélio Laranjeiro 
832230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
8338688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
834230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
8358688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
836230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
837230189d9SNélio Laranjeiro 	} else {
838230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
839230189d9SNélio Laranjeiro 	}
840230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
841230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
842230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
843230189d9SNélio Laranjeiro #endif
844230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
845230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
846230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
84730807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
848230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
849230189d9SNélio Laranjeiro 	return i;
850230189d9SNélio Laranjeiro }
851230189d9SNélio Laranjeiro 
852230189d9SNélio Laranjeiro /**
853230189d9SNélio Laranjeiro  * Open a MPW inline session.
854230189d9SNélio Laranjeiro  *
855230189d9SNélio Laranjeiro  * @param txq
856230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
857230189d9SNélio Laranjeiro  * @param mpw
858230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
859230189d9SNélio Laranjeiro  * @param length
860230189d9SNélio Laranjeiro  *   Packet length.
861230189d9SNélio Laranjeiro  */
862230189d9SNélio Laranjeiro static inline void
863230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
864230189d9SNélio Laranjeiro {
865a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
8668688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
867230189d9SNélio Laranjeiro 
868230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
869230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
870230189d9SNélio Laranjeiro 	mpw->len = length;
871230189d9SNélio Laranjeiro 	mpw->total_len = 0;
872fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
8738688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
874230189d9SNélio Laranjeiro 				  (txq->wqe_ci << 8) |
875c904ae25SNélio Laranjeiro 				  MLX5_OPCODE_TSO);
8768688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
8778688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
8788688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
8798688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
8808688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
8818688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
8828688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
8838688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
8848688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
8858688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
8868688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
887230189d9SNélio Laranjeiro }
888230189d9SNélio Laranjeiro 
889230189d9SNélio Laranjeiro /**
890230189d9SNélio Laranjeiro  * Close a MPW inline session.
891230189d9SNélio Laranjeiro  *
892230189d9SNélio Laranjeiro  * @param txq
893230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
894230189d9SNélio Laranjeiro  * @param mpw
895230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
896230189d9SNélio Laranjeiro  */
897230189d9SNélio Laranjeiro static inline void
898230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
899230189d9SNélio Laranjeiro {
900230189d9SNélio Laranjeiro 	unsigned int size;
9018688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
9028688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
903230189d9SNélio Laranjeiro 
9048688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
905230189d9SNélio Laranjeiro 	/*
906230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
907230189d9SNélio Laranjeiro 	 * count as 2.
908230189d9SNélio Laranjeiro 	 */
9098688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size));
910230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
9118688b2f8SNélio Laranjeiro 	inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG);
9128688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
913230189d9SNélio Laranjeiro }
914230189d9SNélio Laranjeiro 
915230189d9SNélio Laranjeiro /**
916230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
917230189d9SNélio Laranjeiro  *
918230189d9SNélio Laranjeiro  * @param dpdk_txq
919230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
920230189d9SNélio Laranjeiro  * @param[in] pkts
921230189d9SNélio Laranjeiro  *   Packets to transmit.
922230189d9SNélio Laranjeiro  * @param pkts_n
923230189d9SNélio Laranjeiro  *   Number of packets in array.
924230189d9SNélio Laranjeiro  *
925230189d9SNélio Laranjeiro  * @return
926230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
927230189d9SNélio Laranjeiro  */
928230189d9SNélio Laranjeiro uint16_t
929230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
930230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
931230189d9SNélio Laranjeiro {
932230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
933230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
9348c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
9358c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
936c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
937a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
9388c819a69SYongseok Koh 	uint16_t max_elts;
939f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
940230189d9SNélio Laranjeiro 	unsigned int comp;
9410e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
942230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
943230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
944230189d9SNélio Laranjeiro 	};
945f04f1d51SNélio Laranjeiro 	/*
946f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
947f04f1d51SNélio Laranjeiro 	 * code.
948f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
949f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
950f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
951f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
952f04f1d51SNélio Laranjeiro 	 */
953f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
954f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
955f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
956f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
957230189d9SNélio Laranjeiro 
958c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
959c3d62cc9SAdrien Mazarguil 		return 0;
960230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
961fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
962fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
963230189d9SNélio Laranjeiro 	/* Start processing. */
9646cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
9658c819a69SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
966c3d62cc9SAdrien Mazarguil 	do {
967a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
968230189d9SNélio Laranjeiro 		uintptr_t addr;
969230189d9SNélio Laranjeiro 		uint32_t length;
970a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
971230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
972230189d9SNélio Laranjeiro 
973c3d62cc9SAdrien Mazarguil 		/*
974c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
975c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
976c3d62cc9SAdrien Mazarguil 		 */
977a5bf6af9SAdrien Mazarguil 		assert(segs_n);
9788c819a69SYongseok Koh 		if (max_elts < segs_n)
979c3d62cc9SAdrien Mazarguil 			break;
980a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
981a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
982a5bf6af9SAdrien Mazarguil 			break;
9838c819a69SYongseok Koh 		max_elts -= segs_n;
984c3d62cc9SAdrien Mazarguil 		--pkts_n;
985f04f1d51SNélio Laranjeiro 		/*
986f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
987f04f1d51SNélio Laranjeiro 		 * iteration.
988f04f1d51SNélio Laranjeiro 		 */
989f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
990230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
991230189d9SNélio Laranjeiro 		if (buf->ol_flags &
992230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
993230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
994a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
995a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
996230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
997230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
998230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
999a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
10008688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1001230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1002230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1003230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1004a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1005230189d9SNélio Laranjeiro 			    (length > inline_room) ||
10068688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1007230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
10080e8679fcSNélio Laranjeiro 				inline_room =
10090e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1010230189d9SNélio Laranjeiro 			}
1011230189d9SNélio Laranjeiro 		}
1012230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1013a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1014a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1015f04f1d51SNélio Laranjeiro 				/*
1016f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1017f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1018f04f1d51SNélio Laranjeiro 				 * such resources.
1019f04f1d51SNélio Laranjeiro 				 */
1020f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1021f04f1d51SNélio Laranjeiro 					break;
1022f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1023230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
10248688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1025230189d9SNélio Laranjeiro 			} else {
1026f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1027f04f1d51SNélio Laranjeiro 					break;
1028f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1029230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
10308688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1031230189d9SNélio Laranjeiro 			}
1032230189d9SNélio Laranjeiro 		}
1033a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1034a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1035230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
10360e8679fcSNélio Laranjeiro 			assert(inline_room ==
10370e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1038a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1039a5bf6af9SAdrien Mazarguil 			length = 0;
1040a5bf6af9SAdrien Mazarguil #endif
1041a5bf6af9SAdrien Mazarguil 			do {
1042230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1043230189d9SNélio Laranjeiro 
1044a5bf6af9SAdrien Mazarguil 				assert(buf);
10458c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
1046230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1047a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1048230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
1049a5bf6af9SAdrien Mazarguil 					.byte_count = htonl(DATA_LEN(buf)),
10506cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
1051230189d9SNélio Laranjeiro 					.addr = htonll(addr),
1052230189d9SNélio Laranjeiro 				};
1053a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1054a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1055a5bf6af9SAdrien Mazarguil #endif
1056a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1057230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1058a5bf6af9SAdrien Mazarguil 				++j;
1059a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1060a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1061230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1062230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1063230189d9SNélio Laranjeiro 		} else {
1064230189d9SNélio Laranjeiro 			unsigned int max;
1065230189d9SNélio Laranjeiro 
1066230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1067230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1068a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1069a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
10708c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
1071230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1072fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1073fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1074fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1075230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1076230189d9SNélio Laranjeiro 			if (length > max) {
1077230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1078230189d9SNélio Laranjeiro 					   (void *)addr,
1079230189d9SNélio Laranjeiro 					   max);
1080fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1081230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1082230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1083230189d9SNélio Laranjeiro 					   length - max);
1084230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1085230189d9SNélio Laranjeiro 			} else {
1086230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1087230189d9SNélio Laranjeiro 					   (void *)addr,
1088230189d9SNélio Laranjeiro 					   length);
108916c64768SYongseok Koh 
109016c64768SYongseok Koh 				if (length == max)
109116c64768SYongseok Koh 					mpw.data.raw =
109216c64768SYongseok Koh 						(volatile void *)txq->wqes;
109316c64768SYongseok Koh 				else
1094230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1095230189d9SNélio Laranjeiro 			}
1096230189d9SNélio Laranjeiro 			++mpw.pkts_n;
109776bf1574SYongseok Koh 			mpw.total_len += length;
1098a5bf6af9SAdrien Mazarguil 			++j;
1099230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1100230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
11010e8679fcSNélio Laranjeiro 				inline_room =
11020e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1103230189d9SNélio Laranjeiro 			} else {
1104230189d9SNélio Laranjeiro 				inline_room -= length;
1105230189d9SNélio Laranjeiro 			}
1106230189d9SNélio Laranjeiro 		}
1107230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1108230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1109230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1110230189d9SNélio Laranjeiro #endif
1111c3d62cc9SAdrien Mazarguil 		++i;
1112c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1113230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1114230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1115230189d9SNélio Laranjeiro 		return 0;
1116230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1117a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1118a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1119230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
11208688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1121230189d9SNélio Laranjeiro 
1122230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
11238688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1124230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
11258688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1126230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1127230189d9SNélio Laranjeiro 	} else {
1128230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1129230189d9SNélio Laranjeiro 	}
1130230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1131230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1132230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1133230189d9SNélio Laranjeiro #endif
1134230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1135230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1136230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1137230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1138230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
113930807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1140230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1141230189d9SNélio Laranjeiro 	return i;
1142230189d9SNélio Laranjeiro }
1143230189d9SNélio Laranjeiro 
1144230189d9SNélio Laranjeiro /**
11456ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
11466ce84bd8SYongseok Koh  *
11476ce84bd8SYongseok Koh  * @param txq
11486ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
11496ce84bd8SYongseok Koh  * @param mpw
11506ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
11516ce84bd8SYongseok Koh  * @param length
11526ce84bd8SYongseok Koh  *   Packet length.
11536ce84bd8SYongseok Koh  */
11546ce84bd8SYongseok Koh static inline void
11556ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding)
11566ce84bd8SYongseok Koh {
11576ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
11586ce84bd8SYongseok Koh 
11596ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
11606ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
11616ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
11626ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
11636ce84bd8SYongseok Koh 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
11646ce84bd8SYongseok Koh 				  (txq->wqe_ci << 8) |
11656ce84bd8SYongseok Koh 				  MLX5_OPCODE_ENHANCED_MPSW);
11666ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
11676ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
11686ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
11696ce84bd8SYongseok Koh 	if (unlikely(padding)) {
11706ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
11716ce84bd8SYongseok Koh 
11726ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
11736ce84bd8SYongseok Koh 		*(volatile uint32_t *)addr = htonl(MLX5_INLINE_SEG);
11746ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
11756ce84bd8SYongseok Koh 			htonl(MLX5_INLINE_SEG);
11766ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
11776ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
11786ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
11796ce84bd8SYongseok Koh 	} else {
11806ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
11816ce84bd8SYongseok Koh 	}
11826ce84bd8SYongseok Koh }
11836ce84bd8SYongseok Koh 
11846ce84bd8SYongseok Koh /**
11856ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
11866ce84bd8SYongseok Koh  *
11876ce84bd8SYongseok Koh  * @param txq
11886ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
11896ce84bd8SYongseok Koh  * @param mpw
11906ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
11916ce84bd8SYongseok Koh  *
11926ce84bd8SYongseok Koh  * @return
11936ce84bd8SYongseok Koh  *   Number of consumed WQEs.
11946ce84bd8SYongseok Koh  */
11956ce84bd8SYongseok Koh static inline uint16_t
11966ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw)
11976ce84bd8SYongseok Koh {
11986ce84bd8SYongseok Koh 	uint16_t ret;
11996ce84bd8SYongseok Koh 
12006ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
12016ce84bd8SYongseok Koh 	 * count as 2.
12026ce84bd8SYongseok Koh 	 */
12036ce84bd8SYongseok Koh 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(mpw->total_len));
12046ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
12056ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
12066ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
12076ce84bd8SYongseok Koh 	return ret;
12086ce84bd8SYongseok Koh }
12096ce84bd8SYongseok Koh 
12106ce84bd8SYongseok Koh /**
12116ce84bd8SYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
12126ce84bd8SYongseok Koh  *
12136ce84bd8SYongseok Koh  * @param dpdk_txq
12146ce84bd8SYongseok Koh  *   Generic pointer to TX queue structure.
12156ce84bd8SYongseok Koh  * @param[in] pkts
12166ce84bd8SYongseok Koh  *   Packets to transmit.
12176ce84bd8SYongseok Koh  * @param pkts_n
12186ce84bd8SYongseok Koh  *   Number of packets in array.
12196ce84bd8SYongseok Koh  *
12206ce84bd8SYongseok Koh  * @return
12216ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
12226ce84bd8SYongseok Koh  */
12236ce84bd8SYongseok Koh uint16_t
12246ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
12256ce84bd8SYongseok Koh {
12266ce84bd8SYongseok Koh 	struct txq *txq = (struct txq *)dpdk_txq;
12276ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
12288c819a69SYongseok Koh 	const uint16_t elts_n = 1 << txq->elts_n;
12298c819a69SYongseok Koh 	const uint16_t elts_m = elts_n - 1;
12306ce84bd8SYongseok Koh 	unsigned int i = 0;
12316ce84bd8SYongseok Koh 	unsigned int j = 0;
12328c819a69SYongseok Koh 	uint16_t max_elts;
12336ce84bd8SYongseok Koh 	uint16_t max_wqe;
12346ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
12356ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
12366ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
12376ce84bd8SYongseok Koh 	uint32_t inl_hdr;
12386ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
12396ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
12406ce84bd8SYongseok Koh 	};
12416ce84bd8SYongseok Koh 
12426ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
12436ce84bd8SYongseok Koh 		return 0;
12446ce84bd8SYongseok Koh 	/* Start processing. */
12456cb559d6SYongseok Koh 	mlx5_tx_complete(txq);
12466ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
12476ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
12486ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
12496ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
12506ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
12516ce84bd8SYongseok Koh 		return 0;
12526ce84bd8SYongseok Koh 	do {
12536ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
12546ce84bd8SYongseok Koh 		uintptr_t addr;
12556ce84bd8SYongseok Koh 		uint64_t naddr;
12566ce84bd8SYongseok Koh 		unsigned int n;
12576ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
12586ce84bd8SYongseok Koh 		uint32_t length;
12596ce84bd8SYongseok Koh 		unsigned int segs_n = buf->nb_segs;
12606ce84bd8SYongseok Koh 		uint32_t cs_flags = 0;
12616ce84bd8SYongseok Koh 
12626ce84bd8SYongseok Koh 		/*
12636ce84bd8SYongseok Koh 		 * Make sure there is enough room to store this packet and
12646ce84bd8SYongseok Koh 		 * that one ring entry remains unused.
12656ce84bd8SYongseok Koh 		 */
12666ce84bd8SYongseok Koh 		assert(segs_n);
12678c819a69SYongseok Koh 		if (max_elts - j < segs_n)
12686ce84bd8SYongseok Koh 			break;
12696ce84bd8SYongseok Koh 		/* Do not bother with large packets MPW cannot handle. */
12706ce84bd8SYongseok Koh 		if (segs_n > MLX5_MPW_DSEG_MAX)
12716ce84bd8SYongseok Koh 			break;
12726ce84bd8SYongseok Koh 		/* Should we enable HW CKSUM offload. */
12736ce84bd8SYongseok Koh 		if (buf->ol_flags &
12746ce84bd8SYongseok Koh 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
12756ce84bd8SYongseok Koh 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
12766ce84bd8SYongseok Koh 		/* Retrieve packet information. */
12776ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
12786ce84bd8SYongseok Koh 		/* Start new session if:
12796ce84bd8SYongseok Koh 		 * - multi-segment packet
12806ce84bd8SYongseok Koh 		 * - no space left even for a dseg
12816ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
12826ce84bd8SYongseok Koh 		 * - cs_flag differs
12836ce84bd8SYongseok Koh 		 * It can't be MLX5_MPW_STATE_OPENED as always have a single
12846ce84bd8SYongseok Koh 		 * segmented packet.
12856ce84bd8SYongseok Koh 		 */
12866ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
12876ce84bd8SYongseok Koh 			if ((segs_n != 1) ||
12886ce84bd8SYongseok Koh 			    (inl_pad + sizeof(struct mlx5_wqe_data_seg) >
12896ce84bd8SYongseok Koh 			      mpw_room) ||
12906ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
12916ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
12926ce84bd8SYongseok Koh 			      mpw_room) ||
12936ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
12946ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
12956ce84bd8SYongseok Koh 		}
12966ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
12976ce84bd8SYongseok Koh 			if (unlikely(segs_n != 1)) {
12986ce84bd8SYongseok Koh 				/* Fall back to legacy MPW.
12996ce84bd8SYongseok Koh 				 * A MPW session consumes 2 WQEs at most to
13006ce84bd8SYongseok Koh 				 * include MLX5_MPW_DSEG_MAX pointers.
13016ce84bd8SYongseok Koh 				 */
13026ce84bd8SYongseok Koh 				if (unlikely(max_wqe < 2))
13036ce84bd8SYongseok Koh 					break;
13046ce84bd8SYongseok Koh 				mlx5_mpw_new(txq, &mpw, length);
13056ce84bd8SYongseok Koh 			} else {
13066ce84bd8SYongseok Koh 				/* In Enhanced MPW, inline as much as the budget
13076ce84bd8SYongseok Koh 				 * is allowed. The remaining space is to be
13086ce84bd8SYongseok Koh 				 * filled with dsegs. If the title WQEBB isn't
13096ce84bd8SYongseok Koh 				 * padded, it will have 2 dsegs there.
13106ce84bd8SYongseok Koh 				 */
13116ce84bd8SYongseok Koh 				mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
13126ce84bd8SYongseok Koh 					    (max_inline ? max_inline :
13136ce84bd8SYongseok Koh 					     pkts_n * MLX5_WQE_DWORD_SIZE) +
13146ce84bd8SYongseok Koh 					    MLX5_WQE_SIZE);
13156ce84bd8SYongseok Koh 				if (unlikely(max_wqe * MLX5_WQE_SIZE <
13166ce84bd8SYongseok Koh 					      mpw_room))
13176ce84bd8SYongseok Koh 					break;
13186ce84bd8SYongseok Koh 				/* Don't pad the title WQEBB to not waste WQ. */
13196ce84bd8SYongseok Koh 				mlx5_empw_new(txq, &mpw, 0);
13206ce84bd8SYongseok Koh 				mpw_room -= mpw.total_len;
13216ce84bd8SYongseok Koh 				inl_pad = 0;
13226ce84bd8SYongseok Koh 				do_inline =
13236ce84bd8SYongseok Koh 					length <= txq->inline_max_packet_sz &&
13246ce84bd8SYongseok Koh 					sizeof(inl_hdr) + length <= mpw_room &&
13256ce84bd8SYongseok Koh 					!txq->mpw_hdr_dseg;
13266ce84bd8SYongseok Koh 			}
13276ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
13286ce84bd8SYongseok Koh 		} else {
13296ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
13306ce84bd8SYongseok Koh 			 * Inlininig is possible when:
13316ce84bd8SYongseok Koh 			 * - length is less than configured value
13326ce84bd8SYongseok Koh 			 * - length fits for remaining space
13336ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
13346ce84bd8SYongseok Koh 			 */
13356ce84bd8SYongseok Koh 			do_inline =
13366ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
13376ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
13386ce84bd8SYongseok Koh 				 mpw_room &&
13396ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
13406ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
13416ce84bd8SYongseok Koh 		}
13426ce84bd8SYongseok Koh 		/* Multi-segment packets must be alone in their MPW. */
13436ce84bd8SYongseok Koh 		assert((segs_n == 1) || (mpw.pkts_n == 0));
13446ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) {
13456ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
13466ce84bd8SYongseok Koh 			length = 0;
13476ce84bd8SYongseok Koh #endif
13486ce84bd8SYongseok Koh 			do {
13496ce84bd8SYongseok Koh 				volatile struct mlx5_wqe_data_seg *dseg;
13506ce84bd8SYongseok Koh 
13516ce84bd8SYongseok Koh 				assert(buf);
13528c819a69SYongseok Koh 				(*txq->elts)[elts_head++ & elts_m] = buf;
13536ce84bd8SYongseok Koh 				dseg = mpw.data.dseg[mpw.pkts_n];
13546ce84bd8SYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
13556ce84bd8SYongseok Koh 				*dseg = (struct mlx5_wqe_data_seg){
13566ce84bd8SYongseok Koh 					.byte_count = htonl(DATA_LEN(buf)),
13576cb559d6SYongseok Koh 					.lkey = mlx5_tx_mb2mr(txq, buf),
13586ce84bd8SYongseok Koh 					.addr = htonll(addr),
13596ce84bd8SYongseok Koh 				};
13606ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
13616ce84bd8SYongseok Koh 				length += DATA_LEN(buf);
13626ce84bd8SYongseok Koh #endif
13636ce84bd8SYongseok Koh 				buf = buf->next;
13646ce84bd8SYongseok Koh 				++j;
13656ce84bd8SYongseok Koh 				++mpw.pkts_n;
13666ce84bd8SYongseok Koh 			} while (--segs_n);
13676ce84bd8SYongseok Koh 			/* A multi-segmented packet takes one MPW session.
13686ce84bd8SYongseok Koh 			 * TODO: Pack more multi-segmented packets if possible.
13696ce84bd8SYongseok Koh 			 */
13706ce84bd8SYongseok Koh 			mlx5_mpw_close(txq, &mpw);
13716ce84bd8SYongseok Koh 			if (mpw.pkts_n < 3)
13726ce84bd8SYongseok Koh 				max_wqe--;
13736ce84bd8SYongseok Koh 			else
13746ce84bd8SYongseok Koh 				max_wqe -= 2;
13756ce84bd8SYongseok Koh 		} else if (do_inline) {
13766ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
13776ce84bd8SYongseok Koh 			unsigned int max;
13786ce84bd8SYongseok Koh 
13796ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
13806ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
13816ce84bd8SYongseok Koh 			inl_hdr = htonl(length | MLX5_INLINE_SEG);
13826ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
13836ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
13846ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
13856ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
13866ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
13876ce84bd8SYongseok Koh 			/* Copy inline header. */
13886ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
13896ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
13906ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
13916ce84bd8SYongseok Koh 					  &inl_hdr,
13926ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
13936ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
13946ce84bd8SYongseok Koh 					  max);
13956ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
13966ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
13976ce84bd8SYongseok Koh 			/* Copy packet data. */
13986ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
13996ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
14006ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
14016ce84bd8SYongseok Koh 					  (void *)addr,
14026ce84bd8SYongseok Koh 					  length,
14036ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
14046ce84bd8SYongseok Koh 					  max);
14056ce84bd8SYongseok Koh 			++mpw.pkts_n;
14066ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
14076ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
14086ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
14096ce84bd8SYongseok Koh 			 */
14106ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
14116ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
14126ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
14136ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
14146ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
14156ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
14166ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
14176ce84bd8SYongseok Koh 		} else {
14186ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
14196ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
14206ce84bd8SYongseok Koh 
14216ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
14226ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
14236ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
14246ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
14256ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
14266ce84bd8SYongseok Koh 						+ inl_pad)))
14276ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
14286ce84bd8SYongseok Koh 			else
14296ce84bd8SYongseok Koh 				dseg = (volatile void *)
14306ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
14316ce84bd8SYongseok Koh 					 inl_pad);
14328c819a69SYongseok Koh 			(*txq->elts)[elts_head++ & elts_m] = buf;
14336ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
14346ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
14356ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
14366ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
14376ce84bd8SYongseok Koh 			naddr = htonll(addr);
14386ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
14396ce84bd8SYongseok Koh 				htonl(length),
14406cb559d6SYongseok Koh 				mlx5_tx_mb2mr(txq, buf),
14416ce84bd8SYongseok Koh 				naddr,
14426ce84bd8SYongseok Koh 				naddr >> 32,
14436ce84bd8SYongseok Koh 			};
14446ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
14456ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
14466ce84bd8SYongseok Koh 			++j;
14476ce84bd8SYongseok Koh 			++mpw.pkts_n;
14486ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
14496ce84bd8SYongseok Koh 			inl_pad = 0;
14506ce84bd8SYongseok Koh 		}
14516ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
14526ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
14536ce84bd8SYongseok Koh 		txq->stats.obytes += length;
14546ce84bd8SYongseok Koh #endif
14556ce84bd8SYongseok Koh 		++i;
14566ce84bd8SYongseok Koh 	} while (i < pkts_n);
14576ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
14586ce84bd8SYongseok Koh 	if (unlikely(i == 0))
14596ce84bd8SYongseok Koh 		return 0;
14606ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
14616ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
14626ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
14636ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
14646ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
14656ce84bd8SYongseok Koh 
14666ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
14676ce84bd8SYongseok Koh 		wqe->ctrl[2] = htonl(8);
14686ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
14696ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
14706ce84bd8SYongseok Koh 		txq->elts_comp = 0;
14716ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
14726ce84bd8SYongseok Koh 		txq->cq_pi++;
14736ce84bd8SYongseok Koh 	} else {
14746ce84bd8SYongseok Koh 		txq->elts_comp += j;
14756ce84bd8SYongseok Koh 	}
14766ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
14776ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
14786ce84bd8SYongseok Koh 	txq->stats.opackets += i;
14796ce84bd8SYongseok Koh #endif
14806ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
14816ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
14826ce84bd8SYongseok Koh 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
14836ce84bd8SYongseok Koh 		mlx5_mpw_close(txq, &mpw);
14846ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
14856ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
14866ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
14876ce84bd8SYongseok Koh 	return i;
14886ce84bd8SYongseok Koh }
14896ce84bd8SYongseok Koh 
14906ce84bd8SYongseok Koh /**
149167fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
149267fa62bcSAdrien Mazarguil  *
14936218063bSNélio Laranjeiro  * @param[in] cqe
14946218063bSNélio Laranjeiro  *   Pointer to CQE.
149567fa62bcSAdrien Mazarguil  *
149678a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
149778a38edfSJianfeng Tan  *
149867fa62bcSAdrien Mazarguil  * @return
149967fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
150067fa62bcSAdrien Mazarguil  */
150167fa62bcSAdrien Mazarguil static inline uint32_t
150297267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
150367fa62bcSAdrien Mazarguil {
150467fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
15050603df73SNélio Laranjeiro 	uint16_t flags = ntohs(cqe->hdr_type_etc);
150667fa62bcSAdrien Mazarguil 
15070603df73SNélio Laranjeiro 	if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) {
150867fa62bcSAdrien Mazarguil 		pkt_type =
150967fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1510350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV4_PACKET,
1511501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) |
151267fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1513350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV6_PACKET,
1514501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN);
15150603df73SNélio Laranjeiro 		pkt_type |= ((cqe->pkt_info & MLX5_CQE_RX_OUTER_PACKET) ?
15160603df73SNélio Laranjeiro 			     RTE_PTYPE_L3_IPV6_EXT_UNKNOWN :
15170603df73SNélio Laranjeiro 			     RTE_PTYPE_L3_IPV4_EXT_UNKNOWN);
15180603df73SNélio Laranjeiro 	} else {
151967fa62bcSAdrien Mazarguil 		pkt_type =
152067fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
15216218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV6,
1522501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) |
152367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
15246218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV4,
1525501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_L3_IPV4_EXT_UNKNOWN);
15260603df73SNélio Laranjeiro 	}
152767fa62bcSAdrien Mazarguil 	return pkt_type;
152867fa62bcSAdrien Mazarguil }
152967fa62bcSAdrien Mazarguil 
153067fa62bcSAdrien Mazarguil /**
153199c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
153299c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
153399c12dccSNélio Laranjeiro  * been processed.
153499c12dccSNélio Laranjeiro  *
153599c12dccSNélio Laranjeiro  * @param rxq
153699c12dccSNélio Laranjeiro  *   Pointer to RX queue.
153799c12dccSNélio Laranjeiro  * @param cqe
153899c12dccSNélio Laranjeiro  *   CQE to process.
1539ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1540ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
154199c12dccSNélio Laranjeiro  *
154299c12dccSNélio Laranjeiro  * @return
154399c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
154499c12dccSNélio Laranjeiro  *   with error.
154599c12dccSNélio Laranjeiro  */
154699c12dccSNélio Laranjeiro static inline int
154797267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
1548ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
154999c12dccSNélio Laranjeiro {
155099c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
155199c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
155299c12dccSNélio Laranjeiro 	int len = 0;
1553d2e842d0SYongseok Koh 	uint16_t idx, end;
155499c12dccSNélio Laranjeiro 
155599c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
155699c12dccSNélio Laranjeiro 	if (zip->ai) {
155799c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
155899c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
15594aff4bcbSYongseok Koh 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info);
156099c12dccSNélio Laranjeiro 
156199c12dccSNélio Laranjeiro 		len = ntohl((*mc)[zip->ai & 7].byte_cnt);
1562ecf60761SNélio Laranjeiro 		*rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result);
156399c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1564d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1565d2e842d0SYongseok Koh 			idx = zip->ca;
1566d2e842d0SYongseok Koh 			end = zip->na;
1567d2e842d0SYongseok Koh 			while (idx != end) {
1568d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1569d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1570d2e842d0SYongseok Koh 				++idx;
1571d2e842d0SYongseok Koh 			}
157299c12dccSNélio Laranjeiro 			/*
157399c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
157499c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
157599c12dccSNélio Laranjeiro 			 * ring for software use.
157699c12dccSNélio Laranjeiro 			 */
157799c12dccSNélio Laranjeiro 			zip->ca = zip->na;
157899c12dccSNélio Laranjeiro 			zip->na += 8;
157999c12dccSNélio Laranjeiro 		}
158099c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1581d2e842d0SYongseok Koh 			/* Invalidate the rest */
1582d2e842d0SYongseok Koh 			idx = zip->ca;
1583d2e842d0SYongseok Koh 			end = zip->cq_ci;
158499c12dccSNélio Laranjeiro 
158599c12dccSNélio Laranjeiro 			while (idx != end) {
158697267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
158799c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
158899c12dccSNélio Laranjeiro 				++idx;
158999c12dccSNélio Laranjeiro 			}
159099c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
159199c12dccSNélio Laranjeiro 			zip->ai = 0;
159299c12dccSNélio Laranjeiro 		}
159399c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
159499c12dccSNélio Laranjeiro 	} else {
159599c12dccSNélio Laranjeiro 		int ret;
159699c12dccSNélio Laranjeiro 		int8_t op_own;
159799c12dccSNélio Laranjeiro 
159897267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
159999c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
160099c12dccSNélio Laranjeiro 			return 0;
160199c12dccSNélio Laranjeiro 		++rxq->cq_ci;
160299c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
160399c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
160499c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
160599c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
160699c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
16074aff4bcbSYongseok Koh 							  cqe_cnt].pkt_info);
160899c12dccSNélio Laranjeiro 
160999c12dccSNélio Laranjeiro 			/* Fix endianness. */
161099c12dccSNélio Laranjeiro 			zip->cqe_cnt = ntohl(cqe->byte_cnt);
161199c12dccSNélio Laranjeiro 			/*
161299c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
161399c12dccSNélio Laranjeiro 			 * check_cqe64().
161499c12dccSNélio Laranjeiro 			 *
161599c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
161699c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
161799c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
161899c12dccSNélio Laranjeiro 			 */
1619d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
162099c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
162199c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
162299c12dccSNélio Laranjeiro 			--rxq->cq_ci;
162399c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
162499c12dccSNélio Laranjeiro 			/* Get packet size to return. */
162599c12dccSNélio Laranjeiro 			len = ntohl((*mc)[0].byte_cnt);
1626ecf60761SNélio Laranjeiro 			*rss_hash = ntohl((*mc)[0].rx_hash_result);
162799c12dccSNélio Laranjeiro 			zip->ai = 1;
1628d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1629d2e842d0SYongseok Koh 			idx = zip->ca;
1630d2e842d0SYongseok Koh 			end = zip->cq_ci;
1631d2e842d0SYongseok Koh 			while (idx != end) {
1632d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1633d2e842d0SYongseok Koh 				++idx;
1634d2e842d0SYongseok Koh 			}
163599c12dccSNélio Laranjeiro 		} else {
163699c12dccSNélio Laranjeiro 			len = ntohl(cqe->byte_cnt);
1637ecf60761SNélio Laranjeiro 			*rss_hash = ntohl(cqe->rx_hash_res);
163899c12dccSNélio Laranjeiro 		}
163999c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
164099c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
164199c12dccSNélio Laranjeiro 			return -1;
164299c12dccSNélio Laranjeiro 	}
164399c12dccSNélio Laranjeiro 	return len;
164499c12dccSNélio Laranjeiro }
164599c12dccSNélio Laranjeiro 
164699c12dccSNélio Laranjeiro /**
164767fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
164867fa62bcSAdrien Mazarguil  *
164967fa62bcSAdrien Mazarguil  * @param[in] rxq
165067fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
16516218063bSNélio Laranjeiro  * @param[in] cqe
16526218063bSNélio Laranjeiro  *   Pointer to CQE.
165367fa62bcSAdrien Mazarguil  *
165467fa62bcSAdrien Mazarguil  * @return
165567fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
165667fa62bcSAdrien Mazarguil  */
165767fa62bcSAdrien Mazarguil static inline uint32_t
165897267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
165967fa62bcSAdrien Mazarguil {
166067fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
16610603df73SNélio Laranjeiro 	uint16_t flags = ntohs(cqe->hdr_type_etc);
166267fa62bcSAdrien Mazarguil 
16630603df73SNélio Laranjeiro 	ol_flags =
16640603df73SNélio Laranjeiro 		TRANSPOSE(flags,
16650603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
16660603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
16670603df73SNélio Laranjeiro 		TRANSPOSE(flags,
16680603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
166983e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
167097267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
167167fa62bcSAdrien Mazarguil 		ol_flags |=
16720603df73SNélio Laranjeiro 			TRANSPOSE(flags,
16730603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
167483e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
16750603df73SNélio Laranjeiro 			TRANSPOSE(flags,
16760603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
167783e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
167867fa62bcSAdrien Mazarguil 	return ol_flags;
167967fa62bcSAdrien Mazarguil }
168067fa62bcSAdrien Mazarguil 
168167fa62bcSAdrien Mazarguil /**
16822e22920bSAdrien Mazarguil  * DPDK callback for RX.
16832e22920bSAdrien Mazarguil  *
16842e22920bSAdrien Mazarguil  * @param dpdk_rxq
16852e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
16862e22920bSAdrien Mazarguil  * @param[out] pkts
16872e22920bSAdrien Mazarguil  *   Array to store received packets.
16882e22920bSAdrien Mazarguil  * @param pkts_n
16892e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
16902e22920bSAdrien Mazarguil  *
16912e22920bSAdrien Mazarguil  * @return
16922e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
16932e22920bSAdrien Mazarguil  */
16942e22920bSAdrien Mazarguil uint16_t
16952e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
16962e22920bSAdrien Mazarguil {
16976218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
1698b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1699e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
17009964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
17019964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
17029964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
170397267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
170497267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
17059964b965SNélio Laranjeiro 	unsigned int i = 0;
17069964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
17074e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
17082e22920bSAdrien Mazarguil 
17099964b965SNélio Laranjeiro 	while (pkts_n) {
17109964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
17119964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
17129964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1713ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
17149964b965SNélio Laranjeiro 
17159964b965SNélio Laranjeiro 		if (pkt)
17169964b965SNélio Laranjeiro 			NEXT(seg) = rep;
17179964b965SNélio Laranjeiro 		seg = rep;
17189964b965SNélio Laranjeiro 		rte_prefetch0(seg);
17196218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
17209964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1721fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
17222e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
172315a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
172415a756b6SSagi Grimberg 			if (!pkt) {
172515a756b6SSagi Grimberg 				/*
172615a756b6SSagi Grimberg 				 * no buffers before we even started,
172715a756b6SSagi Grimberg 				 * bail out silently.
172815a756b6SSagi Grimberg 				 */
172915a756b6SSagi Grimberg 				break;
173015a756b6SSagi Grimberg 			}
1731a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1732a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1733fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
17348f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
17358f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
17361f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1737fe5fe382SNélio Laranjeiro 				pkt = rep;
17389964b965SNélio Laranjeiro 			}
17396218063bSNélio Laranjeiro 			break;
17402e22920bSAdrien Mazarguil 		}
17419964b965SNélio Laranjeiro 		if (!pkt) {
174297267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1743ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1744ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1745ecf60761SNélio Laranjeiro 			if (!len) {
17461f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
17476218063bSNélio Laranjeiro 				break;
17486218063bSNélio Laranjeiro 			}
174999c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
175099c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
17511f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
175299c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
175399c12dccSNélio Laranjeiro 				goto skip;
175499c12dccSNélio Laranjeiro 			}
17559964b965SNélio Laranjeiro 			pkt = seg;
17569964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
17579964b965SNélio Laranjeiro 			/* Update packet information. */
1758*48dfc20fSYongseok Koh 			pkt->packet_type = rxq_cq_to_pkt_type(cqe);
17590ac64846SMaxime Leroy 			pkt->ol_flags = 0;
176036ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1761ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1762ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1763ecf60761SNélio Laranjeiro 			}
1764c604f619SNélio Laranjeiro 			if (rxq->mark &&
1765c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
1766b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
1767b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
1768b268a3eeSNélio Laranjeiro 				    htonl(MLX5_FLOW_MARK_DEFAULT)) {
1769b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
1770b268a3eeSNélio Laranjeiro 
1771b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
1772ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
1773b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
1774b268a3eeSNélio Laranjeiro 				}
1775ea3bc3b1SNélio Laranjeiro 			}
1776*48dfc20fSYongseok Koh 			if (rxq->csum | rxq->csum_l2tun)
17776703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
17786703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
17796703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
17806703d836SNélio Laranjeiro 			     htons(MLX5_CQE_VLAN_STRIPPED))) {
17816218063bSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_VLAN_PKT |
1782b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
17836218063bSNélio Laranjeiro 				pkt->vlan_tci = ntohs(cqe->vlan_info);
1784f3db9489SYaacov Hazan 			}
17856218063bSNélio Laranjeiro 			if (rxq->crc_present)
17866218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
17876218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
17889964b965SNélio Laranjeiro 		}
17899964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
17909964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
17919964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
17929964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
17939964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
17949964b965SNélio Laranjeiro 		/*
17959964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
17969964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
17979964b965SNélio Laranjeiro 		 * changes.
17989964b965SNélio Laranjeiro 		 */
17999964b965SNélio Laranjeiro 		wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
18009964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
18019964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
18029964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
18039964b965SNélio Laranjeiro 			++rq_ci;
18049964b965SNélio Laranjeiro 			continue;
18059964b965SNélio Laranjeiro 		}
18069964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
180787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
180887011737SAdrien Mazarguil 		/* Increment bytes counter. */
18099964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
181087011737SAdrien Mazarguil #endif
18116218063bSNélio Laranjeiro 		/* Return packet. */
18126218063bSNélio Laranjeiro 		*(pkts++) = pkt;
18139964b965SNélio Laranjeiro 		pkt = NULL;
18149964b965SNélio Laranjeiro 		--pkts_n;
18159964b965SNélio Laranjeiro 		++i;
181699c12dccSNélio Laranjeiro skip:
18179964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
18189964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
18196218063bSNélio Laranjeiro 		++rq_ci;
18209964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
18212e22920bSAdrien Mazarguil 	}
18229964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
18232e22920bSAdrien Mazarguil 		return 0;
18246218063bSNélio Laranjeiro 	/* Update the consumer index. */
18259964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
18266218063bSNélio Laranjeiro 	rte_wmb();
18276218063bSNélio Laranjeiro 	*rxq->cq_db = htonl(rxq->cq_ci);
18286218063bSNélio Laranjeiro 	rte_wmb();
18296218063bSNélio Laranjeiro 	*rxq->rq_db = htonl(rxq->rq_ci);
183087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
183187011737SAdrien Mazarguil 	/* Increment packets counter. */
18329964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
183387011737SAdrien Mazarguil #endif
18349964b965SNélio Laranjeiro 	return i;
18352e22920bSAdrien Mazarguil }
18362e22920bSAdrien Mazarguil 
18372e22920bSAdrien Mazarguil /**
18382e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
18392e22920bSAdrien Mazarguil  *
18402e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
18412e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
18422e22920bSAdrien Mazarguil  *
18432e22920bSAdrien Mazarguil  * @param dpdk_txq
18442e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
18452e22920bSAdrien Mazarguil  * @param[in] pkts
18462e22920bSAdrien Mazarguil  *   Packets to transmit.
18472e22920bSAdrien Mazarguil  * @param pkts_n
18482e22920bSAdrien Mazarguil  *   Number of packets in array.
18492e22920bSAdrien Mazarguil  *
18502e22920bSAdrien Mazarguil  * @return
18512e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
18522e22920bSAdrien Mazarguil  */
18532e22920bSAdrien Mazarguil uint16_t
18542e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
18552e22920bSAdrien Mazarguil {
18562e22920bSAdrien Mazarguil 	(void)dpdk_txq;
18572e22920bSAdrien Mazarguil 	(void)pkts;
18582e22920bSAdrien Mazarguil 	(void)pkts_n;
18592e22920bSAdrien Mazarguil 	return 0;
18602e22920bSAdrien Mazarguil }
18612e22920bSAdrien Mazarguil 
18622e22920bSAdrien Mazarguil /**
18632e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
18642e22920bSAdrien Mazarguil  *
18652e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
18662e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
18672e22920bSAdrien Mazarguil  *
18682e22920bSAdrien Mazarguil  * @param dpdk_rxq
18692e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
18702e22920bSAdrien Mazarguil  * @param[out] pkts
18712e22920bSAdrien Mazarguil  *   Array to store received packets.
18722e22920bSAdrien Mazarguil  * @param pkts_n
18732e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
18742e22920bSAdrien Mazarguil  *
18752e22920bSAdrien Mazarguil  * @return
18762e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
18772e22920bSAdrien Mazarguil  */
18782e22920bSAdrien Mazarguil uint16_t
18792e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
18802e22920bSAdrien Mazarguil {
18812e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
18822e22920bSAdrien Mazarguil 	(void)pkts;
18832e22920bSAdrien Mazarguil 	(void)pkts_n;
18842e22920bSAdrien Mazarguil 	return 0;
18852e22920bSAdrien Mazarguil }
18866cb559d6SYongseok Koh 
18876cb559d6SYongseok Koh /*
18886cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
18896cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
18906cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
18916cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
18926cb559d6SYongseok Koh  */
18936cb559d6SYongseok Koh 
18946cb559d6SYongseok Koh uint16_t __attribute__((weak))
18956cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
18966cb559d6SYongseok Koh {
18976cb559d6SYongseok Koh 	(void)dpdk_txq;
18986cb559d6SYongseok Koh 	(void)pkts;
18996cb559d6SYongseok Koh 	(void)pkts_n;
19006cb559d6SYongseok Koh 	return 0;
19016cb559d6SYongseok Koh }
19026cb559d6SYongseok Koh 
19036cb559d6SYongseok Koh uint16_t __attribute__((weak))
19046cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
19056cb559d6SYongseok Koh {
19066cb559d6SYongseok Koh 	(void)dpdk_txq;
19076cb559d6SYongseok Koh 	(void)pkts;
19086cb559d6SYongseok Koh 	(void)pkts_n;
19096cb559d6SYongseok Koh 	return 0;
19106cb559d6SYongseok Koh }
19116cb559d6SYongseok Koh 
19126cb559d6SYongseok Koh uint16_t __attribute__((weak))
19136cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19146cb559d6SYongseok Koh {
19156cb559d6SYongseok Koh 	(void)dpdk_rxq;
19166cb559d6SYongseok Koh 	(void)pkts;
19176cb559d6SYongseok Koh 	(void)pkts_n;
19186cb559d6SYongseok Koh 	return 0;
19196cb559d6SYongseok Koh }
19206cb559d6SYongseok Koh 
19216cb559d6SYongseok Koh int __attribute__((weak))
19226cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv)
19236cb559d6SYongseok Koh {
19246cb559d6SYongseok Koh 	(void)priv;
19256cb559d6SYongseok Koh 	return -ENOTSUP;
19266cb559d6SYongseok Koh }
19276cb559d6SYongseok Koh 
19286cb559d6SYongseok Koh int __attribute__((weak))
19296cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv)
19306cb559d6SYongseok Koh {
19316cb559d6SYongseok Koh 	(void)priv;
19326cb559d6SYongseok Koh 	return -ENOTSUP;
19336cb559d6SYongseok Koh }
19346cb559d6SYongseok Koh 
19356cb559d6SYongseok Koh int __attribute__((weak))
19366cb559d6SYongseok Koh rxq_check_vec_support(struct rxq *rxq)
19376cb559d6SYongseok Koh {
19386cb559d6SYongseok Koh 	(void)rxq;
19396cb559d6SYongseok Koh 	return -ENOTSUP;
19406cb559d6SYongseok Koh }
19416cb559d6SYongseok Koh 
19426cb559d6SYongseok Koh int __attribute__((weak))
19436cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv)
19446cb559d6SYongseok Koh {
19456cb559d6SYongseok Koh 	(void)priv;
19466cb559d6SYongseok Koh 	return -ENOTSUP;
19476cb559d6SYongseok Koh }
19486cb559d6SYongseok Koh 
19496cb559d6SYongseok Koh void __attribute__((weak))
19506cb559d6SYongseok Koh priv_prep_vec_rx_function(struct priv *priv)
19516cb559d6SYongseok Koh {
19526cb559d6SYongseok Koh 	(void)priv;
19536cb559d6SYongseok Koh }
1954