xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision ab76eab38aae98bc0cfae5d89ed8ee756f31382a)
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 
72ff1807a3SNélio Laranjeiro static inline int
73ff1807a3SNélio Laranjeiro check_cqe(volatile struct mlx5_cqe *cqe,
74ff1807a3SNélio Laranjeiro 	  unsigned int cqes_n, const uint16_t ci)
75ff1807a3SNélio Laranjeiro 	  __attribute__((always_inline));
76ff1807a3SNélio Laranjeiro 
7761b09ae4SNélio Laranjeiro static inline void
7861b09ae4SNélio Laranjeiro txq_complete(struct txq *txq) __attribute__((always_inline));
7961b09ae4SNélio Laranjeiro 
80ff1807a3SNélio Laranjeiro static inline uint32_t
81ff1807a3SNélio Laranjeiro txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
82ff1807a3SNélio Laranjeiro 	__attribute__((always_inline));
83ff1807a3SNélio Laranjeiro 
84ff1807a3SNélio Laranjeiro static inline void
8530807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe)
8630807f62SNélio Laranjeiro 	__attribute__((always_inline));
87ff1807a3SNélio Laranjeiro 
88ff1807a3SNélio Laranjeiro static inline uint32_t
89ff1807a3SNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
90ff1807a3SNélio Laranjeiro 	__attribute__((always_inline));
91ff1807a3SNélio Laranjeiro 
92ff1807a3SNélio Laranjeiro static inline int
93ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
94ff1807a3SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
95ff1807a3SNélio Laranjeiro 		 __attribute__((always_inline));
96ff1807a3SNélio Laranjeiro 
97ff1807a3SNélio Laranjeiro static inline uint32_t
98ff1807a3SNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
99ff1807a3SNélio Laranjeiro 		   __attribute__((always_inline));
100ff1807a3SNélio Laranjeiro 
10199c12dccSNélio Laranjeiro #ifndef NDEBUG
10299c12dccSNélio Laranjeiro 
10399c12dccSNélio Laranjeiro /**
10499c12dccSNélio Laranjeiro  * Verify or set magic value in CQE.
10599c12dccSNélio Laranjeiro  *
10699c12dccSNélio Laranjeiro  * @param cqe
10799c12dccSNélio Laranjeiro  *   Pointer to CQE.
10899c12dccSNélio Laranjeiro  *
10999c12dccSNélio Laranjeiro  * @return
11099c12dccSNélio Laranjeiro  *   0 the first time.
11199c12dccSNélio Laranjeiro  */
11299c12dccSNélio Laranjeiro static inline int
11397267b8eSNelio Laranjeiro check_cqe_seen(volatile struct mlx5_cqe *cqe)
11499c12dccSNélio Laranjeiro {
11599c12dccSNélio Laranjeiro 	static const uint8_t magic[] = "seen";
116ea3bc3b1SNélio Laranjeiro 	volatile uint8_t (*buf)[sizeof(cqe->rsvd0)] = &cqe->rsvd0;
11799c12dccSNélio Laranjeiro 	int ret = 1;
11899c12dccSNélio Laranjeiro 	unsigned int i;
11999c12dccSNélio Laranjeiro 
12099c12dccSNélio Laranjeiro 	for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i)
12199c12dccSNélio Laranjeiro 		if (!ret || (*buf)[i] != magic[i]) {
12299c12dccSNélio Laranjeiro 			ret = 0;
12399c12dccSNélio Laranjeiro 			(*buf)[i] = magic[i];
12499c12dccSNélio Laranjeiro 		}
12599c12dccSNélio Laranjeiro 	return ret;
12699c12dccSNélio Laranjeiro }
12799c12dccSNélio Laranjeiro 
12899c12dccSNélio Laranjeiro #endif /* NDEBUG */
1296218063bSNélio Laranjeiro 
13099c12dccSNélio Laranjeiro /**
13199c12dccSNélio Laranjeiro  * Check whether CQE is valid.
13299c12dccSNélio Laranjeiro  *
13399c12dccSNélio Laranjeiro  * @param cqe
13499c12dccSNélio Laranjeiro  *   Pointer to CQE.
13599c12dccSNélio Laranjeiro  * @param cqes_n
13699c12dccSNélio Laranjeiro  *   Size of completion queue.
13799c12dccSNélio Laranjeiro  * @param ci
13899c12dccSNélio Laranjeiro  *   Consumer index.
13999c12dccSNélio Laranjeiro  *
14099c12dccSNélio Laranjeiro  * @return
14199c12dccSNélio Laranjeiro  *   0 on success, 1 on failure.
14299c12dccSNélio Laranjeiro  */
14399c12dccSNélio Laranjeiro static inline int
14497267b8eSNelio Laranjeiro check_cqe(volatile struct mlx5_cqe *cqe,
14599c12dccSNélio Laranjeiro 	  unsigned int cqes_n, const uint16_t ci)
1466218063bSNélio Laranjeiro {
14799c12dccSNélio Laranjeiro 	uint16_t idx = ci & cqes_n;
14899c12dccSNélio Laranjeiro 	uint8_t op_own = cqe->op_own;
14999c12dccSNélio Laranjeiro 	uint8_t op_owner = MLX5_CQE_OWNER(op_own);
15099c12dccSNélio Laranjeiro 	uint8_t op_code = MLX5_CQE_OPCODE(op_own);
1516218063bSNélio Laranjeiro 
15299c12dccSNélio Laranjeiro 	if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID)))
15399c12dccSNélio Laranjeiro 		return 1; /* No CQE. */
15499c12dccSNélio Laranjeiro #ifndef NDEBUG
15599c12dccSNélio Laranjeiro 	if ((op_code == MLX5_CQE_RESP_ERR) ||
15699c12dccSNélio Laranjeiro 	    (op_code == MLX5_CQE_REQ_ERR)) {
15799c12dccSNélio Laranjeiro 		volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe;
15899c12dccSNélio Laranjeiro 		uint8_t syndrome = err_cqe->syndrome;
15999c12dccSNélio Laranjeiro 
16099c12dccSNélio Laranjeiro 		if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) ||
16199c12dccSNélio Laranjeiro 		    (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR))
16299c12dccSNélio Laranjeiro 			return 0;
16397267b8eSNelio Laranjeiro 		if (!check_cqe_seen(cqe))
16499c12dccSNélio Laranjeiro 			ERROR("unexpected CQE error %u (0x%02x)"
16599c12dccSNélio Laranjeiro 			      " syndrome 0x%02x",
16699c12dccSNélio Laranjeiro 			      op_code, op_code, syndrome);
16799c12dccSNélio Laranjeiro 		return 1;
16899c12dccSNélio Laranjeiro 	} else if ((op_code != MLX5_CQE_RESP_SEND) &&
16999c12dccSNélio Laranjeiro 		   (op_code != MLX5_CQE_REQ)) {
17097267b8eSNelio Laranjeiro 		if (!check_cqe_seen(cqe))
17199c12dccSNélio Laranjeiro 			ERROR("unexpected CQE opcode %u (0x%02x)",
17299c12dccSNélio Laranjeiro 			      op_code, op_code);
17399c12dccSNélio Laranjeiro 		return 1;
1746218063bSNélio Laranjeiro 	}
17599c12dccSNélio Laranjeiro #endif /* NDEBUG */
17699c12dccSNélio Laranjeiro 	return 0;
1776218063bSNélio Laranjeiro }
1782e22920bSAdrien Mazarguil 
179fdcb0f53SNélio Laranjeiro /**
180fdcb0f53SNélio Laranjeiro  * Return the address of the WQE.
181fdcb0f53SNélio Laranjeiro  *
182fdcb0f53SNélio Laranjeiro  * @param txq
183fdcb0f53SNélio Laranjeiro  *   Pointer to TX queue structure.
184fdcb0f53SNélio Laranjeiro  * @param  wqe_ci
185fdcb0f53SNélio Laranjeiro  *   WQE consumer index.
186fdcb0f53SNélio Laranjeiro  *
187fdcb0f53SNélio Laranjeiro  * @return
188fdcb0f53SNélio Laranjeiro  *   WQE address.
189fdcb0f53SNélio Laranjeiro  */
190fdcb0f53SNélio Laranjeiro static inline uintptr_t *
191fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(struct txq *txq, uint16_t ci)
192fdcb0f53SNélio Laranjeiro {
193fdcb0f53SNélio Laranjeiro 	ci &= ((1 << txq->wqe_n) - 1);
194fdcb0f53SNélio Laranjeiro 	return (uintptr_t *)((uintptr_t)txq->wqes + ci * MLX5_WQE_SIZE);
195fdcb0f53SNélio Laranjeiro }
196fdcb0f53SNélio Laranjeiro 
1972e22920bSAdrien Mazarguil /**
1986ce84bd8SYongseok Koh  * Return the size of tailroom of WQ.
1996ce84bd8SYongseok Koh  *
2006ce84bd8SYongseok Koh  * @param txq
2016ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
2026ce84bd8SYongseok Koh  * @param addr
2036ce84bd8SYongseok Koh  *   Pointer to tail of WQ.
2046ce84bd8SYongseok Koh  *
2056ce84bd8SYongseok Koh  * @return
2066ce84bd8SYongseok Koh  *   Size of tailroom.
2076ce84bd8SYongseok Koh  */
2086ce84bd8SYongseok Koh static inline size_t
2096ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr)
2106ce84bd8SYongseok Koh {
2116ce84bd8SYongseok Koh 	size_t tailroom;
2126ce84bd8SYongseok Koh 	tailroom = (uintptr_t)(txq->wqes) +
2136ce84bd8SYongseok Koh 		   (1 << txq->wqe_n) * MLX5_WQE_SIZE -
2146ce84bd8SYongseok Koh 		   (uintptr_t)addr;
2156ce84bd8SYongseok Koh 	return tailroom;
2166ce84bd8SYongseok Koh }
2176ce84bd8SYongseok Koh 
2186ce84bd8SYongseok Koh /**
2196ce84bd8SYongseok Koh  * Copy data to tailroom of circular queue.
2206ce84bd8SYongseok Koh  *
2216ce84bd8SYongseok Koh  * @param dst
2226ce84bd8SYongseok Koh  *   Pointer to destination.
2236ce84bd8SYongseok Koh  * @param src
2246ce84bd8SYongseok Koh  *   Pointer to source.
2256ce84bd8SYongseok Koh  * @param n
2266ce84bd8SYongseok Koh  *   Number of bytes to copy.
2276ce84bd8SYongseok Koh  * @param base
2286ce84bd8SYongseok Koh  *   Pointer to head of queue.
2296ce84bd8SYongseok Koh  * @param tailroom
2306ce84bd8SYongseok Koh  *   Size of tailroom from dst.
2316ce84bd8SYongseok Koh  *
2326ce84bd8SYongseok Koh  * @return
2336ce84bd8SYongseok Koh  *   Pointer after copied data.
2346ce84bd8SYongseok Koh  */
2356ce84bd8SYongseok Koh static inline void *
2366ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n,
2376ce84bd8SYongseok Koh 		void *base, size_t tailroom)
2386ce84bd8SYongseok Koh {
2396ce84bd8SYongseok Koh 	void *ret;
2406ce84bd8SYongseok Koh 
2416ce84bd8SYongseok Koh 	if (n > tailroom) {
2426ce84bd8SYongseok Koh 		rte_memcpy(dst, src, tailroom);
2436ce84bd8SYongseok Koh 		rte_memcpy(base, (void *)((uintptr_t)src + tailroom),
2446ce84bd8SYongseok Koh 			   n - tailroom);
2456ce84bd8SYongseok Koh 		ret = (uint8_t *)base + n - tailroom;
2466ce84bd8SYongseok Koh 	} else {
2476ce84bd8SYongseok Koh 		rte_memcpy(dst, src, n);
2486ce84bd8SYongseok Koh 		ret = (n == tailroom) ? base : (uint8_t *)dst + n;
2496ce84bd8SYongseok Koh 	}
2506ce84bd8SYongseok Koh 	return ret;
2516ce84bd8SYongseok Koh }
2526ce84bd8SYongseok Koh 
2536ce84bd8SYongseok Koh /**
2542e22920bSAdrien Mazarguil  * Manage TX completions.
2552e22920bSAdrien Mazarguil  *
2562e22920bSAdrien Mazarguil  * When sending a burst, mlx5_tx_burst() posts several WRs.
2572e22920bSAdrien Mazarguil  *
2582e22920bSAdrien Mazarguil  * @param txq
2592e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
2602e22920bSAdrien Mazarguil  */
261a6ca35aaSNélio Laranjeiro static inline void
2622e22920bSAdrien Mazarguil txq_complete(struct txq *txq)
2632e22920bSAdrien Mazarguil {
264b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
265e2f116eeSNélio Laranjeiro 	const unsigned int cqe_n = 1 << txq->cqe_n;
26699c12dccSNélio Laranjeiro 	const unsigned int cqe_cnt = cqe_n - 1;
2671d88ba17SNélio Laranjeiro 	uint16_t elts_free = txq->elts_tail;
2681d88ba17SNélio Laranjeiro 	uint16_t elts_tail;
2691d88ba17SNélio Laranjeiro 	uint16_t cq_ci = txq->cq_ci;
27097267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe = NULL;
271fdcb0f53SNélio Laranjeiro 	volatile struct mlx5_wqe_ctrl *ctrl;
2722e22920bSAdrien Mazarguil 
27399c12dccSNélio Laranjeiro 	do {
27497267b8eSNelio Laranjeiro 		volatile struct mlx5_cqe *tmp;
2751d88ba17SNélio Laranjeiro 
27697267b8eSNelio Laranjeiro 		tmp = &(*txq->cqes)[cq_ci & cqe_cnt];
27797267b8eSNelio Laranjeiro 		if (check_cqe(tmp, cqe_n, cq_ci))
2781d88ba17SNélio Laranjeiro 			break;
279c305090bSAdrien Mazarguil 		cqe = tmp;
28099c12dccSNélio Laranjeiro #ifndef NDEBUG
28199c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) {
28297267b8eSNelio Laranjeiro 			if (!check_cqe_seen(cqe))
28399c12dccSNélio Laranjeiro 				ERROR("unexpected compressed CQE, TX stopped");
28499c12dccSNélio Laranjeiro 			return;
2852e22920bSAdrien Mazarguil 		}
28699c12dccSNélio Laranjeiro 		if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) ||
28799c12dccSNélio Laranjeiro 		    (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) {
28897267b8eSNelio Laranjeiro 			if (!check_cqe_seen(cqe))
28999c12dccSNélio Laranjeiro 				ERROR("unexpected error CQE, TX stopped");
29099c12dccSNélio Laranjeiro 			return;
29199c12dccSNélio Laranjeiro 		}
29299c12dccSNélio Laranjeiro #endif /* NDEBUG */
29399c12dccSNélio Laranjeiro 		++cq_ci;
29499c12dccSNélio Laranjeiro 	} while (1);
295c305090bSAdrien Mazarguil 	if (unlikely(cqe == NULL))
2961d88ba17SNélio Laranjeiro 		return;
297f04f1d51SNélio Laranjeiro 	txq->wqe_pi = ntohs(cqe->wqe_counter);
298fdcb0f53SNélio Laranjeiro 	ctrl = (volatile struct mlx5_wqe_ctrl *)
299f04f1d51SNélio Laranjeiro 		tx_mlx5_wqe(txq, txq->wqe_pi);
300fdcb0f53SNélio Laranjeiro 	elts_tail = ctrl->ctrl3;
301a821d09dSNélio Laranjeiro 	assert(elts_tail < (1 << txq->wqe_n));
3021d88ba17SNélio Laranjeiro 	/* Free buffers. */
303c305090bSAdrien Mazarguil 	while (elts_free != elts_tail) {
3041d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt = (*txq->elts)[elts_free];
305a859e8a9SNelio Laranjeiro 		unsigned int elts_free_next =
3061d88ba17SNélio Laranjeiro 			(elts_free + 1) & (elts_n - 1);
3071d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next];
308a859e8a9SNelio Laranjeiro 
309b185e63fSAdrien Mazarguil #ifndef NDEBUG
310b185e63fSAdrien Mazarguil 		/* Poisoning. */
3111d88ba17SNélio Laranjeiro 		memset(&(*txq->elts)[elts_free],
3121d88ba17SNélio Laranjeiro 		       0x66,
3131d88ba17SNélio Laranjeiro 		       sizeof((*txq->elts)[elts_free]));
314b185e63fSAdrien Mazarguil #endif
3151d88ba17SNélio Laranjeiro 		RTE_MBUF_PREFETCH_TO_FREE(elt_next);
3161d88ba17SNélio Laranjeiro 		/* Only one segment needs to be freed. */
3171d88ba17SNélio Laranjeiro 		rte_pktmbuf_free_seg(elt);
318a859e8a9SNelio Laranjeiro 		elts_free = elts_free_next;
319c305090bSAdrien Mazarguil 	}
3201d88ba17SNélio Laranjeiro 	txq->cq_ci = cq_ci;
3212e22920bSAdrien Mazarguil 	txq->elts_tail = elts_tail;
3221d88ba17SNélio Laranjeiro 	/* Update the consumer index. */
3231d88ba17SNélio Laranjeiro 	rte_wmb();
3241d88ba17SNélio Laranjeiro 	*txq->cq_db = htonl(cq_ci);
3252e22920bSAdrien Mazarguil }
3262e22920bSAdrien Mazarguil 
3272e22920bSAdrien Mazarguil /**
3288340392eSAdrien Mazarguil  * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
3298340392eSAdrien Mazarguil  * the cloned mbuf is allocated is returned instead.
3308340392eSAdrien Mazarguil  *
3318340392eSAdrien Mazarguil  * @param buf
3328340392eSAdrien Mazarguil  *   Pointer to mbuf.
3338340392eSAdrien Mazarguil  *
3348340392eSAdrien Mazarguil  * @return
3358340392eSAdrien Mazarguil  *   Memory pool where data is located for given mbuf.
3368340392eSAdrien Mazarguil  */
3378340392eSAdrien Mazarguil static struct rte_mempool *
3388340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf)
3398340392eSAdrien Mazarguil {
3408340392eSAdrien Mazarguil 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
3418340392eSAdrien Mazarguil 		return rte_mbuf_from_indirect(buf)->pool;
3428340392eSAdrien Mazarguil 	return buf->pool;
3438340392eSAdrien Mazarguil }
3448340392eSAdrien Mazarguil 
3458340392eSAdrien Mazarguil /**
3462e22920bSAdrien Mazarguil  * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[].
3472e22920bSAdrien Mazarguil  * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
3482e22920bSAdrien Mazarguil  * remove an entry first.
3492e22920bSAdrien Mazarguil  *
3502e22920bSAdrien Mazarguil  * @param txq
3512e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
3522e22920bSAdrien Mazarguil  * @param[in] mp
3532e22920bSAdrien Mazarguil  *   Memory Pool for which a Memory Region lkey must be returned.
3542e22920bSAdrien Mazarguil  *
3552e22920bSAdrien Mazarguil  * @return
3562e22920bSAdrien Mazarguil  *   mr->lkey on success, (uint32_t)-1 on failure.
3572e22920bSAdrien Mazarguil  */
358491770faSNélio Laranjeiro static inline uint32_t
359d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
3602e22920bSAdrien Mazarguil {
3612e22920bSAdrien Mazarguil 	unsigned int i;
362491770faSNélio Laranjeiro 	uint32_t lkey = (uint32_t)-1;
3632e22920bSAdrien Mazarguil 
3642e22920bSAdrien Mazarguil 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
3652e22920bSAdrien Mazarguil 		if (unlikely(txq->mp2mr[i].mp == NULL)) {
3662e22920bSAdrien Mazarguil 			/* Unknown MP, add a new MR for it. */
3672e22920bSAdrien Mazarguil 			break;
3682e22920bSAdrien Mazarguil 		}
3692e22920bSAdrien Mazarguil 		if (txq->mp2mr[i].mp == mp) {
3702e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].lkey != (uint32_t)-1);
3711d88ba17SNélio Laranjeiro 			assert(htonl(txq->mp2mr[i].mr->lkey) ==
3721d88ba17SNélio Laranjeiro 			       txq->mp2mr[i].lkey);
373491770faSNélio Laranjeiro 			lkey = txq->mp2mr[i].lkey;
374491770faSNélio Laranjeiro 			break;
3752e22920bSAdrien Mazarguil 		}
3762e22920bSAdrien Mazarguil 	}
377491770faSNélio Laranjeiro 	if (unlikely(lkey == (uint32_t)-1))
378491770faSNélio Laranjeiro 		lkey = txq_mp2mr_reg(txq, mp, i);
379491770faSNélio Laranjeiro 	return lkey;
3800a3b350dSOlga Shern }
3810a3b350dSOlga Shern 
382e192ef80SYaacov Hazan /**
3831d88ba17SNélio Laranjeiro  * Ring TX queue doorbell.
3841d88ba17SNélio Laranjeiro  *
3851d88ba17SNélio Laranjeiro  * @param txq
3861d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
38730807f62SNélio Laranjeiro  * @param wqe
38830807f62SNélio Laranjeiro  *   Pointer to the last WQE posted in the NIC.
3891d88ba17SNélio Laranjeiro  */
3901d88ba17SNélio Laranjeiro static inline void
39130807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe)
3921d88ba17SNélio Laranjeiro {
39330807f62SNélio Laranjeiro 	uint64_t *dst = (uint64_t *)((uintptr_t)txq->bf_reg);
39430807f62SNélio Laranjeiro 	volatile uint64_t *src = ((volatile uint64_t *)wqe);
39530807f62SNélio Laranjeiro 
3961d88ba17SNélio Laranjeiro 	rte_wmb();
3971d88ba17SNélio Laranjeiro 	*txq->qp_db = htonl(txq->wqe_ci);
3981d88ba17SNélio Laranjeiro 	/* Ensure ordering between DB record and BF copy. */
3991d88ba17SNélio Laranjeiro 	rte_wmb();
40030807f62SNélio Laranjeiro 	*dst = *src;
4011d88ba17SNélio Laranjeiro }
402e192ef80SYaacov Hazan 
4031d88ba17SNélio Laranjeiro /**
4048788fec1SOlivier Matz  * DPDK callback to check the status of a tx descriptor.
4058788fec1SOlivier Matz  *
4068788fec1SOlivier Matz  * @param tx_queue
4078788fec1SOlivier Matz  *   The tx queue.
4088788fec1SOlivier Matz  * @param[in] offset
4098788fec1SOlivier Matz  *   The index of the descriptor in the ring.
4108788fec1SOlivier Matz  *
4118788fec1SOlivier Matz  * @return
4128788fec1SOlivier Matz  *   The status of the tx descriptor.
4138788fec1SOlivier Matz  */
4148788fec1SOlivier Matz int
4158788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
4168788fec1SOlivier Matz {
4178788fec1SOlivier Matz 	struct txq *txq = tx_queue;
4188788fec1SOlivier Matz 	const unsigned int elts_n = 1 << txq->elts_n;
4198788fec1SOlivier Matz 	const unsigned int elts_cnt = elts_n - 1;
4208788fec1SOlivier Matz 	unsigned int used;
4218788fec1SOlivier Matz 
4228788fec1SOlivier Matz 	txq_complete(txq);
4238788fec1SOlivier Matz 	used = (txq->elts_head - txq->elts_tail) & elts_cnt;
4248788fec1SOlivier Matz 	if (offset < used)
4258788fec1SOlivier Matz 		return RTE_ETH_TX_DESC_FULL;
4268788fec1SOlivier Matz 	return RTE_ETH_TX_DESC_DONE;
4278788fec1SOlivier Matz }
4288788fec1SOlivier Matz 
4298788fec1SOlivier Matz /**
4308788fec1SOlivier Matz  * DPDK callback to check the status of a rx descriptor.
4318788fec1SOlivier Matz  *
4328788fec1SOlivier Matz  * @param rx_queue
4338788fec1SOlivier Matz  *   The rx queue.
4348788fec1SOlivier Matz  * @param[in] offset
4358788fec1SOlivier Matz  *   The index of the descriptor in the ring.
4368788fec1SOlivier Matz  *
4378788fec1SOlivier Matz  * @return
4388788fec1SOlivier Matz  *   The status of the tx descriptor.
4398788fec1SOlivier Matz  */
4408788fec1SOlivier Matz int
4418788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
4428788fec1SOlivier Matz {
4438788fec1SOlivier Matz 	struct rxq *rxq = rx_queue;
4448788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
4458788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
4468788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
4478788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
4488788fec1SOlivier Matz 	unsigned int cq_ci;
4498788fec1SOlivier Matz 	unsigned int used;
4508788fec1SOlivier Matz 
4518788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
4528788fec1SOlivier Matz 	if (zip->ai) {
4538788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
4548788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
4558788fec1SOlivier Matz 	} else {
4568788fec1SOlivier Matz 		used = 0;
4578788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
4588788fec1SOlivier Matz 	}
4598788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
4608788fec1SOlivier Matz 	while (check_cqe(cqe, cqe_n, cq_ci) == 0) {
4618788fec1SOlivier Matz 		int8_t op_own;
4628788fec1SOlivier Matz 		unsigned int n;
4638788fec1SOlivier Matz 
4648788fec1SOlivier Matz 		op_own = cqe->op_own;
4658788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
4668788fec1SOlivier Matz 			n = ntohl(cqe->byte_cnt);
4678788fec1SOlivier Matz 		else
4688788fec1SOlivier Matz 			n = 1;
4698788fec1SOlivier Matz 		cq_ci += n;
4708788fec1SOlivier Matz 		used += n;
4718788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
4728788fec1SOlivier Matz 	}
4738788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
4748788fec1SOlivier Matz 	if (offset < used)
4758788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
4768788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
4778788fec1SOlivier Matz }
4788788fec1SOlivier Matz 
4798788fec1SOlivier Matz /**
4802e22920bSAdrien Mazarguil  * DPDK callback for TX.
4812e22920bSAdrien Mazarguil  *
4822e22920bSAdrien Mazarguil  * @param dpdk_txq
4832e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
4842e22920bSAdrien Mazarguil  * @param[in] pkts
4852e22920bSAdrien Mazarguil  *   Packets to transmit.
4862e22920bSAdrien Mazarguil  * @param pkts_n
4872e22920bSAdrien Mazarguil  *   Number of packets in array.
4882e22920bSAdrien Mazarguil  *
4892e22920bSAdrien Mazarguil  * @return
4902e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
4912e22920bSAdrien Mazarguil  */
4922e22920bSAdrien Mazarguil uint16_t
4932e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
4942e22920bSAdrien Mazarguil {
4952e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
4961d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
497b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
498c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
499a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
5003f13f8c2SShahaf Shuler 	unsigned int k = 0;
5012e22920bSAdrien Mazarguil 	unsigned int max;
502*ab76eab3SYongseok Koh 	unsigned int max_inline = txq->max_inline;
503*ab76eab3SYongseok Koh 	const unsigned int inline_en = !!max_inline && txq->inline_en;
504f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
505c305090bSAdrien Mazarguil 	unsigned int comp;
5069a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
5076579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
5086579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
5096579c27cSNélio Laranjeiro 	uint8_t *raw;
5102e22920bSAdrien Mazarguil 
5111d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
5121d88ba17SNélio Laranjeiro 		return 0;
5135e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
514c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
5151d88ba17SNélio Laranjeiro 	/* Start processing. */
5162e22920bSAdrien Mazarguil 	txq_complete(txq);
5174f52bbfbSNelio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
5182e22920bSAdrien Mazarguil 	if (max > elts_n)
5192e22920bSAdrien Mazarguil 		max -= elts_n;
520f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
521f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
522f04f1d51SNélio Laranjeiro 		return 0;
523c3d62cc9SAdrien Mazarguil 	do {
5249a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
525573f54afSNélio Laranjeiro 		uint32_t length;
5268688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
5276579c27cSNélio Laranjeiro 		uintptr_t addr;
5289a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
5290d637a34SNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2;
5303f13f8c2SShahaf Shuler 		uint16_t tso_header_sz = 0;
531eef822ddSNélio Laranjeiro 		uint16_t ehdr;
5329a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
5333f13f8c2SShahaf Shuler 		uint64_t tso = 0;
5346579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
5356579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
5366579c27cSNélio Laranjeiro #endif
5372e22920bSAdrien Mazarguil 
5386579c27cSNélio Laranjeiro 		/* first_seg */
5396579c27cSNélio Laranjeiro 		buf = *(pkts++);
5406579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
541c3d62cc9SAdrien Mazarguil 		/*
542c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
543c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
544c3d62cc9SAdrien Mazarguil 		 */
545a5bf6af9SAdrien Mazarguil 		assert(segs_n);
546a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
547c3d62cc9SAdrien Mazarguil 			break;
548a5bf6af9SAdrien Mazarguil 		max -= segs_n;
5496579c27cSNélio Laranjeiro 		--segs_n;
5506579c27cSNélio Laranjeiro 		if (!segs_n)
551c3d62cc9SAdrien Mazarguil 			--pkts_n;
552f04f1d51SNélio Laranjeiro 		if (unlikely(--max_wqe == 0))
553f04f1d51SNélio Laranjeiro 			break;
5549a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
555fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
556fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
5576579c27cSNélio Laranjeiro 		if (pkts_n > 1)
558c3d62cc9SAdrien Mazarguil 			rte_prefetch0(*pkts);
5596579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
5602e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
561eef822ddSNélio Laranjeiro 		ehdr = (((uint8_t *)addr)[1] << 8) |
562eef822ddSNélio Laranjeiro 		       ((uint8_t *)addr)[0];
5636579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
5646579c27cSNélio Laranjeiro 		total_length = length;
5656579c27cSNélio Laranjeiro #endif
566959be52eSNélio Laranjeiro 		if (length < (MLX5_WQE_DWORD_SIZE + 2))
567959be52eSNélio Laranjeiro 			break;
5682e22920bSAdrien Mazarguil 		/* Update element. */
5691d88ba17SNélio Laranjeiro 		(*txq->elts)[elts_head] = buf;
5706579c27cSNélio Laranjeiro 		elts_head = (elts_head + 1) & (elts_n - 1);
5715e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
5726579c27cSNélio Laranjeiro 		if (pkts_n > 1) {
5736579c27cSNélio Laranjeiro 			volatile void *pkt_addr;
5746579c27cSNélio Laranjeiro 
5756579c27cSNélio Laranjeiro 			pkt_addr = rte_pktmbuf_mtod(*pkts, volatile void *);
5766579c27cSNélio Laranjeiro 			rte_prefetch0(pkt_addr);
5776579c27cSNélio Laranjeiro 		}
5781d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
5791d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
5801d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
581f5fde520SShahaf Shuler 			const uint64_t is_tunneled = buf->ol_flags &
582f5fde520SShahaf Shuler 						     (PKT_TX_TUNNEL_GRE |
583f5fde520SShahaf Shuler 						      PKT_TX_TUNNEL_VXLAN);
584f5fde520SShahaf Shuler 
585f5fde520SShahaf Shuler 			if (is_tunneled && txq->tunnel_en) {
586f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM |
587f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_INNER_CSUM;
588f5fde520SShahaf Shuler 				if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
589f5fde520SShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L3_CSUM;
590f5fde520SShahaf Shuler 			} else {
591f5fde520SShahaf Shuler 				cs_flags = MLX5_ETH_WQE_L3_CSUM |
592f5fde520SShahaf Shuler 					   MLX5_ETH_WQE_L4_CSUM;
593f5fde520SShahaf Shuler 			}
5941d88ba17SNélio Laranjeiro 		}
595b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
5966579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
5976579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
5986579c27cSNélio Laranjeiro 			uint32_t vlan = htonl(0x81000000 | buf->vlan_tci);
5990d637a34SNélio Laranjeiro 			unsigned int len = 2 * ETHER_ADDR_LEN - 2;
6006579c27cSNélio Laranjeiro 
6010d637a34SNélio Laranjeiro 			addr += 2;
6020d637a34SNélio Laranjeiro 			length -= 2;
6030d637a34SNélio Laranjeiro 			/* Copy Destination and source mac address. */
6040d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr), len);
6050d637a34SNélio Laranjeiro 			/* Copy VLAN. */
6060d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan));
6070d637a34SNélio Laranjeiro 			/* Copy missing two bytes to end the DSeg. */
6080d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw + len + sizeof(vlan),
6090d637a34SNélio Laranjeiro 			       ((uint8_t *)addr) + len, 2);
6100d637a34SNélio Laranjeiro 			addr += len + 2;
6110d637a34SNélio Laranjeiro 			length -= (len + 2);
6120d637a34SNélio Laranjeiro 		} else {
6130d637a34SNélio Laranjeiro 			memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2,
6140d637a34SNélio Laranjeiro 			       MLX5_WQE_DWORD_SIZE);
6150d637a34SNélio Laranjeiro 			length -= pkt_inline_sz;
6160d637a34SNélio Laranjeiro 			addr += pkt_inline_sz;
6176579c27cSNélio Laranjeiro 		}
6183f13f8c2SShahaf Shuler 		if (txq->tso_en) {
6193f13f8c2SShahaf Shuler 			tso = buf->ol_flags & PKT_TX_TCP_SEG;
6203f13f8c2SShahaf Shuler 			if (tso) {
6213f13f8c2SShahaf Shuler 				uintptr_t end = (uintptr_t)
6223f13f8c2SShahaf Shuler 						(((uintptr_t)txq->wqes) +
6233f13f8c2SShahaf Shuler 						(1 << txq->wqe_n) *
6243f13f8c2SShahaf Shuler 						MLX5_WQE_SIZE);
6253f13f8c2SShahaf Shuler 				unsigned int copy_b;
6263f13f8c2SShahaf Shuler 				uint8_t vlan_sz = (buf->ol_flags &
6273f13f8c2SShahaf Shuler 						  PKT_TX_VLAN_PKT) ? 4 : 0;
628b247f346SShahaf Shuler 				const uint64_t is_tunneled =
629b247f346SShahaf Shuler 							buf->ol_flags &
630b247f346SShahaf Shuler 							(PKT_TX_TUNNEL_GRE |
631b247f346SShahaf Shuler 							 PKT_TX_TUNNEL_VXLAN);
6323f13f8c2SShahaf Shuler 
6333f13f8c2SShahaf Shuler 				tso_header_sz = buf->l2_len + vlan_sz +
6343f13f8c2SShahaf Shuler 						buf->l3_len + buf->l4_len;
6353f13f8c2SShahaf Shuler 
636b247f346SShahaf Shuler 				if (is_tunneled	&& txq->tunnel_en) {
637b247f346SShahaf Shuler 					tso_header_sz += buf->outer_l2_len +
638b247f346SShahaf Shuler 							 buf->outer_l3_len;
6392a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM;
6402a6c96beSShahaf Shuler 				} else {
6412a6c96beSShahaf Shuler 					cs_flags |= MLX5_ETH_WQE_L4_CSUM;
642b247f346SShahaf Shuler 				}
6433f13f8c2SShahaf Shuler 				if (unlikely(tso_header_sz >
6443f13f8c2SShahaf Shuler 					     MLX5_MAX_TSO_HEADER))
6453f13f8c2SShahaf Shuler 					break;
6463f13f8c2SShahaf Shuler 				copy_b = tso_header_sz - pkt_inline_sz;
6473f13f8c2SShahaf Shuler 				/* First seg must contain all headers. */
6483f13f8c2SShahaf Shuler 				assert(copy_b <= length);
6493f13f8c2SShahaf Shuler 				raw += MLX5_WQE_DWORD_SIZE;
6503f13f8c2SShahaf Shuler 				if (copy_b &&
6513f13f8c2SShahaf Shuler 				   ((end - (uintptr_t)raw) > copy_b)) {
6523f13f8c2SShahaf Shuler 					uint16_t n = (MLX5_WQE_DS(copy_b) -
6533f13f8c2SShahaf Shuler 						      1 + 3) / 4;
6543f13f8c2SShahaf Shuler 
6553f13f8c2SShahaf Shuler 					if (unlikely(max_wqe < n))
6563f13f8c2SShahaf Shuler 						break;
6573f13f8c2SShahaf Shuler 					max_wqe -= n;
6583f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
6593f13f8c2SShahaf Shuler 						   (void *)addr, copy_b);
6603f13f8c2SShahaf Shuler 					addr += copy_b;
6613f13f8c2SShahaf Shuler 					length -= copy_b;
6623f13f8c2SShahaf Shuler 					pkt_inline_sz += copy_b;
6633f13f8c2SShahaf Shuler 					/*
6643f13f8c2SShahaf Shuler 					 * Another DWORD will be added
6653f13f8c2SShahaf Shuler 					 * in the inline part.
6663f13f8c2SShahaf Shuler 					 */
6673f13f8c2SShahaf Shuler 					raw += MLX5_WQE_DS(copy_b) *
6683f13f8c2SShahaf Shuler 					       MLX5_WQE_DWORD_SIZE -
6693f13f8c2SShahaf Shuler 					       MLX5_WQE_DWORD_SIZE;
6703f13f8c2SShahaf Shuler 				} else {
6713f13f8c2SShahaf Shuler 					/* NOP WQE. */
6723f13f8c2SShahaf Shuler 					wqe->ctrl = (rte_v128u32_t){
6733f13f8c2SShahaf Shuler 						     htonl(txq->wqe_ci << 8),
6743f13f8c2SShahaf Shuler 						     htonl(txq->qp_num_8s | 1),
6753f13f8c2SShahaf Shuler 						     0,
6763f13f8c2SShahaf Shuler 						     0,
6773f13f8c2SShahaf Shuler 					};
6783f13f8c2SShahaf Shuler 					ds = 1;
6793f13f8c2SShahaf Shuler 					total_length = 0;
6803f13f8c2SShahaf Shuler 					pkts--;
6813f13f8c2SShahaf Shuler 					pkts_n++;
6823f13f8c2SShahaf Shuler 					elts_head = (elts_head - 1) &
6833f13f8c2SShahaf Shuler 						    (elts_n - 1);
6843f13f8c2SShahaf Shuler 					k++;
6853f13f8c2SShahaf Shuler 					goto next_wqe;
6863f13f8c2SShahaf Shuler 				}
6873f13f8c2SShahaf Shuler 			}
6883f13f8c2SShahaf Shuler 		}
6896579c27cSNélio Laranjeiro 		/* Inline if enough room. */
690*ab76eab3SYongseok Koh 		if (inline_en || tso) {
691fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
692fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
693fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
694*ab76eab3SYongseok Koh 			unsigned int inline_room = max_inline *
6958fcd6c2cSNélio Laranjeiro 						   RTE_CACHE_LINE_SIZE -
6963f13f8c2SShahaf Shuler 						   (pkt_inline_sz - 2);
697*ab76eab3SYongseok Koh 			uintptr_t addr_end = (addr + inline_room) &
6986579c27cSNélio Laranjeiro 					     ~(RTE_CACHE_LINE_SIZE - 1);
6998fcd6c2cSNélio Laranjeiro 			unsigned int copy_b = (addr_end > addr) ?
7008fcd6c2cSNélio Laranjeiro 				RTE_MIN((addr_end - addr), length) :
7018fcd6c2cSNélio Laranjeiro 				0;
7026579c27cSNélio Laranjeiro 
7038fcd6c2cSNélio Laranjeiro 			raw += MLX5_WQE_DWORD_SIZE;
7048fcd6c2cSNélio Laranjeiro 			if (copy_b && ((end - (uintptr_t)raw) > copy_b)) {
705f04f1d51SNélio Laranjeiro 				/*
706f04f1d51SNélio Laranjeiro 				 * One Dseg remains in the current WQE.  To
707f04f1d51SNélio Laranjeiro 				 * keep the computation positive, it is
708f04f1d51SNélio Laranjeiro 				 * removed after the bytes to Dseg conversion.
709f04f1d51SNélio Laranjeiro 				 */
7108fcd6c2cSNélio Laranjeiro 				uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4;
7118fcd6c2cSNélio Laranjeiro 
712f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < n))
713f04f1d51SNélio Laranjeiro 					break;
714f04f1d51SNélio Laranjeiro 				max_wqe -= n;
7153f13f8c2SShahaf Shuler 				if (tso) {
7163f13f8c2SShahaf Shuler 					uint32_t inl =
7173f13f8c2SShahaf Shuler 						htonl(copy_b | MLX5_INLINE_SEG);
7183f13f8c2SShahaf Shuler 
7193f13f8c2SShahaf Shuler 					pkt_inline_sz =
7203f13f8c2SShahaf Shuler 						MLX5_WQE_DS(tso_header_sz) *
7213f13f8c2SShahaf Shuler 						MLX5_WQE_DWORD_SIZE;
7223f13f8c2SShahaf Shuler 					rte_memcpy((void *)raw,
7233f13f8c2SShahaf Shuler 						   (void *)&inl, sizeof(inl));
7243f13f8c2SShahaf Shuler 					raw += sizeof(inl);
7253f13f8c2SShahaf Shuler 					pkt_inline_sz += sizeof(inl);
7263f13f8c2SShahaf Shuler 				}
7276579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
7286579c27cSNélio Laranjeiro 				addr += copy_b;
7296579c27cSNélio Laranjeiro 				length -= copy_b;
7306579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
7316579c27cSNélio Laranjeiro 			}
7326579c27cSNélio Laranjeiro 			/*
733786b5c2dSShahaf Shuler 			 * 2 DWORDs consumed by the WQE header + ETH segment +
7346579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
7356579c27cSNélio Laranjeiro 			 */
7366579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
7376579c27cSNélio Laranjeiro 			if (length > 0) {
738f04f1d51SNélio Laranjeiro 				if (ds % (MLX5_WQE_SIZE /
739f04f1d51SNélio Laranjeiro 					  MLX5_WQE_DWORD_SIZE) == 0) {
740f04f1d51SNélio Laranjeiro 					if (unlikely(--max_wqe == 0))
741f04f1d51SNélio Laranjeiro 						break;
742f04f1d51SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
743f04f1d51SNélio Laranjeiro 					       tx_mlx5_wqe(txq, txq->wqe_ci +
744f04f1d51SNélio Laranjeiro 							   ds / 4);
745f04f1d51SNélio Laranjeiro 				} else {
7469a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
7476579c27cSNélio Laranjeiro 						((uintptr_t)wqe +
7486579c27cSNélio Laranjeiro 						 (ds * MLX5_WQE_DWORD_SIZE));
749f04f1d51SNélio Laranjeiro 				}
7506579c27cSNélio Laranjeiro 				goto use_dseg;
7516579c27cSNélio Laranjeiro 			} else if (!segs_n) {
7526579c27cSNélio Laranjeiro 				goto next_pkt;
7536579c27cSNélio Laranjeiro 			} else {
754786b5c2dSShahaf Shuler 				/* dseg will be advance as part of next_seg */
755786b5c2dSShahaf Shuler 				dseg = (volatile rte_v128u32_t *)
756786b5c2dSShahaf Shuler 					((uintptr_t)wqe +
757786b5c2dSShahaf Shuler 					 ((ds - 1) * MLX5_WQE_DWORD_SIZE));
7586579c27cSNélio Laranjeiro 				goto next_seg;
7596579c27cSNélio Laranjeiro 			}
7606579c27cSNélio Laranjeiro 		} else {
7616579c27cSNélio Laranjeiro 			/*
7626579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
7636579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
7646579c27cSNélio Laranjeiro 			 */
7659a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
7666579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
7676579c27cSNélio Laranjeiro 			ds = 3;
7686579c27cSNélio Laranjeiro use_dseg:
7696579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
7709a7fa9f7SNélio Laranjeiro 			naddr = htonll(addr);
7719a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
7729a7fa9f7SNélio Laranjeiro 				htonl(length),
7739a7fa9f7SNélio Laranjeiro 				txq_mp2mr(txq, txq_mb2mp(buf)),
7749a7fa9f7SNélio Laranjeiro 				naddr,
7759a7fa9f7SNélio Laranjeiro 				naddr >> 32,
7766579c27cSNélio Laranjeiro 			};
7776579c27cSNélio Laranjeiro 			++ds;
7786579c27cSNélio Laranjeiro 			if (!segs_n)
7796579c27cSNélio Laranjeiro 				goto next_pkt;
7806579c27cSNélio Laranjeiro 		}
7816579c27cSNélio Laranjeiro next_seg:
7826579c27cSNélio Laranjeiro 		assert(buf);
7836579c27cSNélio Laranjeiro 		assert(ds);
7846579c27cSNélio Laranjeiro 		assert(wqe);
785a5bf6af9SAdrien Mazarguil 		/*
786a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
787a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
788a5bf6af9SAdrien Mazarguil 		 * of data segment size.
789a5bf6af9SAdrien Mazarguil 		 */
7908688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
7916579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
792f04f1d51SNélio Laranjeiro 			if (unlikely(--max_wqe == 0))
793f04f1d51SNélio Laranjeiro 				break;
7949a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
795f04f1d51SNélio Laranjeiro 			       tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4);
796f04f1d51SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq,
797f04f1d51SNélio Laranjeiro 						  txq->wqe_ci + ds / 4 + 1));
7986579c27cSNélio Laranjeiro 		} else {
799a5bf6af9SAdrien Mazarguil 			++dseg;
8006579c27cSNélio Laranjeiro 		}
801a5bf6af9SAdrien Mazarguil 		++ds;
802a5bf6af9SAdrien Mazarguil 		buf = buf->next;
803a5bf6af9SAdrien Mazarguil 		assert(buf);
8046579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
805a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
8066579c27cSNélio Laranjeiro 		total_length += length;
807a5bf6af9SAdrien Mazarguil #endif
8086579c27cSNélio Laranjeiro 		/* Store segment information. */
8099a7fa9f7SNélio Laranjeiro 		naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t));
8109a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
8119a7fa9f7SNélio Laranjeiro 			htonl(length),
8129a7fa9f7SNélio Laranjeiro 			txq_mp2mr(txq, txq_mb2mp(buf)),
8139a7fa9f7SNélio Laranjeiro 			naddr,
8149a7fa9f7SNélio Laranjeiro 			naddr >> 32,
8156579c27cSNélio Laranjeiro 		};
8166579c27cSNélio Laranjeiro 		(*txq->elts)[elts_head] = buf;
8176579c27cSNélio Laranjeiro 		elts_head = (elts_head + 1) & (elts_n - 1);
818a5bf6af9SAdrien Mazarguil 		++j;
8196579c27cSNélio Laranjeiro 		--segs_n;
8206579c27cSNélio Laranjeiro 		if (segs_n)
8216579c27cSNélio Laranjeiro 			goto next_seg;
8226579c27cSNélio Laranjeiro 		else
8236579c27cSNélio Laranjeiro 			--pkts_n;
8246579c27cSNélio Laranjeiro next_pkt:
8256579c27cSNélio Laranjeiro 		++i;
826b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
8273f13f8c2SShahaf Shuler 		if (tso) {
8283f13f8c2SShahaf Shuler 			wqe->ctrl = (rte_v128u32_t){
8293f13f8c2SShahaf Shuler 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO),
8303f13f8c2SShahaf Shuler 				htonl(txq->qp_num_8s | ds),
8313f13f8c2SShahaf Shuler 				0,
8323f13f8c2SShahaf Shuler 				0,
8333f13f8c2SShahaf Shuler 			};
8343f13f8c2SShahaf Shuler 			wqe->eseg = (rte_v128u32_t){
8353f13f8c2SShahaf Shuler 				0,
8363f13f8c2SShahaf Shuler 				cs_flags | (htons(buf->tso_segsz) << 16),
8373f13f8c2SShahaf Shuler 				0,
8383f13f8c2SShahaf Shuler 				(ehdr << 16) | htons(tso_header_sz),
8393f13f8c2SShahaf Shuler 			};
8403f13f8c2SShahaf Shuler 		} else {
8419a7fa9f7SNélio Laranjeiro 			wqe->ctrl = (rte_v128u32_t){
8429a7fa9f7SNélio Laranjeiro 				htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
8439a7fa9f7SNélio Laranjeiro 				htonl(txq->qp_num_8s | ds),
8449a7fa9f7SNélio Laranjeiro 				0,
8459a7fa9f7SNélio Laranjeiro 				0,
8469a7fa9f7SNélio Laranjeiro 			};
8479a7fa9f7SNélio Laranjeiro 			wqe->eseg = (rte_v128u32_t){
8489a7fa9f7SNélio Laranjeiro 				0,
8499a7fa9f7SNélio Laranjeiro 				cs_flags,
8509a7fa9f7SNélio Laranjeiro 				0,
851eef822ddSNélio Laranjeiro 				(ehdr << 16) | htons(pkt_inline_sz),
8529a7fa9f7SNélio Laranjeiro 			};
8533f13f8c2SShahaf Shuler 		}
8543f13f8c2SShahaf Shuler next_wqe:
8556579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
85687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
857573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
8586579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
85987011737SAdrien Mazarguil #endif
860c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
8612e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
8623f13f8c2SShahaf Shuler 	if (unlikely((i + k) == 0))
8632e22920bSAdrien Mazarguil 		return 0;
864c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
8653f13f8c2SShahaf Shuler 	comp = txq->elts_comp + i + j + k;
866c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
8679a7fa9f7SNélio Laranjeiro 		volatile struct mlx5_wqe_ctrl *w =
8689a7fa9f7SNélio Laranjeiro 			(volatile struct mlx5_wqe_ctrl *)wqe;
8699a7fa9f7SNélio Laranjeiro 
870c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
8719a7fa9f7SNélio Laranjeiro 		w->ctrl2 = htonl(8);
872c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
8739a7fa9f7SNélio Laranjeiro 		w->ctrl3 = elts_head;
874c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
875c305090bSAdrien Mazarguil 	} else {
876c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
877c305090bSAdrien Mazarguil 	}
87887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
87987011737SAdrien Mazarguil 	/* Increment sent packets counter. */
88087011737SAdrien Mazarguil 	txq->stats.opackets += i;
88187011737SAdrien Mazarguil #endif
8822e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
88330807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)wqe);
8842e22920bSAdrien Mazarguil 	txq->elts_head = elts_head;
8852e22920bSAdrien Mazarguil 	return i;
8862e22920bSAdrien Mazarguil }
8872e22920bSAdrien Mazarguil 
8882e22920bSAdrien Mazarguil /**
889230189d9SNélio Laranjeiro  * Open a MPW session.
890230189d9SNélio Laranjeiro  *
891230189d9SNélio Laranjeiro  * @param txq
892230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
893230189d9SNélio Laranjeiro  * @param mpw
894230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
895230189d9SNélio Laranjeiro  * @param length
896230189d9SNélio Laranjeiro  *   Packet length.
897230189d9SNélio Laranjeiro  */
898230189d9SNélio Laranjeiro static inline void
899230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
900230189d9SNélio Laranjeiro {
901a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
902230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
903230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
904fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
905230189d9SNélio Laranjeiro 
906230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
907230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
908230189d9SNélio Laranjeiro 	mpw->len = length;
909230189d9SNélio Laranjeiro 	mpw->total_len = 0;
910fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
9118688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
9128688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
9138688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
9148688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
9158688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
9168688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
917c904ae25SNélio Laranjeiro 				  (txq->wqe_ci << 8) | MLX5_OPCODE_TSO);
9188688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
9198688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
9208688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
9218688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
9228688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
9238688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
924230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
925230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
926230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
927230189d9SNélio Laranjeiro }
928230189d9SNélio Laranjeiro 
929230189d9SNélio Laranjeiro /**
930230189d9SNélio Laranjeiro  * Close a MPW session.
931230189d9SNélio Laranjeiro  *
932230189d9SNélio Laranjeiro  * @param txq
933230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
934230189d9SNélio Laranjeiro  * @param mpw
935230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
936230189d9SNélio Laranjeiro  */
937230189d9SNélio Laranjeiro static inline void
938230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
939230189d9SNélio Laranjeiro {
940230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
941230189d9SNélio Laranjeiro 
942230189d9SNélio Laranjeiro 	/*
943230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
944230189d9SNélio Laranjeiro 	 * count as 2.
945230189d9SNélio Laranjeiro 	 */
9468688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num));
947230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
948230189d9SNélio Laranjeiro 	if (num < 3)
949230189d9SNélio Laranjeiro 		++txq->wqe_ci;
950230189d9SNélio Laranjeiro 	else
951230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
952fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
953fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
954230189d9SNélio Laranjeiro }
955230189d9SNélio Laranjeiro 
956230189d9SNélio Laranjeiro /**
957230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
958230189d9SNélio Laranjeiro  *
959230189d9SNélio Laranjeiro  * @param dpdk_txq
960230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
961230189d9SNélio Laranjeiro  * @param[in] pkts
962230189d9SNélio Laranjeiro  *   Packets to transmit.
963230189d9SNélio Laranjeiro  * @param pkts_n
964230189d9SNélio Laranjeiro  *   Number of packets in array.
965230189d9SNélio Laranjeiro  *
966230189d9SNélio Laranjeiro  * @return
967230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
968230189d9SNélio Laranjeiro  */
969230189d9SNélio Laranjeiro uint16_t
970230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
971230189d9SNélio Laranjeiro {
972230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
973230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
974b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
975c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
976a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
977230189d9SNélio Laranjeiro 	unsigned int max;
978f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
979230189d9SNélio Laranjeiro 	unsigned int comp;
980230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
981230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
982230189d9SNélio Laranjeiro 	};
983230189d9SNélio Laranjeiro 
984c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
985c3d62cc9SAdrien Mazarguil 		return 0;
986230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
987fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
988fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
989230189d9SNélio Laranjeiro 	/* Start processing. */
990230189d9SNélio Laranjeiro 	txq_complete(txq);
991230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
992230189d9SNélio Laranjeiro 	if (max > elts_n)
993230189d9SNélio Laranjeiro 		max -= elts_n;
994f04f1d51SNélio Laranjeiro 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
995f04f1d51SNélio Laranjeiro 	if (unlikely(!max_wqe))
996f04f1d51SNélio Laranjeiro 		return 0;
997c3d62cc9SAdrien Mazarguil 	do {
998a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
999c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
1000230189d9SNélio Laranjeiro 		uint32_t length;
1001a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
1002230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
1003230189d9SNélio Laranjeiro 
1004c3d62cc9SAdrien Mazarguil 		/*
1005c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1006c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1007c3d62cc9SAdrien Mazarguil 		 */
1008a5bf6af9SAdrien Mazarguil 		assert(segs_n);
1009a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
1010c3d62cc9SAdrien Mazarguil 			break;
1011a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
1012a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
1013a5bf6af9SAdrien Mazarguil 			break;
1014a5bf6af9SAdrien Mazarguil 		max -= segs_n;
1015c3d62cc9SAdrien Mazarguil 		--pkts_n;
1016230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
1017230189d9SNélio Laranjeiro 		if (buf->ol_flags &
1018230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
1019230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
1020a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1021a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1022a5bf6af9SAdrien Mazarguil 		assert(length);
1023230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1024230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
1025230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
1026a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
10278688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
1028230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
1029230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1030f04f1d51SNélio Laranjeiro 			/*
1031f04f1d51SNélio Laranjeiro 			 * Multi-Packet WQE consumes at most two WQE.
1032f04f1d51SNélio Laranjeiro 			 * mlx5_mpw_new() expects to be able to use such
1033f04f1d51SNélio Laranjeiro 			 * resources.
1034f04f1d51SNélio Laranjeiro 			 */
1035f04f1d51SNélio Laranjeiro 			if (unlikely(max_wqe < 2))
1036f04f1d51SNélio Laranjeiro 				break;
1037f04f1d51SNélio Laranjeiro 			max_wqe -= 2;
1038230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
10398688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
1040230189d9SNélio Laranjeiro 		}
1041a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1042a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1043a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1044a5bf6af9SAdrien Mazarguil 		length = 0;
1045a5bf6af9SAdrien Mazarguil #endif
1046a5bf6af9SAdrien Mazarguil 		do {
1047a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
1048a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
1049a5bf6af9SAdrien Mazarguil 
1050a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
1051a5bf6af9SAdrien Mazarguil 			assert(buf);
1052a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
1053230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
1054a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1055230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
1056a5bf6af9SAdrien Mazarguil 				.byte_count = htonl(DATA_LEN(buf)),
1057230189d9SNélio Laranjeiro 				.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
1058230189d9SNélio Laranjeiro 				.addr = htonll(addr),
1059230189d9SNélio Laranjeiro 			};
1060a5bf6af9SAdrien Mazarguil 			elts_head = elts_head_next;
1061a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1062a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
1063a5bf6af9SAdrien Mazarguil #endif
1064a5bf6af9SAdrien Mazarguil 			buf = buf->next;
1065230189d9SNélio Laranjeiro 			++mpw.pkts_n;
1066a5bf6af9SAdrien Mazarguil 			++j;
1067a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
1068a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
1069230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1070230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
1071230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
1072230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1073230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1074230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1075230189d9SNélio Laranjeiro #endif
1076c3d62cc9SAdrien Mazarguil 		++i;
1077c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1078230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1079230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1080230189d9SNélio Laranjeiro 		return 0;
1081230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1082a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1083a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1084230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
10858688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1086230189d9SNélio Laranjeiro 
1087230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
10888688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1089230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
10908688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1091230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1092230189d9SNélio Laranjeiro 	} else {
1093230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1094230189d9SNélio Laranjeiro 	}
1095230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1096230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1097230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1098230189d9SNélio Laranjeiro #endif
1099230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1100230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
1101230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
110230807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1103230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1104230189d9SNélio Laranjeiro 	return i;
1105230189d9SNélio Laranjeiro }
1106230189d9SNélio Laranjeiro 
1107230189d9SNélio Laranjeiro /**
1108230189d9SNélio Laranjeiro  * Open a MPW inline session.
1109230189d9SNélio Laranjeiro  *
1110230189d9SNélio Laranjeiro  * @param txq
1111230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
1112230189d9SNélio Laranjeiro  * @param mpw
1113230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1114230189d9SNélio Laranjeiro  * @param length
1115230189d9SNélio Laranjeiro  *   Packet length.
1116230189d9SNélio Laranjeiro  */
1117230189d9SNélio Laranjeiro static inline void
1118230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
1119230189d9SNélio Laranjeiro {
1120a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
11218688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
1122230189d9SNélio Laranjeiro 
1123230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
1124230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
1125230189d9SNélio Laranjeiro 	mpw->len = length;
1126230189d9SNélio Laranjeiro 	mpw->total_len = 0;
1127fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
11288688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
1129230189d9SNélio Laranjeiro 				  (txq->wqe_ci << 8) |
1130c904ae25SNélio Laranjeiro 				  MLX5_OPCODE_TSO);
11318688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
11328688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
11338688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
11348688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
11358688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
11368688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
11378688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
11388688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
11398688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
11408688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
11418688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
1142230189d9SNélio Laranjeiro }
1143230189d9SNélio Laranjeiro 
1144230189d9SNélio Laranjeiro /**
1145230189d9SNélio Laranjeiro  * Close a MPW inline session.
1146230189d9SNélio Laranjeiro  *
1147230189d9SNélio Laranjeiro  * @param txq
1148230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
1149230189d9SNélio Laranjeiro  * @param mpw
1150230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
1151230189d9SNélio Laranjeiro  */
1152230189d9SNélio Laranjeiro static inline void
1153230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
1154230189d9SNélio Laranjeiro {
1155230189d9SNélio Laranjeiro 	unsigned int size;
11568688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
11578688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
1158230189d9SNélio Laranjeiro 
11598688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
1160230189d9SNélio Laranjeiro 	/*
1161230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
1162230189d9SNélio Laranjeiro 	 * count as 2.
1163230189d9SNélio Laranjeiro 	 */
11648688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size));
1165230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
11668688b2f8SNélio Laranjeiro 	inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG);
11678688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
1168230189d9SNélio Laranjeiro }
1169230189d9SNélio Laranjeiro 
1170230189d9SNélio Laranjeiro /**
1171230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
1172230189d9SNélio Laranjeiro  *
1173230189d9SNélio Laranjeiro  * @param dpdk_txq
1174230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
1175230189d9SNélio Laranjeiro  * @param[in] pkts
1176230189d9SNélio Laranjeiro  *   Packets to transmit.
1177230189d9SNélio Laranjeiro  * @param pkts_n
1178230189d9SNélio Laranjeiro  *   Number of packets in array.
1179230189d9SNélio Laranjeiro  *
1180230189d9SNélio Laranjeiro  * @return
1181230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
1182230189d9SNélio Laranjeiro  */
1183230189d9SNélio Laranjeiro uint16_t
1184230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
1185230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
1186230189d9SNélio Laranjeiro {
1187230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
1188230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
1189b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
1190c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
1191a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
1192230189d9SNélio Laranjeiro 	unsigned int max;
1193f04f1d51SNélio Laranjeiro 	uint16_t max_wqe;
1194230189d9SNélio Laranjeiro 	unsigned int comp;
11950e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
1196230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
1197230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
1198230189d9SNélio Laranjeiro 	};
1199f04f1d51SNélio Laranjeiro 	/*
1200f04f1d51SNélio Laranjeiro 	 * Compute the maximum number of WQE which can be consumed by inline
1201f04f1d51SNélio Laranjeiro 	 * code.
1202f04f1d51SNélio Laranjeiro 	 * - 2 DSEG for:
1203f04f1d51SNélio Laranjeiro 	 *   - 1 control segment,
1204f04f1d51SNélio Laranjeiro 	 *   - 1 Ethernet segment,
1205f04f1d51SNélio Laranjeiro 	 * - N Dseg from the inline request.
1206f04f1d51SNélio Laranjeiro 	 */
1207f04f1d51SNélio Laranjeiro 	const unsigned int wqe_inl_n =
1208f04f1d51SNélio Laranjeiro 		((2 * MLX5_WQE_DWORD_SIZE +
1209f04f1d51SNélio Laranjeiro 		  txq->max_inline * RTE_CACHE_LINE_SIZE) +
1210f04f1d51SNélio Laranjeiro 		 RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE;
1211230189d9SNélio Laranjeiro 
1212c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
1213c3d62cc9SAdrien Mazarguil 		return 0;
1214230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
1215fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
1216fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
1217230189d9SNélio Laranjeiro 	/* Start processing. */
1218230189d9SNélio Laranjeiro 	txq_complete(txq);
1219230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
1220230189d9SNélio Laranjeiro 	if (max > elts_n)
1221230189d9SNélio Laranjeiro 		max -= elts_n;
1222c3d62cc9SAdrien Mazarguil 	do {
1223a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
1224c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
1225230189d9SNélio Laranjeiro 		uintptr_t addr;
1226230189d9SNélio Laranjeiro 		uint32_t length;
1227a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
1228230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
1229230189d9SNélio Laranjeiro 
1230c3d62cc9SAdrien Mazarguil 		/*
1231c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
1232c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
1233c3d62cc9SAdrien Mazarguil 		 */
1234a5bf6af9SAdrien Mazarguil 		assert(segs_n);
1235a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
1236c3d62cc9SAdrien Mazarguil 			break;
1237a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
1238a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
1239a5bf6af9SAdrien Mazarguil 			break;
1240a5bf6af9SAdrien Mazarguil 		max -= segs_n;
1241c3d62cc9SAdrien Mazarguil 		--pkts_n;
1242f04f1d51SNélio Laranjeiro 		/*
1243f04f1d51SNélio Laranjeiro 		 * Compute max_wqe in case less WQE were consumed in previous
1244f04f1d51SNélio Laranjeiro 		 * iteration.
1245f04f1d51SNélio Laranjeiro 		 */
1246f04f1d51SNélio Laranjeiro 		max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
1247230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
1248230189d9SNélio Laranjeiro 		if (buf->ol_flags &
1249230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
1250230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
1251a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
1252a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
1253230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
1254230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
1255230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1256a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
12578688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
1258230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1259230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
1260230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
1261a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
1262230189d9SNélio Laranjeiro 			    (length > inline_room) ||
12638688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
1264230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
12650e8679fcSNélio Laranjeiro 				inline_room =
12660e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1267230189d9SNélio Laranjeiro 			}
1268230189d9SNélio Laranjeiro 		}
1269230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
1270a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
1271a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
1272f04f1d51SNélio Laranjeiro 				/*
1273f04f1d51SNélio Laranjeiro 				 * Multi-Packet WQE consumes at most two WQE.
1274f04f1d51SNélio Laranjeiro 				 * mlx5_mpw_new() expects to be able to use
1275f04f1d51SNélio Laranjeiro 				 * such resources.
1276f04f1d51SNélio Laranjeiro 				 */
1277f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < 2))
1278f04f1d51SNélio Laranjeiro 					break;
1279f04f1d51SNélio Laranjeiro 				max_wqe -= 2;
1280230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
12818688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1282230189d9SNélio Laranjeiro 			} else {
1283f04f1d51SNélio Laranjeiro 				if (unlikely(max_wqe < wqe_inl_n))
1284f04f1d51SNélio Laranjeiro 					break;
1285f04f1d51SNélio Laranjeiro 				max_wqe -= wqe_inl_n;
1286230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
12878688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
1288230189d9SNélio Laranjeiro 			}
1289230189d9SNélio Laranjeiro 		}
1290a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1291a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1292230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
12930e8679fcSNélio Laranjeiro 			assert(inline_room ==
12940e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1295a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1296a5bf6af9SAdrien Mazarguil 			length = 0;
1297a5bf6af9SAdrien Mazarguil #endif
1298a5bf6af9SAdrien Mazarguil 			do {
1299230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1300230189d9SNélio Laranjeiro 
1301a5bf6af9SAdrien Mazarguil 				elts_head_next =
1302a5bf6af9SAdrien Mazarguil 					(elts_head + 1) & (elts_n - 1);
1303a5bf6af9SAdrien Mazarguil 				assert(buf);
1304a5bf6af9SAdrien Mazarguil 				(*txq->elts)[elts_head] = buf;
1305230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1306a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1307230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
1308a5bf6af9SAdrien Mazarguil 					.byte_count = htonl(DATA_LEN(buf)),
1309230189d9SNélio Laranjeiro 					.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
1310230189d9SNélio Laranjeiro 					.addr = htonll(addr),
1311230189d9SNélio Laranjeiro 				};
1312a5bf6af9SAdrien Mazarguil 				elts_head = elts_head_next;
1313a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1314a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1315a5bf6af9SAdrien Mazarguil #endif
1316a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1317230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1318a5bf6af9SAdrien Mazarguil 				++j;
1319a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1320a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1321230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1322230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1323230189d9SNélio Laranjeiro 		} else {
1324230189d9SNélio Laranjeiro 			unsigned int max;
1325230189d9SNélio Laranjeiro 
1326230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1327230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1328a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1329a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
1330a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1331a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
1332230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1333fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1334fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1335fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1336230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1337230189d9SNélio Laranjeiro 			if (length > max) {
1338230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1339230189d9SNélio Laranjeiro 					   (void *)addr,
1340230189d9SNélio Laranjeiro 					   max);
1341fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1342230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1343230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1344230189d9SNélio Laranjeiro 					   length - max);
1345230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1346230189d9SNélio Laranjeiro 			} else {
1347230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1348230189d9SNélio Laranjeiro 					   (void *)addr,
1349230189d9SNélio Laranjeiro 					   length);
135016c64768SYongseok Koh 
135116c64768SYongseok Koh 				if (length == max)
135216c64768SYongseok Koh 					mpw.data.raw =
135316c64768SYongseok Koh 						(volatile void *)txq->wqes;
135416c64768SYongseok Koh 				else
1355230189d9SNélio Laranjeiro 					mpw.data.raw += length;
1356230189d9SNélio Laranjeiro 			}
1357230189d9SNélio Laranjeiro 			++mpw.pkts_n;
135876bf1574SYongseok Koh 			mpw.total_len += length;
1359a5bf6af9SAdrien Mazarguil 			++j;
1360230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1361230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
13620e8679fcSNélio Laranjeiro 				inline_room =
13630e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1364230189d9SNélio Laranjeiro 			} else {
1365230189d9SNélio Laranjeiro 				inline_room -= length;
1366230189d9SNélio Laranjeiro 			}
1367230189d9SNélio Laranjeiro 		}
1368230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
1369230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1370230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1371230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1372230189d9SNélio Laranjeiro #endif
1373c3d62cc9SAdrien Mazarguil 		++i;
1374c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1375230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1376230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1377230189d9SNélio Laranjeiro 		return 0;
1378230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1379a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1380a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1381230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
13828688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1383230189d9SNélio Laranjeiro 
1384230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
13858688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1386230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
13878688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1388230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1389230189d9SNélio Laranjeiro 	} else {
1390230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1391230189d9SNélio Laranjeiro 	}
1392230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1393230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1394230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1395230189d9SNélio Laranjeiro #endif
1396230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1397230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1398230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1399230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1400230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
140130807f62SNélio Laranjeiro 	mlx5_tx_dbrec(txq, mpw.wqe);
1402230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1403230189d9SNélio Laranjeiro 	return i;
1404230189d9SNélio Laranjeiro }
1405230189d9SNélio Laranjeiro 
1406230189d9SNélio Laranjeiro /**
14076ce84bd8SYongseok Koh  * Open an Enhanced MPW session.
14086ce84bd8SYongseok Koh  *
14096ce84bd8SYongseok Koh  * @param txq
14106ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
14116ce84bd8SYongseok Koh  * @param mpw
14126ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
14136ce84bd8SYongseok Koh  * @param length
14146ce84bd8SYongseok Koh  *   Packet length.
14156ce84bd8SYongseok Koh  */
14166ce84bd8SYongseok Koh static inline void
14176ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding)
14186ce84bd8SYongseok Koh {
14196ce84bd8SYongseok Koh 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
14206ce84bd8SYongseok Koh 
14216ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED;
14226ce84bd8SYongseok Koh 	mpw->pkts_n = 0;
14236ce84bd8SYongseok Koh 	mpw->total_len = sizeof(struct mlx5_wqe);
14246ce84bd8SYongseok Koh 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
14256ce84bd8SYongseok Koh 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_ENHANCED_MPSW << 24) |
14266ce84bd8SYongseok Koh 				  (txq->wqe_ci << 8) |
14276ce84bd8SYongseok Koh 				  MLX5_OPCODE_ENHANCED_MPSW);
14286ce84bd8SYongseok Koh 	mpw->wqe->ctrl[2] = 0;
14296ce84bd8SYongseok Koh 	mpw->wqe->ctrl[3] = 0;
14306ce84bd8SYongseok Koh 	memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE);
14316ce84bd8SYongseok Koh 	if (unlikely(padding)) {
14326ce84bd8SYongseok Koh 		uintptr_t addr = (uintptr_t)(mpw->wqe + 1);
14336ce84bd8SYongseok Koh 
14346ce84bd8SYongseok Koh 		/* Pad the first 2 DWORDs with zero-length inline header. */
14356ce84bd8SYongseok Koh 		*(volatile uint32_t *)addr = htonl(MLX5_INLINE_SEG);
14366ce84bd8SYongseok Koh 		*(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) =
14376ce84bd8SYongseok Koh 			htonl(MLX5_INLINE_SEG);
14386ce84bd8SYongseok Koh 		mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE;
14396ce84bd8SYongseok Koh 		/* Start from the next WQEBB. */
14406ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1));
14416ce84bd8SYongseok Koh 	} else {
14426ce84bd8SYongseok Koh 		mpw->data.raw = (volatile void *)(mpw->wqe + 1);
14436ce84bd8SYongseok Koh 	}
14446ce84bd8SYongseok Koh }
14456ce84bd8SYongseok Koh 
14466ce84bd8SYongseok Koh /**
14476ce84bd8SYongseok Koh  * Close an Enhanced MPW session.
14486ce84bd8SYongseok Koh  *
14496ce84bd8SYongseok Koh  * @param txq
14506ce84bd8SYongseok Koh  *   Pointer to TX queue structure.
14516ce84bd8SYongseok Koh  * @param mpw
14526ce84bd8SYongseok Koh  *   Pointer to MPW session structure.
14536ce84bd8SYongseok Koh  *
14546ce84bd8SYongseok Koh  * @return
14556ce84bd8SYongseok Koh  *   Number of consumed WQEs.
14566ce84bd8SYongseok Koh  */
14576ce84bd8SYongseok Koh static inline uint16_t
14586ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw)
14596ce84bd8SYongseok Koh {
14606ce84bd8SYongseok Koh 	uint16_t ret;
14616ce84bd8SYongseok Koh 
14626ce84bd8SYongseok Koh 	/* Store size in multiple of 16 bytes. Control and Ethernet segments
14636ce84bd8SYongseok Koh 	 * count as 2.
14646ce84bd8SYongseok Koh 	 */
14656ce84bd8SYongseok Koh 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(mpw->total_len));
14666ce84bd8SYongseok Koh 	mpw->state = MLX5_MPW_STATE_CLOSED;
14676ce84bd8SYongseok Koh 	ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
14686ce84bd8SYongseok Koh 	txq->wqe_ci += ret;
14696ce84bd8SYongseok Koh 	return ret;
14706ce84bd8SYongseok Koh }
14716ce84bd8SYongseok Koh 
14726ce84bd8SYongseok Koh /**
14736ce84bd8SYongseok Koh  * DPDK callback for TX with Enhanced MPW support.
14746ce84bd8SYongseok Koh  *
14756ce84bd8SYongseok Koh  * @param dpdk_txq
14766ce84bd8SYongseok Koh  *   Generic pointer to TX queue structure.
14776ce84bd8SYongseok Koh  * @param[in] pkts
14786ce84bd8SYongseok Koh  *   Packets to transmit.
14796ce84bd8SYongseok Koh  * @param pkts_n
14806ce84bd8SYongseok Koh  *   Number of packets in array.
14816ce84bd8SYongseok Koh  *
14826ce84bd8SYongseok Koh  * @return
14836ce84bd8SYongseok Koh  *   Number of packets successfully transmitted (<= pkts_n).
14846ce84bd8SYongseok Koh  */
14856ce84bd8SYongseok Koh uint16_t
14866ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
14876ce84bd8SYongseok Koh {
14886ce84bd8SYongseok Koh 	struct txq *txq = (struct txq *)dpdk_txq;
14896ce84bd8SYongseok Koh 	uint16_t elts_head = txq->elts_head;
14906ce84bd8SYongseok Koh 	const unsigned int elts_n = 1 << txq->elts_n;
14916ce84bd8SYongseok Koh 	unsigned int i = 0;
14926ce84bd8SYongseok Koh 	unsigned int j = 0;
14936ce84bd8SYongseok Koh 	unsigned int max_elts;
14946ce84bd8SYongseok Koh 	uint16_t max_wqe;
14956ce84bd8SYongseok Koh 	unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
14966ce84bd8SYongseok Koh 	unsigned int mpw_room = 0;
14976ce84bd8SYongseok Koh 	unsigned int inl_pad = 0;
14986ce84bd8SYongseok Koh 	uint32_t inl_hdr;
14996ce84bd8SYongseok Koh 	struct mlx5_mpw mpw = {
15006ce84bd8SYongseok Koh 		.state = MLX5_MPW_STATE_CLOSED,
15016ce84bd8SYongseok Koh 	};
15026ce84bd8SYongseok Koh 
15036ce84bd8SYongseok Koh 	if (unlikely(!pkts_n))
15046ce84bd8SYongseok Koh 		return 0;
15056ce84bd8SYongseok Koh 	/* Start processing. */
15066ce84bd8SYongseok Koh 	txq_complete(txq);
15076ce84bd8SYongseok Koh 	max_elts = (elts_n - (elts_head - txq->elts_tail));
15086ce84bd8SYongseok Koh 	if (max_elts > elts_n)
15096ce84bd8SYongseok Koh 		max_elts -= elts_n;
15106ce84bd8SYongseok Koh 	/* A CQE slot must always be available. */
15116ce84bd8SYongseok Koh 	assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci));
15126ce84bd8SYongseok Koh 	max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi);
15136ce84bd8SYongseok Koh 	if (unlikely(!max_wqe))
15146ce84bd8SYongseok Koh 		return 0;
15156ce84bd8SYongseok Koh 	do {
15166ce84bd8SYongseok Koh 		struct rte_mbuf *buf = *(pkts++);
15176ce84bd8SYongseok Koh 		unsigned int elts_head_next;
15186ce84bd8SYongseok Koh 		uintptr_t addr;
15196ce84bd8SYongseok Koh 		uint64_t naddr;
15206ce84bd8SYongseok Koh 		unsigned int n;
15216ce84bd8SYongseok Koh 		unsigned int do_inline = 0; /* Whether inline is possible. */
15226ce84bd8SYongseok Koh 		uint32_t length;
15236ce84bd8SYongseok Koh 		unsigned int segs_n = buf->nb_segs;
15246ce84bd8SYongseok Koh 		uint32_t cs_flags = 0;
15256ce84bd8SYongseok Koh 
15266ce84bd8SYongseok Koh 		/*
15276ce84bd8SYongseok Koh 		 * Make sure there is enough room to store this packet and
15286ce84bd8SYongseok Koh 		 * that one ring entry remains unused.
15296ce84bd8SYongseok Koh 		 */
15306ce84bd8SYongseok Koh 		assert(segs_n);
15316ce84bd8SYongseok Koh 		if (max_elts - j < segs_n + 1)
15326ce84bd8SYongseok Koh 			break;
15336ce84bd8SYongseok Koh 		/* Do not bother with large packets MPW cannot handle. */
15346ce84bd8SYongseok Koh 		if (segs_n > MLX5_MPW_DSEG_MAX)
15356ce84bd8SYongseok Koh 			break;
15366ce84bd8SYongseok Koh 		/* Should we enable HW CKSUM offload. */
15376ce84bd8SYongseok Koh 		if (buf->ol_flags &
15386ce84bd8SYongseok Koh 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
15396ce84bd8SYongseok Koh 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
15406ce84bd8SYongseok Koh 		/* Retrieve packet information. */
15416ce84bd8SYongseok Koh 		length = PKT_LEN(buf);
15426ce84bd8SYongseok Koh 		/* Start new session if:
15436ce84bd8SYongseok Koh 		 * - multi-segment packet
15446ce84bd8SYongseok Koh 		 * - no space left even for a dseg
15456ce84bd8SYongseok Koh 		 * - next packet can be inlined with a new WQE
15466ce84bd8SYongseok Koh 		 * - cs_flag differs
15476ce84bd8SYongseok Koh 		 * It can't be MLX5_MPW_STATE_OPENED as always have a single
15486ce84bd8SYongseok Koh 		 * segmented packet.
15496ce84bd8SYongseok Koh 		 */
15506ce84bd8SYongseok Koh 		if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) {
15516ce84bd8SYongseok Koh 			if ((segs_n != 1) ||
15526ce84bd8SYongseok Koh 			    (inl_pad + sizeof(struct mlx5_wqe_data_seg) >
15536ce84bd8SYongseok Koh 			      mpw_room) ||
15546ce84bd8SYongseok Koh 			    (length <= txq->inline_max_packet_sz &&
15556ce84bd8SYongseok Koh 			     inl_pad + sizeof(inl_hdr) + length >
15566ce84bd8SYongseok Koh 			      mpw_room) ||
15576ce84bd8SYongseok Koh 			    (mpw.wqe->eseg.cs_flags != cs_flags))
15586ce84bd8SYongseok Koh 				max_wqe -= mlx5_empw_close(txq, &mpw);
15596ce84bd8SYongseok Koh 		}
15606ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) {
15616ce84bd8SYongseok Koh 			if (unlikely(segs_n != 1)) {
15626ce84bd8SYongseok Koh 				/* Fall back to legacy MPW.
15636ce84bd8SYongseok Koh 				 * A MPW session consumes 2 WQEs at most to
15646ce84bd8SYongseok Koh 				 * include MLX5_MPW_DSEG_MAX pointers.
15656ce84bd8SYongseok Koh 				 */
15666ce84bd8SYongseok Koh 				if (unlikely(max_wqe < 2))
15676ce84bd8SYongseok Koh 					break;
15686ce84bd8SYongseok Koh 				mlx5_mpw_new(txq, &mpw, length);
15696ce84bd8SYongseok Koh 			} else {
15706ce84bd8SYongseok Koh 				/* In Enhanced MPW, inline as much as the budget
15716ce84bd8SYongseok Koh 				 * is allowed. The remaining space is to be
15726ce84bd8SYongseok Koh 				 * filled with dsegs. If the title WQEBB isn't
15736ce84bd8SYongseok Koh 				 * padded, it will have 2 dsegs there.
15746ce84bd8SYongseok Koh 				 */
15756ce84bd8SYongseok Koh 				mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX,
15766ce84bd8SYongseok Koh 					    (max_inline ? max_inline :
15776ce84bd8SYongseok Koh 					     pkts_n * MLX5_WQE_DWORD_SIZE) +
15786ce84bd8SYongseok Koh 					    MLX5_WQE_SIZE);
15796ce84bd8SYongseok Koh 				if (unlikely(max_wqe * MLX5_WQE_SIZE <
15806ce84bd8SYongseok Koh 					      mpw_room))
15816ce84bd8SYongseok Koh 					break;
15826ce84bd8SYongseok Koh 				/* Don't pad the title WQEBB to not waste WQ. */
15836ce84bd8SYongseok Koh 				mlx5_empw_new(txq, &mpw, 0);
15846ce84bd8SYongseok Koh 				mpw_room -= mpw.total_len;
15856ce84bd8SYongseok Koh 				inl_pad = 0;
15866ce84bd8SYongseok Koh 				do_inline =
15876ce84bd8SYongseok Koh 					length <= txq->inline_max_packet_sz &&
15886ce84bd8SYongseok Koh 					sizeof(inl_hdr) + length <= mpw_room &&
15896ce84bd8SYongseok Koh 					!txq->mpw_hdr_dseg;
15906ce84bd8SYongseok Koh 			}
15916ce84bd8SYongseok Koh 			mpw.wqe->eseg.cs_flags = cs_flags;
15926ce84bd8SYongseok Koh 		} else {
15936ce84bd8SYongseok Koh 			/* Evaluate whether the next packet can be inlined.
15946ce84bd8SYongseok Koh 			 * Inlininig is possible when:
15956ce84bd8SYongseok Koh 			 * - length is less than configured value
15966ce84bd8SYongseok Koh 			 * - length fits for remaining space
15976ce84bd8SYongseok Koh 			 * - not required to fill the title WQEBB with dsegs
15986ce84bd8SYongseok Koh 			 */
15996ce84bd8SYongseok Koh 			do_inline =
16006ce84bd8SYongseok Koh 				length <= txq->inline_max_packet_sz &&
16016ce84bd8SYongseok Koh 				inl_pad + sizeof(inl_hdr) + length <=
16026ce84bd8SYongseok Koh 				 mpw_room &&
16036ce84bd8SYongseok Koh 				(!txq->mpw_hdr_dseg ||
16046ce84bd8SYongseok Koh 				 mpw.total_len >= MLX5_WQE_SIZE);
16056ce84bd8SYongseok Koh 		}
16066ce84bd8SYongseok Koh 		/* Multi-segment packets must be alone in their MPW. */
16076ce84bd8SYongseok Koh 		assert((segs_n == 1) || (mpw.pkts_n == 0));
16086ce84bd8SYongseok Koh 		if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) {
16096ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
16106ce84bd8SYongseok Koh 			length = 0;
16116ce84bd8SYongseok Koh #endif
16126ce84bd8SYongseok Koh 			do {
16136ce84bd8SYongseok Koh 				volatile struct mlx5_wqe_data_seg *dseg;
16146ce84bd8SYongseok Koh 
16156ce84bd8SYongseok Koh 				elts_head_next =
16166ce84bd8SYongseok Koh 					(elts_head + 1) & (elts_n - 1);
16176ce84bd8SYongseok Koh 				assert(buf);
16186ce84bd8SYongseok Koh 				(*txq->elts)[elts_head] = buf;
16196ce84bd8SYongseok Koh 				dseg = mpw.data.dseg[mpw.pkts_n];
16206ce84bd8SYongseok Koh 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
16216ce84bd8SYongseok Koh 				*dseg = (struct mlx5_wqe_data_seg){
16226ce84bd8SYongseok Koh 					.byte_count = htonl(DATA_LEN(buf)),
16236ce84bd8SYongseok Koh 					.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
16246ce84bd8SYongseok Koh 					.addr = htonll(addr),
16256ce84bd8SYongseok Koh 				};
16266ce84bd8SYongseok Koh 				elts_head = elts_head_next;
16276ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
16286ce84bd8SYongseok Koh 				length += DATA_LEN(buf);
16296ce84bd8SYongseok Koh #endif
16306ce84bd8SYongseok Koh 				buf = buf->next;
16316ce84bd8SYongseok Koh 				++j;
16326ce84bd8SYongseok Koh 				++mpw.pkts_n;
16336ce84bd8SYongseok Koh 			} while (--segs_n);
16346ce84bd8SYongseok Koh 			/* A multi-segmented packet takes one MPW session.
16356ce84bd8SYongseok Koh 			 * TODO: Pack more multi-segmented packets if possible.
16366ce84bd8SYongseok Koh 			 */
16376ce84bd8SYongseok Koh 			mlx5_mpw_close(txq, &mpw);
16386ce84bd8SYongseok Koh 			if (mpw.pkts_n < 3)
16396ce84bd8SYongseok Koh 				max_wqe--;
16406ce84bd8SYongseok Koh 			else
16416ce84bd8SYongseok Koh 				max_wqe -= 2;
16426ce84bd8SYongseok Koh 		} else if (do_inline) {
16436ce84bd8SYongseok Koh 			/* Inline packet into WQE. */
16446ce84bd8SYongseok Koh 			unsigned int max;
16456ce84bd8SYongseok Koh 
16466ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
16476ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
16486ce84bd8SYongseok Koh 			inl_hdr = htonl(length | MLX5_INLINE_SEG);
16496ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
16506ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16516ce84bd8SYongseok Koh 				((uintptr_t)mpw.data.raw + inl_pad);
16526ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
16536ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
16546ce84bd8SYongseok Koh 			/* Copy inline header. */
16556ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16566ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
16576ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
16586ce84bd8SYongseok Koh 					  &inl_hdr,
16596ce84bd8SYongseok Koh 					  sizeof(inl_hdr),
16606ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
16616ce84bd8SYongseok Koh 					  max);
16626ce84bd8SYongseok Koh 			max = tx_mlx5_wq_tailroom(txq,
16636ce84bd8SYongseok Koh 					(void *)(uintptr_t)mpw.data.raw);
16646ce84bd8SYongseok Koh 			/* Copy packet data. */
16656ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)
16666ce84bd8SYongseok Koh 				mlx5_copy_to_wq(
16676ce84bd8SYongseok Koh 					  (void *)(uintptr_t)mpw.data.raw,
16686ce84bd8SYongseok Koh 					  (void *)addr,
16696ce84bd8SYongseok Koh 					  length,
16706ce84bd8SYongseok Koh 					  (void *)(uintptr_t)txq->wqes,
16716ce84bd8SYongseok Koh 					  max);
16726ce84bd8SYongseok Koh 			++mpw.pkts_n;
16736ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(inl_hdr) + length);
16746ce84bd8SYongseok Koh 			/* No need to get completion as the entire packet is
16756ce84bd8SYongseok Koh 			 * copied to WQ. Free the buf right away.
16766ce84bd8SYongseok Koh 			 */
16776ce84bd8SYongseok Koh 			elts_head_next = elts_head;
16786ce84bd8SYongseok Koh 			rte_pktmbuf_free_seg(buf);
16796ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(inl_hdr) + length);
16806ce84bd8SYongseok Koh 			/* Add pad in the next packet if any. */
16816ce84bd8SYongseok Koh 			inl_pad = (((uintptr_t)mpw.data.raw +
16826ce84bd8SYongseok Koh 					(MLX5_WQE_DWORD_SIZE - 1)) &
16836ce84bd8SYongseok Koh 					~(MLX5_WQE_DWORD_SIZE - 1)) -
16846ce84bd8SYongseok Koh 				  (uintptr_t)mpw.data.raw;
16856ce84bd8SYongseok Koh 		} else {
16866ce84bd8SYongseok Koh 			/* No inline. Load a dseg of packet pointer. */
16876ce84bd8SYongseok Koh 			volatile rte_v128u32_t *dseg;
16886ce84bd8SYongseok Koh 
16896ce84bd8SYongseok Koh 			assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED);
16906ce84bd8SYongseok Koh 			assert((inl_pad + sizeof(*dseg)) <= mpw_room);
16916ce84bd8SYongseok Koh 			assert(length == DATA_LEN(buf));
16926ce84bd8SYongseok Koh 			if (!tx_mlx5_wq_tailroom(txq,
16936ce84bd8SYongseok Koh 					(void *)((uintptr_t)mpw.data.raw
16946ce84bd8SYongseok Koh 						+ inl_pad)))
16956ce84bd8SYongseok Koh 				dseg = (volatile void *)txq->wqes;
16966ce84bd8SYongseok Koh 			else
16976ce84bd8SYongseok Koh 				dseg = (volatile void *)
16986ce84bd8SYongseok Koh 					((uintptr_t)mpw.data.raw +
16996ce84bd8SYongseok Koh 					 inl_pad);
17006ce84bd8SYongseok Koh 			elts_head_next = (elts_head + 1) & (elts_n - 1);
17016ce84bd8SYongseok Koh 			(*txq->elts)[elts_head] = buf;
17026ce84bd8SYongseok Koh 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
17036ce84bd8SYongseok Koh 			for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++)
17046ce84bd8SYongseok Koh 				rte_prefetch2((void *)(addr +
17056ce84bd8SYongseok Koh 						n * RTE_CACHE_LINE_SIZE));
17066ce84bd8SYongseok Koh 			naddr = htonll(addr);
17076ce84bd8SYongseok Koh 			*dseg = (rte_v128u32_t) {
17086ce84bd8SYongseok Koh 				htonl(length),
17096ce84bd8SYongseok Koh 				txq_mp2mr(txq, txq_mb2mp(buf)),
17106ce84bd8SYongseok Koh 				naddr,
17116ce84bd8SYongseok Koh 				naddr >> 32,
17126ce84bd8SYongseok Koh 			};
17136ce84bd8SYongseok Koh 			mpw.data.raw = (volatile void *)(dseg + 1);
17146ce84bd8SYongseok Koh 			mpw.total_len += (inl_pad + sizeof(*dseg));
17156ce84bd8SYongseok Koh 			++j;
17166ce84bd8SYongseok Koh 			++mpw.pkts_n;
17176ce84bd8SYongseok Koh 			mpw_room -= (inl_pad + sizeof(*dseg));
17186ce84bd8SYongseok Koh 			inl_pad = 0;
17196ce84bd8SYongseok Koh 		}
17206ce84bd8SYongseok Koh 		elts_head = elts_head_next;
17216ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
17226ce84bd8SYongseok Koh 		/* Increment sent bytes counter. */
17236ce84bd8SYongseok Koh 		txq->stats.obytes += length;
17246ce84bd8SYongseok Koh #endif
17256ce84bd8SYongseok Koh 		++i;
17266ce84bd8SYongseok Koh 	} while (i < pkts_n);
17276ce84bd8SYongseok Koh 	/* Take a shortcut if nothing must be sent. */
17286ce84bd8SYongseok Koh 	if (unlikely(i == 0))
17296ce84bd8SYongseok Koh 		return 0;
17306ce84bd8SYongseok Koh 	/* Check whether completion threshold has been reached. */
17316ce84bd8SYongseok Koh 	if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH ||
17326ce84bd8SYongseok Koh 			(uint16_t)(txq->wqe_ci - txq->mpw_comp) >=
17336ce84bd8SYongseok Koh 			 (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) {
17346ce84bd8SYongseok Koh 		volatile struct mlx5_wqe *wqe = mpw.wqe;
17356ce84bd8SYongseok Koh 
17366ce84bd8SYongseok Koh 		/* Request completion on last WQE. */
17376ce84bd8SYongseok Koh 		wqe->ctrl[2] = htonl(8);
17386ce84bd8SYongseok Koh 		/* Save elts_head in unused "immediate" field of WQE. */
17396ce84bd8SYongseok Koh 		wqe->ctrl[3] = elts_head;
17406ce84bd8SYongseok Koh 		txq->elts_comp = 0;
17416ce84bd8SYongseok Koh 		txq->mpw_comp = txq->wqe_ci;
17426ce84bd8SYongseok Koh 		txq->cq_pi++;
17436ce84bd8SYongseok Koh 	} else {
17446ce84bd8SYongseok Koh 		txq->elts_comp += j;
17456ce84bd8SYongseok Koh 	}
17466ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
17476ce84bd8SYongseok Koh 	/* Increment sent packets counter. */
17486ce84bd8SYongseok Koh 	txq->stats.opackets += i;
17496ce84bd8SYongseok Koh #endif
17506ce84bd8SYongseok Koh 	if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED)
17516ce84bd8SYongseok Koh 		mlx5_empw_close(txq, &mpw);
17526ce84bd8SYongseok Koh 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
17536ce84bd8SYongseok Koh 		mlx5_mpw_close(txq, &mpw);
17546ce84bd8SYongseok Koh 	/* Ring QP doorbell. */
17556ce84bd8SYongseok Koh 	mlx5_tx_dbrec(txq, mpw.wqe);
17566ce84bd8SYongseok Koh 	txq->elts_head = elts_head;
17576ce84bd8SYongseok Koh 	return i;
17586ce84bd8SYongseok Koh }
17596ce84bd8SYongseok Koh 
17606ce84bd8SYongseok Koh /**
176167fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
176267fa62bcSAdrien Mazarguil  *
17636218063bSNélio Laranjeiro  * @param[in] cqe
17646218063bSNélio Laranjeiro  *   Pointer to CQE.
176567fa62bcSAdrien Mazarguil  *
176678a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
176778a38edfSJianfeng Tan  *
176867fa62bcSAdrien Mazarguil  * @return
176967fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
177067fa62bcSAdrien Mazarguil  */
177167fa62bcSAdrien Mazarguil static inline uint32_t
177297267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
177367fa62bcSAdrien Mazarguil {
177467fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
17750603df73SNélio Laranjeiro 	uint16_t flags = ntohs(cqe->hdr_type_etc);
177667fa62bcSAdrien Mazarguil 
17770603df73SNélio Laranjeiro 	if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) {
177867fa62bcSAdrien Mazarguil 		pkt_type =
177967fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1780350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV4_PACKET,
1781501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) |
178267fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1783350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV6_PACKET,
1784501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN);
17850603df73SNélio Laranjeiro 		pkt_type |= ((cqe->pkt_info & MLX5_CQE_RX_OUTER_PACKET) ?
17860603df73SNélio Laranjeiro 			     RTE_PTYPE_L3_IPV6_EXT_UNKNOWN :
17870603df73SNélio Laranjeiro 			     RTE_PTYPE_L3_IPV4_EXT_UNKNOWN);
17880603df73SNélio Laranjeiro 	} else {
178967fa62bcSAdrien Mazarguil 		pkt_type =
179067fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
17916218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV6,
1792501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) |
179367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
17946218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV4,
1795501505c5SMatthieu Ternisien d'Ouville 				  RTE_PTYPE_L3_IPV4_EXT_UNKNOWN);
17960603df73SNélio Laranjeiro 	}
179767fa62bcSAdrien Mazarguil 	return pkt_type;
179867fa62bcSAdrien Mazarguil }
179967fa62bcSAdrien Mazarguil 
180067fa62bcSAdrien Mazarguil /**
180199c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
180299c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
180399c12dccSNélio Laranjeiro  * been processed.
180499c12dccSNélio Laranjeiro  *
180599c12dccSNélio Laranjeiro  * @param rxq
180699c12dccSNélio Laranjeiro  *   Pointer to RX queue.
180799c12dccSNélio Laranjeiro  * @param cqe
180899c12dccSNélio Laranjeiro  *   CQE to process.
1809ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1810ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
181199c12dccSNélio Laranjeiro  *
181299c12dccSNélio Laranjeiro  * @return
181399c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
181499c12dccSNélio Laranjeiro  *   with error.
181599c12dccSNélio Laranjeiro  */
181699c12dccSNélio Laranjeiro static inline int
181797267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
1818ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
181999c12dccSNélio Laranjeiro {
182099c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
182199c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
182299c12dccSNélio Laranjeiro 	int len = 0;
1823d2e842d0SYongseok Koh 	uint16_t idx, end;
182499c12dccSNélio Laranjeiro 
182599c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
182699c12dccSNélio Laranjeiro 	if (zip->ai) {
182799c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
182899c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
182997267b8eSNelio Laranjeiro 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt]);
183099c12dccSNélio Laranjeiro 
183199c12dccSNélio Laranjeiro 		len = ntohl((*mc)[zip->ai & 7].byte_cnt);
1832ecf60761SNélio Laranjeiro 		*rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result);
183399c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
1834d2e842d0SYongseok Koh 			/* Invalidate consumed CQEs */
1835d2e842d0SYongseok Koh 			idx = zip->ca;
1836d2e842d0SYongseok Koh 			end = zip->na;
1837d2e842d0SYongseok Koh 			while (idx != end) {
1838d2e842d0SYongseok Koh 				(*rxq->cqes)[idx & cqe_cnt].op_own =
1839d2e842d0SYongseok Koh 					MLX5_CQE_INVALIDATE;
1840d2e842d0SYongseok Koh 				++idx;
1841d2e842d0SYongseok Koh 			}
184299c12dccSNélio Laranjeiro 			/*
184399c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
184499c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
184599c12dccSNélio Laranjeiro 			 * ring for software use.
184699c12dccSNélio Laranjeiro 			 */
184799c12dccSNélio Laranjeiro 			zip->ca = zip->na;
184899c12dccSNélio Laranjeiro 			zip->na += 8;
184999c12dccSNélio Laranjeiro 		}
185099c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1851d2e842d0SYongseok Koh 			/* Invalidate the rest */
1852d2e842d0SYongseok Koh 			idx = zip->ca;
1853d2e842d0SYongseok Koh 			end = zip->cq_ci;
185499c12dccSNélio Laranjeiro 
185599c12dccSNélio Laranjeiro 			while (idx != end) {
185697267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
185799c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
185899c12dccSNélio Laranjeiro 				++idx;
185999c12dccSNélio Laranjeiro 			}
186099c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
186199c12dccSNélio Laranjeiro 			zip->ai = 0;
186299c12dccSNélio Laranjeiro 		}
186399c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
186499c12dccSNélio Laranjeiro 	} else {
186599c12dccSNélio Laranjeiro 		int ret;
186699c12dccSNélio Laranjeiro 		int8_t op_own;
186799c12dccSNélio Laranjeiro 
186897267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
186999c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
187099c12dccSNélio Laranjeiro 			return 0;
187199c12dccSNélio Laranjeiro 		++rxq->cq_ci;
187299c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
187399c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
187499c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
187599c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
187699c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
187797267b8eSNelio Laranjeiro 							  cqe_cnt]);
187899c12dccSNélio Laranjeiro 
187999c12dccSNélio Laranjeiro 			/* Fix endianness. */
188099c12dccSNélio Laranjeiro 			zip->cqe_cnt = ntohl(cqe->byte_cnt);
188199c12dccSNélio Laranjeiro 			/*
188299c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
188399c12dccSNélio Laranjeiro 			 * check_cqe64().
188499c12dccSNélio Laranjeiro 			 *
188599c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
188699c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
188799c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
188899c12dccSNélio Laranjeiro 			 */
1889d2e842d0SYongseok Koh 			zip->ca = rxq->cq_ci;
189099c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
189199c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
189299c12dccSNélio Laranjeiro 			--rxq->cq_ci;
189399c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
189499c12dccSNélio Laranjeiro 			/* Get packet size to return. */
189599c12dccSNélio Laranjeiro 			len = ntohl((*mc)[0].byte_cnt);
1896ecf60761SNélio Laranjeiro 			*rss_hash = ntohl((*mc)[0].rx_hash_result);
189799c12dccSNélio Laranjeiro 			zip->ai = 1;
1898d2e842d0SYongseok Koh 			/* Prefetch all the entries to be invalidated */
1899d2e842d0SYongseok Koh 			idx = zip->ca;
1900d2e842d0SYongseok Koh 			end = zip->cq_ci;
1901d2e842d0SYongseok Koh 			while (idx != end) {
1902d2e842d0SYongseok Koh 				rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]);
1903d2e842d0SYongseok Koh 				++idx;
1904d2e842d0SYongseok Koh 			}
190599c12dccSNélio Laranjeiro 		} else {
190699c12dccSNélio Laranjeiro 			len = ntohl(cqe->byte_cnt);
1907ecf60761SNélio Laranjeiro 			*rss_hash = ntohl(cqe->rx_hash_res);
190899c12dccSNélio Laranjeiro 		}
190999c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
191099c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
191199c12dccSNélio Laranjeiro 			return -1;
191299c12dccSNélio Laranjeiro 	}
191399c12dccSNélio Laranjeiro 	return len;
191499c12dccSNélio Laranjeiro }
191599c12dccSNélio Laranjeiro 
191699c12dccSNélio Laranjeiro /**
191767fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
191867fa62bcSAdrien Mazarguil  *
191967fa62bcSAdrien Mazarguil  * @param[in] rxq
192067fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
19216218063bSNélio Laranjeiro  * @param[in] cqe
19226218063bSNélio Laranjeiro  *   Pointer to CQE.
192367fa62bcSAdrien Mazarguil  *
192467fa62bcSAdrien Mazarguil  * @return
192567fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
192667fa62bcSAdrien Mazarguil  */
192767fa62bcSAdrien Mazarguil static inline uint32_t
192897267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
192967fa62bcSAdrien Mazarguil {
193067fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
19310603df73SNélio Laranjeiro 	uint16_t flags = ntohs(cqe->hdr_type_etc);
193267fa62bcSAdrien Mazarguil 
19330603df73SNélio Laranjeiro 	ol_flags =
19340603df73SNélio Laranjeiro 		TRANSPOSE(flags,
19350603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
19360603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
19370603df73SNélio Laranjeiro 		TRANSPOSE(flags,
19380603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
193983e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
194097267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
194167fa62bcSAdrien Mazarguil 		ol_flags |=
19420603df73SNélio Laranjeiro 			TRANSPOSE(flags,
19430603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L3_HDR_VALID,
194483e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
19450603df73SNélio Laranjeiro 			TRANSPOSE(flags,
19460603df73SNélio Laranjeiro 				  MLX5_CQE_RX_L4_HDR_VALID,
194783e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
194867fa62bcSAdrien Mazarguil 	return ol_flags;
194967fa62bcSAdrien Mazarguil }
195067fa62bcSAdrien Mazarguil 
195167fa62bcSAdrien Mazarguil /**
19522e22920bSAdrien Mazarguil  * DPDK callback for RX.
19532e22920bSAdrien Mazarguil  *
19542e22920bSAdrien Mazarguil  * @param dpdk_rxq
19552e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
19562e22920bSAdrien Mazarguil  * @param[out] pkts
19572e22920bSAdrien Mazarguil  *   Array to store received packets.
19582e22920bSAdrien Mazarguil  * @param pkts_n
19592e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
19602e22920bSAdrien Mazarguil  *
19612e22920bSAdrien Mazarguil  * @return
19622e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
19632e22920bSAdrien Mazarguil  */
19642e22920bSAdrien Mazarguil uint16_t
19652e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
19662e22920bSAdrien Mazarguil {
19676218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
1968b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1969e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
19709964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
19719964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
19729964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
197397267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
197497267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
19759964b965SNélio Laranjeiro 	unsigned int i = 0;
19769964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
19774e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
19782e22920bSAdrien Mazarguil 
19799964b965SNélio Laranjeiro 	while (pkts_n) {
19809964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
19819964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
19829964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1983ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
19849964b965SNélio Laranjeiro 
19859964b965SNélio Laranjeiro 		if (pkt)
19869964b965SNélio Laranjeiro 			NEXT(seg) = rep;
19879964b965SNélio Laranjeiro 		seg = rep;
19889964b965SNélio Laranjeiro 		rte_prefetch0(seg);
19896218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
19909964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1991fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
19922e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
199315a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
199415a756b6SSagi Grimberg 			if (!pkt) {
199515a756b6SSagi Grimberg 				/*
199615a756b6SSagi Grimberg 				 * no buffers before we even started,
199715a756b6SSagi Grimberg 				 * bail out silently.
199815a756b6SSagi Grimberg 				 */
199915a756b6SSagi Grimberg 				break;
200015a756b6SSagi Grimberg 			}
2001a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
2002a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
2003fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
20048f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
20058f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
20061f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
2007fe5fe382SNélio Laranjeiro 				pkt = rep;
20089964b965SNélio Laranjeiro 			}
20096218063bSNélio Laranjeiro 			break;
20102e22920bSAdrien Mazarguil 		}
20119964b965SNélio Laranjeiro 		if (!pkt) {
201297267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
2013ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
2014ecf60761SNélio Laranjeiro 					       &rss_hash_res);
2015ecf60761SNélio Laranjeiro 			if (!len) {
20161f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
20176218063bSNélio Laranjeiro 				break;
20186218063bSNélio Laranjeiro 			}
201999c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
202099c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
20211f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
202299c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
202399c12dccSNélio Laranjeiro 				goto skip;
202499c12dccSNélio Laranjeiro 			}
20259964b965SNélio Laranjeiro 			pkt = seg;
20269964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
20279964b965SNélio Laranjeiro 			/* Update packet information. */
20280ac64846SMaxime Leroy 			pkt->packet_type = 0;
20290ac64846SMaxime Leroy 			pkt->ol_flags = 0;
203036ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
2031ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
2032ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
2033ecf60761SNélio Laranjeiro 			}
2034c604f619SNélio Laranjeiro 			if (rxq->mark &&
2035c604f619SNélio Laranjeiro 			    MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
2036b268a3eeSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR;
2037b268a3eeSNélio Laranjeiro 				if (cqe->sop_drop_qpn !=
2038b268a3eeSNélio Laranjeiro 				    htonl(MLX5_FLOW_MARK_DEFAULT)) {
2039b268a3eeSNélio Laranjeiro 					uint32_t mark = cqe->sop_drop_qpn;
2040b268a3eeSNélio Laranjeiro 
2041b268a3eeSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_FDIR_ID;
2042ea3bc3b1SNélio Laranjeiro 					pkt->hash.fdir.hi =
2043b268a3eeSNélio Laranjeiro 						mlx5_flow_mark_get(mark);
2044b268a3eeSNélio Laranjeiro 				}
2045ea3bc3b1SNélio Laranjeiro 			}
20466703d836SNélio Laranjeiro 			if (rxq->csum | rxq->csum_l2tun) {
20476703d836SNélio Laranjeiro 				pkt->packet_type = rxq_cq_to_pkt_type(cqe);
20486703d836SNélio Laranjeiro 				pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe);
20496218063bSNélio Laranjeiro 			}
20506703d836SNélio Laranjeiro 			if (rxq->vlan_strip &&
20516703d836SNélio Laranjeiro 			    (cqe->hdr_type_etc &
20526703d836SNélio Laranjeiro 			     htons(MLX5_CQE_VLAN_STRIPPED))) {
20536218063bSNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_VLAN_PKT |
2054b37b528dSOlivier Matz 					PKT_RX_VLAN_STRIPPED;
20556218063bSNélio Laranjeiro 				pkt->vlan_tci = ntohs(cqe->vlan_info);
2056f3db9489SYaacov Hazan 			}
20576218063bSNélio Laranjeiro 			if (rxq->crc_present)
20586218063bSNélio Laranjeiro 				len -= ETHER_CRC_LEN;
20596218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
20609964b965SNélio Laranjeiro 		}
20619964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
20629964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
20639964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
20649964b965SNélio Laranjeiro 		NB_SEGS(rep) = NB_SEGS(seg);
20659964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
20669964b965SNélio Laranjeiro 		NEXT(rep) = NULL;
20679964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
20689964b965SNélio Laranjeiro 		/*
20699964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
20709964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
20719964b965SNélio Laranjeiro 		 * changes.
20729964b965SNélio Laranjeiro 		 */
20739964b965SNélio Laranjeiro 		wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
20749964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
20759964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
20769964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
20779964b965SNélio Laranjeiro 			++rq_ci;
20789964b965SNélio Laranjeiro 			continue;
20799964b965SNélio Laranjeiro 		}
20809964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
208187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
208287011737SAdrien Mazarguil 		/* Increment bytes counter. */
20839964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
208487011737SAdrien Mazarguil #endif
20856218063bSNélio Laranjeiro 		/* Return packet. */
20866218063bSNélio Laranjeiro 		*(pkts++) = pkt;
20879964b965SNélio Laranjeiro 		pkt = NULL;
20889964b965SNélio Laranjeiro 		--pkts_n;
20899964b965SNélio Laranjeiro 		++i;
209099c12dccSNélio Laranjeiro skip:
20919964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
20929964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
20936218063bSNélio Laranjeiro 		++rq_ci;
20949964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
20952e22920bSAdrien Mazarguil 	}
20969964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
20972e22920bSAdrien Mazarguil 		return 0;
20986218063bSNélio Laranjeiro 	/* Update the consumer index. */
20999964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
21006218063bSNélio Laranjeiro 	rte_wmb();
21016218063bSNélio Laranjeiro 	*rxq->cq_db = htonl(rxq->cq_ci);
21026218063bSNélio Laranjeiro 	rte_wmb();
21036218063bSNélio Laranjeiro 	*rxq->rq_db = htonl(rxq->rq_ci);
210487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
210587011737SAdrien Mazarguil 	/* Increment packets counter. */
21069964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
210787011737SAdrien Mazarguil #endif
21089964b965SNélio Laranjeiro 	return i;
21092e22920bSAdrien Mazarguil }
21102e22920bSAdrien Mazarguil 
21112e22920bSAdrien Mazarguil /**
21122e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
21132e22920bSAdrien Mazarguil  *
21142e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
21152e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
21162e22920bSAdrien Mazarguil  *
21172e22920bSAdrien Mazarguil  * @param dpdk_txq
21182e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
21192e22920bSAdrien Mazarguil  * @param[in] pkts
21202e22920bSAdrien Mazarguil  *   Packets to transmit.
21212e22920bSAdrien Mazarguil  * @param pkts_n
21222e22920bSAdrien Mazarguil  *   Number of packets in array.
21232e22920bSAdrien Mazarguil  *
21242e22920bSAdrien Mazarguil  * @return
21252e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
21262e22920bSAdrien Mazarguil  */
21272e22920bSAdrien Mazarguil uint16_t
21282e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
21292e22920bSAdrien Mazarguil {
21302e22920bSAdrien Mazarguil 	(void)dpdk_txq;
21312e22920bSAdrien Mazarguil 	(void)pkts;
21322e22920bSAdrien Mazarguil 	(void)pkts_n;
21332e22920bSAdrien Mazarguil 	return 0;
21342e22920bSAdrien Mazarguil }
21352e22920bSAdrien Mazarguil 
21362e22920bSAdrien Mazarguil /**
21372e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
21382e22920bSAdrien Mazarguil  *
21392e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
21402e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
21412e22920bSAdrien Mazarguil  *
21422e22920bSAdrien Mazarguil  * @param dpdk_rxq
21432e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
21442e22920bSAdrien Mazarguil  * @param[out] pkts
21452e22920bSAdrien Mazarguil  *   Array to store received packets.
21462e22920bSAdrien Mazarguil  * @param pkts_n
21472e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
21482e22920bSAdrien Mazarguil  *
21492e22920bSAdrien Mazarguil  * @return
21502e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
21512e22920bSAdrien Mazarguil  */
21522e22920bSAdrien Mazarguil uint16_t
21532e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
21542e22920bSAdrien Mazarguil {
21552e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
21562e22920bSAdrien Mazarguil 	(void)pkts;
21572e22920bSAdrien Mazarguil 	(void)pkts_n;
21582e22920bSAdrien Mazarguil 	return 0;
21592e22920bSAdrien Mazarguil }
21603c7d44afSShahaf Shuler 
21613c7d44afSShahaf Shuler /**
21623c7d44afSShahaf Shuler  * DPDK callback for rx queue interrupt enable.
21633c7d44afSShahaf Shuler  *
21643c7d44afSShahaf Shuler  * @param dev
21653c7d44afSShahaf Shuler  *   Pointer to Ethernet device structure.
21663c7d44afSShahaf Shuler  * @param rx_queue_id
21673c7d44afSShahaf Shuler  *   RX queue number
21683c7d44afSShahaf Shuler  *
21693c7d44afSShahaf Shuler  * @return
21703c7d44afSShahaf Shuler  *   0 on success, negative on failure.
21713c7d44afSShahaf Shuler  */
21723c7d44afSShahaf Shuler int
21733c7d44afSShahaf Shuler mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
21743c7d44afSShahaf Shuler {
21753c7d44afSShahaf Shuler #ifdef HAVE_UPDATE_CQ_CI
21763c7d44afSShahaf Shuler 	struct priv *priv = mlx5_get_priv(dev);
21773c7d44afSShahaf Shuler 	struct rxq *rxq = (*priv->rxqs)[rx_queue_id];
21783c7d44afSShahaf Shuler 	struct rxq_ctrl *rxq_ctrl = container_of(rxq, struct rxq_ctrl, rxq);
21793c7d44afSShahaf Shuler 	struct ibv_cq *cq = rxq_ctrl->cq;
21803c7d44afSShahaf Shuler 	uint16_t ci = rxq->cq_ci;
21813c7d44afSShahaf Shuler 	int ret = 0;
21823c7d44afSShahaf Shuler 
21833c7d44afSShahaf Shuler 	ibv_mlx5_exp_update_cq_ci(cq, ci);
21843c7d44afSShahaf Shuler 	ret = ibv_req_notify_cq(cq, 0);
21853c7d44afSShahaf Shuler #else
21863c7d44afSShahaf Shuler 	int ret = -1;
21873c7d44afSShahaf Shuler 	(void)dev;
21883c7d44afSShahaf Shuler 	(void)rx_queue_id;
21893c7d44afSShahaf Shuler #endif
21903c7d44afSShahaf Shuler 	if (ret)
21913c7d44afSShahaf Shuler 		WARN("unable to arm interrupt on rx queue %d", rx_queue_id);
21923c7d44afSShahaf Shuler 	return ret;
21933c7d44afSShahaf Shuler }
21943c7d44afSShahaf Shuler 
21953c7d44afSShahaf Shuler /**
21963c7d44afSShahaf Shuler  * DPDK callback for rx queue interrupt disable.
21973c7d44afSShahaf Shuler  *
21983c7d44afSShahaf Shuler  * @param dev
21993c7d44afSShahaf Shuler  *   Pointer to Ethernet device structure.
22003c7d44afSShahaf Shuler  * @param rx_queue_id
22013c7d44afSShahaf Shuler  *   RX queue number
22023c7d44afSShahaf Shuler  *
22033c7d44afSShahaf Shuler  * @return
22043c7d44afSShahaf Shuler  *   0 on success, negative on failure.
22053c7d44afSShahaf Shuler  */
22063c7d44afSShahaf Shuler int
22073c7d44afSShahaf Shuler mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)
22083c7d44afSShahaf Shuler {
22093c7d44afSShahaf Shuler #ifdef HAVE_UPDATE_CQ_CI
22103c7d44afSShahaf Shuler 	struct priv *priv = mlx5_get_priv(dev);
22113c7d44afSShahaf Shuler 	struct rxq *rxq = (*priv->rxqs)[rx_queue_id];
22123c7d44afSShahaf Shuler 	struct rxq_ctrl *rxq_ctrl = container_of(rxq, struct rxq_ctrl, rxq);
22133c7d44afSShahaf Shuler 	struct ibv_cq *cq = rxq_ctrl->cq;
22143c7d44afSShahaf Shuler 	struct ibv_cq *ev_cq;
22153c7d44afSShahaf Shuler 	void *ev_ctx;
22163c7d44afSShahaf Shuler 	int ret = 0;
22173c7d44afSShahaf Shuler 
22183c7d44afSShahaf Shuler 	ret = ibv_get_cq_event(cq->channel, &ev_cq, &ev_ctx);
22193c7d44afSShahaf Shuler 	if (ret || ev_cq != cq)
22203c7d44afSShahaf Shuler 		ret = -1;
22213c7d44afSShahaf Shuler 	else
22223c7d44afSShahaf Shuler 		ibv_ack_cq_events(cq, 1);
22233c7d44afSShahaf Shuler #else
22243c7d44afSShahaf Shuler 	int ret = -1;
22253c7d44afSShahaf Shuler 	(void)dev;
22263c7d44afSShahaf Shuler 	(void)rx_queue_id;
22273c7d44afSShahaf Shuler #endif
22283c7d44afSShahaf Shuler 	if (ret)
22293c7d44afSShahaf Shuler 		WARN("unable to disable interrupt on rx queue %d",
22303c7d44afSShahaf Shuler 		     rx_queue_id);
22313c7d44afSShahaf Shuler 	return ret;
22323c7d44afSShahaf Shuler }
2233