xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 61b09ae45a977eceb16b0d4511e12fc4888ef89d)
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 
77*61b09ae4SNélio Laranjeiro static inline void
78*61b09ae4SNélio Laranjeiro txq_complete(struct txq *txq) __attribute__((always_inline));
79*61b09ae4SNé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
85ff1807a3SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq) __attribute__((always_inline));
86ff1807a3SNélio Laranjeiro 
87ff1807a3SNélio Laranjeiro static inline uint32_t
88ff1807a3SNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
89ff1807a3SNélio Laranjeiro 	__attribute__((always_inline));
90ff1807a3SNélio Laranjeiro 
91ff1807a3SNélio Laranjeiro static inline int
92ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
93ff1807a3SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
94ff1807a3SNélio Laranjeiro 		 __attribute__((always_inline));
95ff1807a3SNélio Laranjeiro 
96ff1807a3SNélio Laranjeiro static inline uint32_t
97ff1807a3SNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
98ff1807a3SNélio Laranjeiro 		   __attribute__((always_inline));
99ff1807a3SNélio Laranjeiro 
10099c12dccSNélio Laranjeiro #ifndef NDEBUG
10199c12dccSNélio Laranjeiro 
10299c12dccSNélio Laranjeiro /**
10399c12dccSNélio Laranjeiro  * Verify or set magic value in CQE.
10499c12dccSNélio Laranjeiro  *
10599c12dccSNélio Laranjeiro  * @param cqe
10699c12dccSNélio Laranjeiro  *   Pointer to CQE.
10799c12dccSNélio Laranjeiro  *
10899c12dccSNélio Laranjeiro  * @return
10999c12dccSNélio Laranjeiro  *   0 the first time.
11099c12dccSNélio Laranjeiro  */
11199c12dccSNélio Laranjeiro static inline int
11297267b8eSNelio Laranjeiro check_cqe_seen(volatile struct mlx5_cqe *cqe)
11399c12dccSNélio Laranjeiro {
11499c12dccSNélio Laranjeiro 	static const uint8_t magic[] = "seen";
115ea3bc3b1SNélio Laranjeiro 	volatile uint8_t (*buf)[sizeof(cqe->rsvd0)] = &cqe->rsvd0;
11699c12dccSNélio Laranjeiro 	int ret = 1;
11799c12dccSNélio Laranjeiro 	unsigned int i;
11899c12dccSNélio Laranjeiro 
11999c12dccSNélio Laranjeiro 	for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i)
12099c12dccSNélio Laranjeiro 		if (!ret || (*buf)[i] != magic[i]) {
12199c12dccSNélio Laranjeiro 			ret = 0;
12299c12dccSNélio Laranjeiro 			(*buf)[i] = magic[i];
12399c12dccSNélio Laranjeiro 		}
12499c12dccSNélio Laranjeiro 	return ret;
12599c12dccSNélio Laranjeiro }
12699c12dccSNélio Laranjeiro 
12799c12dccSNélio Laranjeiro #endif /* NDEBUG */
1286218063bSNélio Laranjeiro 
12999c12dccSNélio Laranjeiro /**
13099c12dccSNélio Laranjeiro  * Check whether CQE is valid.
13199c12dccSNélio Laranjeiro  *
13299c12dccSNélio Laranjeiro  * @param cqe
13399c12dccSNélio Laranjeiro  *   Pointer to CQE.
13499c12dccSNélio Laranjeiro  * @param cqes_n
13599c12dccSNélio Laranjeiro  *   Size of completion queue.
13699c12dccSNélio Laranjeiro  * @param ci
13799c12dccSNélio Laranjeiro  *   Consumer index.
13899c12dccSNélio Laranjeiro  *
13999c12dccSNélio Laranjeiro  * @return
14099c12dccSNélio Laranjeiro  *   0 on success, 1 on failure.
14199c12dccSNélio Laranjeiro  */
14299c12dccSNélio Laranjeiro static inline int
14397267b8eSNelio Laranjeiro check_cqe(volatile struct mlx5_cqe *cqe,
14499c12dccSNélio Laranjeiro 	  unsigned int cqes_n, const uint16_t ci)
1456218063bSNélio Laranjeiro {
14699c12dccSNélio Laranjeiro 	uint16_t idx = ci & cqes_n;
14799c12dccSNélio Laranjeiro 	uint8_t op_own = cqe->op_own;
14899c12dccSNélio Laranjeiro 	uint8_t op_owner = MLX5_CQE_OWNER(op_own);
14999c12dccSNélio Laranjeiro 	uint8_t op_code = MLX5_CQE_OPCODE(op_own);
1506218063bSNélio Laranjeiro 
15199c12dccSNélio Laranjeiro 	if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID)))
15299c12dccSNélio Laranjeiro 		return 1; /* No CQE. */
15399c12dccSNélio Laranjeiro #ifndef NDEBUG
15499c12dccSNélio Laranjeiro 	if ((op_code == MLX5_CQE_RESP_ERR) ||
15599c12dccSNélio Laranjeiro 	    (op_code == MLX5_CQE_REQ_ERR)) {
15699c12dccSNélio Laranjeiro 		volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe;
15799c12dccSNélio Laranjeiro 		uint8_t syndrome = err_cqe->syndrome;
15899c12dccSNélio Laranjeiro 
15999c12dccSNélio Laranjeiro 		if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) ||
16099c12dccSNélio Laranjeiro 		    (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR))
16199c12dccSNélio Laranjeiro 			return 0;
16297267b8eSNelio Laranjeiro 		if (!check_cqe_seen(cqe))
16399c12dccSNélio Laranjeiro 			ERROR("unexpected CQE error %u (0x%02x)"
16499c12dccSNélio Laranjeiro 			      " syndrome 0x%02x",
16599c12dccSNélio Laranjeiro 			      op_code, op_code, syndrome);
16699c12dccSNélio Laranjeiro 		return 1;
16799c12dccSNélio Laranjeiro 	} else if ((op_code != MLX5_CQE_RESP_SEND) &&
16899c12dccSNélio Laranjeiro 		   (op_code != MLX5_CQE_REQ)) {
16997267b8eSNelio Laranjeiro 		if (!check_cqe_seen(cqe))
17099c12dccSNélio Laranjeiro 			ERROR("unexpected CQE opcode %u (0x%02x)",
17199c12dccSNélio Laranjeiro 			      op_code, op_code);
17299c12dccSNélio Laranjeiro 		return 1;
1736218063bSNélio Laranjeiro 	}
17499c12dccSNélio Laranjeiro #endif /* NDEBUG */
17599c12dccSNélio Laranjeiro 	return 0;
1766218063bSNélio Laranjeiro }
1772e22920bSAdrien Mazarguil 
178fdcb0f53SNélio Laranjeiro /**
179fdcb0f53SNélio Laranjeiro  * Return the address of the WQE.
180fdcb0f53SNélio Laranjeiro  *
181fdcb0f53SNélio Laranjeiro  * @param txq
182fdcb0f53SNélio Laranjeiro  *   Pointer to TX queue structure.
183fdcb0f53SNélio Laranjeiro  * @param  wqe_ci
184fdcb0f53SNélio Laranjeiro  *   WQE consumer index.
185fdcb0f53SNélio Laranjeiro  *
186fdcb0f53SNélio Laranjeiro  * @return
187fdcb0f53SNélio Laranjeiro  *   WQE address.
188fdcb0f53SNélio Laranjeiro  */
189fdcb0f53SNélio Laranjeiro static inline uintptr_t *
190fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(struct txq *txq, uint16_t ci)
191fdcb0f53SNélio Laranjeiro {
192fdcb0f53SNélio Laranjeiro 	ci &= ((1 << txq->wqe_n) - 1);
193fdcb0f53SNélio Laranjeiro 	return (uintptr_t *)((uintptr_t)txq->wqes + ci * MLX5_WQE_SIZE);
194fdcb0f53SNélio Laranjeiro }
195fdcb0f53SNélio Laranjeiro 
1962e22920bSAdrien Mazarguil /**
1972e22920bSAdrien Mazarguil  * Manage TX completions.
1982e22920bSAdrien Mazarguil  *
1992e22920bSAdrien Mazarguil  * When sending a burst, mlx5_tx_burst() posts several WRs.
2002e22920bSAdrien Mazarguil  *
2012e22920bSAdrien Mazarguil  * @param txq
2022e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
2032e22920bSAdrien Mazarguil  */
204a6ca35aaSNélio Laranjeiro static inline void
2052e22920bSAdrien Mazarguil txq_complete(struct txq *txq)
2062e22920bSAdrien Mazarguil {
207b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
208e2f116eeSNélio Laranjeiro 	const unsigned int cqe_n = 1 << txq->cqe_n;
20999c12dccSNélio Laranjeiro 	const unsigned int cqe_cnt = cqe_n - 1;
2101d88ba17SNélio Laranjeiro 	uint16_t elts_free = txq->elts_tail;
2111d88ba17SNélio Laranjeiro 	uint16_t elts_tail;
2121d88ba17SNélio Laranjeiro 	uint16_t cq_ci = txq->cq_ci;
21397267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe = NULL;
214fdcb0f53SNélio Laranjeiro 	volatile struct mlx5_wqe_ctrl *ctrl;
2152e22920bSAdrien Mazarguil 
21699c12dccSNélio Laranjeiro 	do {
21797267b8eSNelio Laranjeiro 		volatile struct mlx5_cqe *tmp;
2181d88ba17SNélio Laranjeiro 
21997267b8eSNelio Laranjeiro 		tmp = &(*txq->cqes)[cq_ci & cqe_cnt];
22097267b8eSNelio Laranjeiro 		if (check_cqe(tmp, cqe_n, cq_ci))
2211d88ba17SNélio Laranjeiro 			break;
222c305090bSAdrien Mazarguil 		cqe = tmp;
22399c12dccSNélio Laranjeiro #ifndef NDEBUG
22499c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) {
22597267b8eSNelio Laranjeiro 			if (!check_cqe_seen(cqe))
22699c12dccSNélio Laranjeiro 				ERROR("unexpected compressed CQE, TX stopped");
22799c12dccSNélio Laranjeiro 			return;
2282e22920bSAdrien Mazarguil 		}
22999c12dccSNélio Laranjeiro 		if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) ||
23099c12dccSNélio Laranjeiro 		    (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) {
23197267b8eSNelio Laranjeiro 			if (!check_cqe_seen(cqe))
23299c12dccSNélio Laranjeiro 				ERROR("unexpected error CQE, TX stopped");
23399c12dccSNélio Laranjeiro 			return;
23499c12dccSNélio Laranjeiro 		}
23599c12dccSNélio Laranjeiro #endif /* NDEBUG */
23699c12dccSNélio Laranjeiro 		++cq_ci;
23799c12dccSNélio Laranjeiro 	} while (1);
238c305090bSAdrien Mazarguil 	if (unlikely(cqe == NULL))
2391d88ba17SNélio Laranjeiro 		return;
240fdcb0f53SNélio Laranjeiro 	ctrl = (volatile struct mlx5_wqe_ctrl *)
241fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, ntohs(cqe->wqe_counter));
242fdcb0f53SNélio Laranjeiro 	elts_tail = ctrl->ctrl3;
243a821d09dSNélio Laranjeiro 	assert(elts_tail < (1 << txq->wqe_n));
2441d88ba17SNélio Laranjeiro 	/* Free buffers. */
245c305090bSAdrien Mazarguil 	while (elts_free != elts_tail) {
2461d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt = (*txq->elts)[elts_free];
247a859e8a9SNelio Laranjeiro 		unsigned int elts_free_next =
2481d88ba17SNélio Laranjeiro 			(elts_free + 1) & (elts_n - 1);
2491d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next];
250a859e8a9SNelio Laranjeiro 
251b185e63fSAdrien Mazarguil #ifndef NDEBUG
252b185e63fSAdrien Mazarguil 		/* Poisoning. */
2531d88ba17SNélio Laranjeiro 		memset(&(*txq->elts)[elts_free],
2541d88ba17SNélio Laranjeiro 		       0x66,
2551d88ba17SNélio Laranjeiro 		       sizeof((*txq->elts)[elts_free]));
256b185e63fSAdrien Mazarguil #endif
2571d88ba17SNélio Laranjeiro 		RTE_MBUF_PREFETCH_TO_FREE(elt_next);
2581d88ba17SNélio Laranjeiro 		/* Only one segment needs to be freed. */
2591d88ba17SNélio Laranjeiro 		rte_pktmbuf_free_seg(elt);
260a859e8a9SNelio Laranjeiro 		elts_free = elts_free_next;
261c305090bSAdrien Mazarguil 	}
2621d88ba17SNélio Laranjeiro 	txq->cq_ci = cq_ci;
2632e22920bSAdrien Mazarguil 	txq->elts_tail = elts_tail;
2641d88ba17SNélio Laranjeiro 	/* Update the consumer index. */
2651d88ba17SNélio Laranjeiro 	rte_wmb();
2661d88ba17SNélio Laranjeiro 	*txq->cq_db = htonl(cq_ci);
2672e22920bSAdrien Mazarguil }
2682e22920bSAdrien Mazarguil 
2692e22920bSAdrien Mazarguil /**
2708340392eSAdrien Mazarguil  * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
2718340392eSAdrien Mazarguil  * the cloned mbuf is allocated is returned instead.
2728340392eSAdrien Mazarguil  *
2738340392eSAdrien Mazarguil  * @param buf
2748340392eSAdrien Mazarguil  *   Pointer to mbuf.
2758340392eSAdrien Mazarguil  *
2768340392eSAdrien Mazarguil  * @return
2778340392eSAdrien Mazarguil  *   Memory pool where data is located for given mbuf.
2788340392eSAdrien Mazarguil  */
2798340392eSAdrien Mazarguil static struct rte_mempool *
2808340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf)
2818340392eSAdrien Mazarguil {
2828340392eSAdrien Mazarguil 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
2838340392eSAdrien Mazarguil 		return rte_mbuf_from_indirect(buf)->pool;
2848340392eSAdrien Mazarguil 	return buf->pool;
2858340392eSAdrien Mazarguil }
2868340392eSAdrien Mazarguil 
2878340392eSAdrien Mazarguil /**
2882e22920bSAdrien Mazarguil  * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[].
2892e22920bSAdrien Mazarguil  * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
2902e22920bSAdrien Mazarguil  * remove an entry first.
2912e22920bSAdrien Mazarguil  *
2922e22920bSAdrien Mazarguil  * @param txq
2932e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
2942e22920bSAdrien Mazarguil  * @param[in] mp
2952e22920bSAdrien Mazarguil  *   Memory Pool for which a Memory Region lkey must be returned.
2962e22920bSAdrien Mazarguil  *
2972e22920bSAdrien Mazarguil  * @return
2982e22920bSAdrien Mazarguil  *   mr->lkey on success, (uint32_t)-1 on failure.
2992e22920bSAdrien Mazarguil  */
300491770faSNélio Laranjeiro static inline uint32_t
301d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
3022e22920bSAdrien Mazarguil {
3032e22920bSAdrien Mazarguil 	unsigned int i;
304491770faSNélio Laranjeiro 	uint32_t lkey = (uint32_t)-1;
3052e22920bSAdrien Mazarguil 
3062e22920bSAdrien Mazarguil 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
3072e22920bSAdrien Mazarguil 		if (unlikely(txq->mp2mr[i].mp == NULL)) {
3082e22920bSAdrien Mazarguil 			/* Unknown MP, add a new MR for it. */
3092e22920bSAdrien Mazarguil 			break;
3102e22920bSAdrien Mazarguil 		}
3112e22920bSAdrien Mazarguil 		if (txq->mp2mr[i].mp == mp) {
3122e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].lkey != (uint32_t)-1);
3131d88ba17SNélio Laranjeiro 			assert(htonl(txq->mp2mr[i].mr->lkey) ==
3141d88ba17SNélio Laranjeiro 			       txq->mp2mr[i].lkey);
315491770faSNélio Laranjeiro 			lkey = txq->mp2mr[i].lkey;
316491770faSNélio Laranjeiro 			break;
3172e22920bSAdrien Mazarguil 		}
3182e22920bSAdrien Mazarguil 	}
319491770faSNélio Laranjeiro 	if (unlikely(lkey == (uint32_t)-1))
320491770faSNélio Laranjeiro 		lkey = txq_mp2mr_reg(txq, mp, i);
321491770faSNélio Laranjeiro 	return lkey;
3220a3b350dSOlga Shern }
3230a3b350dSOlga Shern 
324e192ef80SYaacov Hazan /**
3251d88ba17SNélio Laranjeiro  * Ring TX queue doorbell.
3261d88ba17SNélio Laranjeiro  *
3271d88ba17SNélio Laranjeiro  * @param txq
3281d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
3291d88ba17SNélio Laranjeiro  */
3301d88ba17SNélio Laranjeiro static inline void
3311d88ba17SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq)
3321d88ba17SNélio Laranjeiro {
3331d88ba17SNélio Laranjeiro 	uint8_t *dst = (uint8_t *)((uintptr_t)txq->bf_reg + txq->bf_offset);
3341d88ba17SNélio Laranjeiro 	uint32_t data[4] = {
3351d88ba17SNélio Laranjeiro 		htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
3361d88ba17SNélio Laranjeiro 		htonl(txq->qp_num_8s),
3371d88ba17SNélio Laranjeiro 		0,
3381d88ba17SNélio Laranjeiro 		0,
3391d88ba17SNélio Laranjeiro 	};
3401d88ba17SNélio Laranjeiro 	rte_wmb();
3411d88ba17SNélio Laranjeiro 	*txq->qp_db = htonl(txq->wqe_ci);
3421d88ba17SNélio Laranjeiro 	/* Ensure ordering between DB record and BF copy. */
3431d88ba17SNélio Laranjeiro 	rte_wmb();
344609a0767SElad Persiko 	memcpy(dst, (uint8_t *)data, 16);
345d5793daeSNélio Laranjeiro 	txq->bf_offset ^= (1 << txq->bf_buf_size);
3461d88ba17SNélio Laranjeiro }
347e192ef80SYaacov Hazan 
3481d88ba17SNélio Laranjeiro /**
3491d88ba17SNélio Laranjeiro  * Prefetch a CQE.
3501d88ba17SNélio Laranjeiro  *
3511d88ba17SNélio Laranjeiro  * @param txq
3521d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
3531d88ba17SNélio Laranjeiro  * @param cqe_ci
3541d88ba17SNélio Laranjeiro  *   CQE consumer index.
3551d88ba17SNélio Laranjeiro  */
3561d88ba17SNélio Laranjeiro static inline void
3571d88ba17SNélio Laranjeiro tx_prefetch_cqe(struct txq *txq, uint16_t ci)
3581d88ba17SNélio Laranjeiro {
359e2f116eeSNélio Laranjeiro 	volatile struct mlx5_cqe *cqe;
3601d88ba17SNélio Laranjeiro 
361e2f116eeSNélio Laranjeiro 	cqe = &(*txq->cqes)[ci & ((1 << txq->cqe_n) - 1)];
3621d88ba17SNélio Laranjeiro 	rte_prefetch0(cqe);
363e192ef80SYaacov Hazan }
364e192ef80SYaacov Hazan 
3652e22920bSAdrien Mazarguil /**
3662e22920bSAdrien Mazarguil  * DPDK callback for TX.
3672e22920bSAdrien Mazarguil  *
3682e22920bSAdrien Mazarguil  * @param dpdk_txq
3692e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
3702e22920bSAdrien Mazarguil  * @param[in] pkts
3712e22920bSAdrien Mazarguil  *   Packets to transmit.
3722e22920bSAdrien Mazarguil  * @param pkts_n
3732e22920bSAdrien Mazarguil  *   Number of packets in array.
3742e22920bSAdrien Mazarguil  *
3752e22920bSAdrien Mazarguil  * @return
3762e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
3772e22920bSAdrien Mazarguil  */
3782e22920bSAdrien Mazarguil uint16_t
3792e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
3802e22920bSAdrien Mazarguil {
3812e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
3821d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
383b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
384c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
385a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
3862e22920bSAdrien Mazarguil 	unsigned int max;
387c305090bSAdrien Mazarguil 	unsigned int comp;
3889a7fa9f7SNélio Laranjeiro 	volatile struct mlx5_wqe_v *wqe = NULL;
3896579c27cSNélio Laranjeiro 	unsigned int segs_n = 0;
3906579c27cSNélio Laranjeiro 	struct rte_mbuf *buf = NULL;
3916579c27cSNélio Laranjeiro 	uint8_t *raw;
3922e22920bSAdrien Mazarguil 
3931d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
3941d88ba17SNélio Laranjeiro 		return 0;
3955e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
3961d88ba17SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
3971d88ba17SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci + 1);
398c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
3991d88ba17SNélio Laranjeiro 	/* Start processing. */
4002e22920bSAdrien Mazarguil 	txq_complete(txq);
4014f52bbfbSNelio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
4022e22920bSAdrien Mazarguil 	if (max > elts_n)
4032e22920bSAdrien Mazarguil 		max -= elts_n;
404c3d62cc9SAdrien Mazarguil 	do {
4059a7fa9f7SNélio Laranjeiro 		volatile rte_v128u32_t *dseg = NULL;
406573f54afSNélio Laranjeiro 		uint32_t length;
4078688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
4086579c27cSNélio Laranjeiro 		uintptr_t addr;
4099a7fa9f7SNélio Laranjeiro 		uint64_t naddr;
410b8fe952eSNélio Laranjeiro 		uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE;
411b8fe952eSNélio Laranjeiro 		uint8_t ehdr[2];
4129a7fa9f7SNélio Laranjeiro 		uint8_t cs_flags = 0;
4136579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
4146579c27cSNélio Laranjeiro 		uint32_t total_length = 0;
4156579c27cSNélio Laranjeiro #endif
4162e22920bSAdrien Mazarguil 
4176579c27cSNélio Laranjeiro 		/* first_seg */
4186579c27cSNélio Laranjeiro 		buf = *(pkts++);
4196579c27cSNélio Laranjeiro 		segs_n = buf->nb_segs;
420c3d62cc9SAdrien Mazarguil 		/*
421c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
422c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
423c3d62cc9SAdrien Mazarguil 		 */
424a5bf6af9SAdrien Mazarguil 		assert(segs_n);
425a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
426c3d62cc9SAdrien Mazarguil 			break;
427a5bf6af9SAdrien Mazarguil 		max -= segs_n;
4286579c27cSNélio Laranjeiro 		--segs_n;
4296579c27cSNélio Laranjeiro 		if (!segs_n)
430c3d62cc9SAdrien Mazarguil 			--pkts_n;
4319a7fa9f7SNélio Laranjeiro 		wqe = (volatile struct mlx5_wqe_v *)
432fdcb0f53SNélio Laranjeiro 			tx_mlx5_wqe(txq, txq->wqe_ci);
433fdcb0f53SNélio Laranjeiro 		rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
4346579c27cSNélio Laranjeiro 		if (pkts_n > 1)
435c3d62cc9SAdrien Mazarguil 			rte_prefetch0(*pkts);
4366579c27cSNélio Laranjeiro 		addr = rte_pktmbuf_mtod(buf, uintptr_t);
4372e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
438b8fe952eSNélio Laranjeiro 		ehdr[0] = ((uint8_t *)addr)[0];
439b8fe952eSNélio Laranjeiro 		ehdr[1] = ((uint8_t *)addr)[1];
4406579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
4416579c27cSNélio Laranjeiro 		total_length = length;
4426579c27cSNélio Laranjeiro #endif
4436579c27cSNélio Laranjeiro 		assert(length >= MLX5_WQE_DWORD_SIZE);
4442e22920bSAdrien Mazarguil 		/* Update element. */
4451d88ba17SNélio Laranjeiro 		(*txq->elts)[elts_head] = buf;
4466579c27cSNélio Laranjeiro 		elts_head = (elts_head + 1) & (elts_n - 1);
4475e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
4486579c27cSNélio Laranjeiro 		if (pkts_n > 1) {
4496579c27cSNélio Laranjeiro 			volatile void *pkt_addr;
4506579c27cSNélio Laranjeiro 
4516579c27cSNélio Laranjeiro 			pkt_addr = rte_pktmbuf_mtod(*pkts, volatile void *);
4526579c27cSNélio Laranjeiro 			rte_prefetch0(pkt_addr);
4536579c27cSNélio Laranjeiro 		}
4541d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
4551d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
4561d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
4579a7fa9f7SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
4581d88ba17SNélio Laranjeiro 		}
459b8fe952eSNélio Laranjeiro 		raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE;
460b8fe952eSNélio Laranjeiro 		/*
461b8fe952eSNélio Laranjeiro 		 * Start by copying the Ethernet header minus the first two
462b8fe952eSNélio Laranjeiro 		 * bytes which will be appended at the end of the Ethernet
463b8fe952eSNélio Laranjeiro 		 * segment.
464b8fe952eSNélio Laranjeiro 		 */
465b8fe952eSNélio Laranjeiro 		memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 16);
4666579c27cSNélio Laranjeiro 		length -= MLX5_WQE_DWORD_SIZE;
4676579c27cSNélio Laranjeiro 		addr += MLX5_WQE_DWORD_SIZE;
4686579c27cSNélio Laranjeiro 		/* Replace the Ethernet type by the VLAN if necessary. */
4696579c27cSNélio Laranjeiro 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
4706579c27cSNélio Laranjeiro 			uint32_t vlan = htonl(0x81000000 | buf->vlan_tci);
4716579c27cSNélio Laranjeiro 
472b8fe952eSNélio Laranjeiro 			memcpy((uint8_t *)(raw + MLX5_WQE_DWORD_SIZE - 2 -
4736579c27cSNélio Laranjeiro 					   sizeof(vlan)),
4746579c27cSNélio Laranjeiro 			       &vlan, sizeof(vlan));
4756579c27cSNélio Laranjeiro 			addr -= sizeof(vlan);
4766579c27cSNélio Laranjeiro 			length += sizeof(vlan);
4776579c27cSNélio Laranjeiro 		}
4786579c27cSNélio Laranjeiro 		/* Inline if enough room. */
4796579c27cSNélio Laranjeiro 		if (txq->max_inline != 0) {
480fdcb0f53SNélio Laranjeiro 			uintptr_t end = (uintptr_t)
481fdcb0f53SNélio Laranjeiro 				(((uintptr_t)txq->wqes) +
482fdcb0f53SNélio Laranjeiro 				 (1 << txq->wqe_n) * MLX5_WQE_SIZE);
4836579c27cSNélio Laranjeiro 			uint16_t max_inline =
4846579c27cSNélio Laranjeiro 				txq->max_inline * RTE_CACHE_LINE_SIZE;
4856579c27cSNélio Laranjeiro 			uint16_t room;
4866579c27cSNélio Laranjeiro 
487b8fe952eSNélio Laranjeiro 			/*
488b8fe952eSNélio Laranjeiro 			 * raw starts two bytes before the boundary to
489b8fe952eSNélio Laranjeiro 			 * continue the above copy of packet data.
490b8fe952eSNélio Laranjeiro 			 */
491b8fe952eSNélio Laranjeiro 			raw += MLX5_WQE_DWORD_SIZE - 2;
4926579c27cSNélio Laranjeiro 			room = end - (uintptr_t)raw;
4936579c27cSNélio Laranjeiro 			if (room > max_inline) {
4946579c27cSNélio Laranjeiro 				uintptr_t addr_end = (addr + max_inline) &
4956579c27cSNélio Laranjeiro 					~(RTE_CACHE_LINE_SIZE - 1);
4966579c27cSNélio Laranjeiro 				uint16_t copy_b = ((addr_end - addr) > length) ?
4976579c27cSNélio Laranjeiro 						  length :
4986579c27cSNélio Laranjeiro 						  (addr_end - addr);
4996579c27cSNélio Laranjeiro 
5006579c27cSNélio Laranjeiro 				rte_memcpy((void *)raw, (void *)addr, copy_b);
5016579c27cSNélio Laranjeiro 				addr += copy_b;
5026579c27cSNélio Laranjeiro 				length -= copy_b;
5036579c27cSNélio Laranjeiro 				pkt_inline_sz += copy_b;
5046579c27cSNélio Laranjeiro 				/* Sanity check. */
5056579c27cSNélio Laranjeiro 				assert(addr <= addr_end);
5066579c27cSNélio Laranjeiro 			}
5076579c27cSNélio Laranjeiro 			/*
5086579c27cSNélio Laranjeiro 			 * 2 DWORDs consumed by the WQE header + 1 DSEG +
5096579c27cSNélio Laranjeiro 			 * the size of the inline part of the packet.
5106579c27cSNélio Laranjeiro 			 */
5116579c27cSNélio Laranjeiro 			ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
5126579c27cSNélio Laranjeiro 			if (length > 0) {
5139a7fa9f7SNélio Laranjeiro 				dseg = (volatile rte_v128u32_t *)
5146579c27cSNélio Laranjeiro 					((uintptr_t)wqe +
5156579c27cSNélio Laranjeiro 					 (ds * MLX5_WQE_DWORD_SIZE));
5166579c27cSNélio Laranjeiro 				if ((uintptr_t)dseg >= end)
5179a7fa9f7SNélio Laranjeiro 					dseg = (volatile rte_v128u32_t *)
518fdcb0f53SNélio Laranjeiro 					       txq->wqes;
5196579c27cSNélio Laranjeiro 				goto use_dseg;
5206579c27cSNélio Laranjeiro 			} else if (!segs_n) {
5216579c27cSNélio Laranjeiro 				goto next_pkt;
5226579c27cSNélio Laranjeiro 			} else {
5236579c27cSNélio Laranjeiro 				goto next_seg;
5246579c27cSNélio Laranjeiro 			}
5256579c27cSNélio Laranjeiro 		} else {
5266579c27cSNélio Laranjeiro 			/*
5276579c27cSNélio Laranjeiro 			 * No inline has been done in the packet, only the
5286579c27cSNélio Laranjeiro 			 * Ethernet Header as been stored.
5296579c27cSNélio Laranjeiro 			 */
5309a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
5316579c27cSNélio Laranjeiro 				((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE));
5326579c27cSNélio Laranjeiro 			ds = 3;
5336579c27cSNélio Laranjeiro use_dseg:
5346579c27cSNélio Laranjeiro 			/* Add the remaining packet as a simple ds. */
5359a7fa9f7SNélio Laranjeiro 			naddr = htonll(addr);
5369a7fa9f7SNélio Laranjeiro 			*dseg = (rte_v128u32_t){
5379a7fa9f7SNélio Laranjeiro 				htonl(length),
5389a7fa9f7SNélio Laranjeiro 				txq_mp2mr(txq, txq_mb2mp(buf)),
5399a7fa9f7SNélio Laranjeiro 				naddr,
5409a7fa9f7SNélio Laranjeiro 				naddr >> 32,
5416579c27cSNélio Laranjeiro 			};
5426579c27cSNélio Laranjeiro 			++ds;
5436579c27cSNélio Laranjeiro 			if (!segs_n)
5446579c27cSNélio Laranjeiro 				goto next_pkt;
5456579c27cSNélio Laranjeiro 		}
5466579c27cSNélio Laranjeiro next_seg:
5476579c27cSNélio Laranjeiro 		assert(buf);
5486579c27cSNélio Laranjeiro 		assert(ds);
5496579c27cSNélio Laranjeiro 		assert(wqe);
550a5bf6af9SAdrien Mazarguil 		/*
551a5bf6af9SAdrien Mazarguil 		 * Spill on next WQE when the current one does not have
552a5bf6af9SAdrien Mazarguil 		 * enough room left. Size of WQE must a be a multiple
553a5bf6af9SAdrien Mazarguil 		 * of data segment size.
554a5bf6af9SAdrien Mazarguil 		 */
5558688b2f8SNélio Laranjeiro 		assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
5566579c27cSNélio Laranjeiro 		if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) {
5576579c27cSNélio Laranjeiro 			unsigned int n = (txq->wqe_ci + ((ds + 3) / 4)) &
5586579c27cSNélio Laranjeiro 				((1 << txq->wqe_n) - 1);
5596579c27cSNélio Laranjeiro 
5609a7fa9f7SNélio Laranjeiro 			dseg = (volatile rte_v128u32_t *)
561fdcb0f53SNélio Laranjeiro 			       tx_mlx5_wqe(txq, n);
562fdcb0f53SNélio Laranjeiro 			rte_prefetch0(tx_mlx5_wqe(txq, n + 1));
5636579c27cSNélio Laranjeiro 		} else {
564a5bf6af9SAdrien Mazarguil 			++dseg;
5656579c27cSNélio Laranjeiro 		}
566a5bf6af9SAdrien Mazarguil 		++ds;
567a5bf6af9SAdrien Mazarguil 		buf = buf->next;
568a5bf6af9SAdrien Mazarguil 		assert(buf);
5696579c27cSNélio Laranjeiro 		length = DATA_LEN(buf);
570a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
5716579c27cSNélio Laranjeiro 		total_length += length;
572a5bf6af9SAdrien Mazarguil #endif
5736579c27cSNélio Laranjeiro 		/* Store segment information. */
5749a7fa9f7SNélio Laranjeiro 		naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t));
5759a7fa9f7SNélio Laranjeiro 		*dseg = (rte_v128u32_t){
5769a7fa9f7SNélio Laranjeiro 			htonl(length),
5779a7fa9f7SNélio Laranjeiro 			txq_mp2mr(txq, txq_mb2mp(buf)),
5789a7fa9f7SNélio Laranjeiro 			naddr,
5799a7fa9f7SNélio Laranjeiro 			naddr >> 32,
5806579c27cSNélio Laranjeiro 		};
5816579c27cSNélio Laranjeiro 		(*txq->elts)[elts_head] = buf;
5826579c27cSNélio Laranjeiro 		elts_head = (elts_head + 1) & (elts_n - 1);
583a5bf6af9SAdrien Mazarguil 		++j;
5846579c27cSNélio Laranjeiro 		--segs_n;
5856579c27cSNélio Laranjeiro 		if (segs_n)
5866579c27cSNélio Laranjeiro 			goto next_seg;
5876579c27cSNélio Laranjeiro 		else
5886579c27cSNélio Laranjeiro 			--pkts_n;
5896579c27cSNélio Laranjeiro next_pkt:
5906579c27cSNélio Laranjeiro 		++i;
591b8fe952eSNélio Laranjeiro 		/* Initialize known and common part of the WQE structure. */
5929a7fa9f7SNélio Laranjeiro 		wqe->ctrl = (rte_v128u32_t){
5939a7fa9f7SNélio Laranjeiro 			htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
5949a7fa9f7SNélio Laranjeiro 			htonl(txq->qp_num_8s | ds),
5959a7fa9f7SNélio Laranjeiro 			0,
5969a7fa9f7SNélio Laranjeiro 			0,
5979a7fa9f7SNélio Laranjeiro 		};
5989a7fa9f7SNélio Laranjeiro 		wqe->eseg = (rte_v128u32_t){
5999a7fa9f7SNélio Laranjeiro 			0,
6009a7fa9f7SNélio Laranjeiro 			cs_flags,
6019a7fa9f7SNélio Laranjeiro 			0,
6029a7fa9f7SNélio Laranjeiro 			(ehdr[1] << 24) | (ehdr[0] << 16) |
6039a7fa9f7SNélio Laranjeiro 			htons(pkt_inline_sz),
6049a7fa9f7SNélio Laranjeiro 		};
6056579c27cSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
60687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
607573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
6086579c27cSNélio Laranjeiro 		txq->stats.obytes += total_length;
60987011737SAdrien Mazarguil #endif
610c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
6112e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
6122e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
6132e22920bSAdrien Mazarguil 		return 0;
614c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
615a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + i + j;
616c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
6179a7fa9f7SNélio Laranjeiro 		volatile struct mlx5_wqe_ctrl *w =
6189a7fa9f7SNélio Laranjeiro 			(volatile struct mlx5_wqe_ctrl *)wqe;
6199a7fa9f7SNélio Laranjeiro 
620c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
6219a7fa9f7SNélio Laranjeiro 		w->ctrl2 = htonl(8);
622c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
6239a7fa9f7SNélio Laranjeiro 		w->ctrl3 = elts_head;
624c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
625c305090bSAdrien Mazarguil 	} else {
626c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
627c305090bSAdrien Mazarguil 	}
62887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
62987011737SAdrien Mazarguil 	/* Increment sent packets counter. */
63087011737SAdrien Mazarguil 	txq->stats.opackets += i;
63187011737SAdrien Mazarguil #endif
6322e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
6331d88ba17SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
6342e22920bSAdrien Mazarguil 	txq->elts_head = elts_head;
6352e22920bSAdrien Mazarguil 	return i;
6362e22920bSAdrien Mazarguil }
6372e22920bSAdrien Mazarguil 
6382e22920bSAdrien Mazarguil /**
639230189d9SNélio Laranjeiro  * Open a MPW session.
640230189d9SNélio Laranjeiro  *
641230189d9SNélio Laranjeiro  * @param txq
642230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
643230189d9SNélio Laranjeiro  * @param mpw
644230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
645230189d9SNélio Laranjeiro  * @param length
646230189d9SNélio Laranjeiro  *   Packet length.
647230189d9SNélio Laranjeiro  */
648230189d9SNélio Laranjeiro static inline void
649230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
650230189d9SNélio Laranjeiro {
651a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
652230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
653230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
654fdcb0f53SNélio Laranjeiro 		tx_mlx5_wqe(txq, idx + 1);
655230189d9SNélio Laranjeiro 
656230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
657230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
658230189d9SNélio Laranjeiro 	mpw->len = length;
659230189d9SNélio Laranjeiro 	mpw->total_len = 0;
660fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
6618688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
6628688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
6638688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
6648688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
6658688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
6668688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
667c904ae25SNélio Laranjeiro 				  (txq->wqe_ci << 8) | MLX5_OPCODE_TSO);
6688688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
6698688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
6708688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
6718688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
6728688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
6738688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
674230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
675230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
676230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
677230189d9SNélio Laranjeiro }
678230189d9SNélio Laranjeiro 
679230189d9SNélio Laranjeiro /**
680230189d9SNélio Laranjeiro  * Close a MPW session.
681230189d9SNélio Laranjeiro  *
682230189d9SNélio Laranjeiro  * @param txq
683230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
684230189d9SNélio Laranjeiro  * @param mpw
685230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
686230189d9SNélio Laranjeiro  */
687230189d9SNélio Laranjeiro static inline void
688230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
689230189d9SNélio Laranjeiro {
690230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
691230189d9SNélio Laranjeiro 
692230189d9SNélio Laranjeiro 	/*
693230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
694230189d9SNélio Laranjeiro 	 * count as 2.
695230189d9SNélio Laranjeiro 	 */
6968688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num));
697230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
698230189d9SNélio Laranjeiro 	if (num < 3)
699230189d9SNélio Laranjeiro 		++txq->wqe_ci;
700230189d9SNélio Laranjeiro 	else
701230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
702fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
703fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
704230189d9SNélio Laranjeiro }
705230189d9SNélio Laranjeiro 
706230189d9SNélio Laranjeiro /**
707230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
708230189d9SNélio Laranjeiro  *
709230189d9SNélio Laranjeiro  * @param dpdk_txq
710230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
711230189d9SNélio Laranjeiro  * @param[in] pkts
712230189d9SNélio Laranjeiro  *   Packets to transmit.
713230189d9SNélio Laranjeiro  * @param pkts_n
714230189d9SNélio Laranjeiro  *   Number of packets in array.
715230189d9SNélio Laranjeiro  *
716230189d9SNélio Laranjeiro  * @return
717230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
718230189d9SNélio Laranjeiro  */
719230189d9SNélio Laranjeiro uint16_t
720230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
721230189d9SNélio Laranjeiro {
722230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
723230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
724b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
725c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
726a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
727230189d9SNélio Laranjeiro 	unsigned int max;
728230189d9SNélio Laranjeiro 	unsigned int comp;
729230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
730230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
731230189d9SNélio Laranjeiro 	};
732230189d9SNélio Laranjeiro 
733c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
734c3d62cc9SAdrien Mazarguil 		return 0;
735230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
736230189d9SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
737fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
738fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
739230189d9SNélio Laranjeiro 	/* Start processing. */
740230189d9SNélio Laranjeiro 	txq_complete(txq);
741230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
742230189d9SNélio Laranjeiro 	if (max > elts_n)
743230189d9SNélio Laranjeiro 		max -= elts_n;
744c3d62cc9SAdrien Mazarguil 	do {
745a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
746c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
747230189d9SNélio Laranjeiro 		uint32_t length;
748a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
749230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
750230189d9SNélio Laranjeiro 
751c3d62cc9SAdrien Mazarguil 		/*
752c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
753c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
754c3d62cc9SAdrien Mazarguil 		 */
755a5bf6af9SAdrien Mazarguil 		assert(segs_n);
756a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
757c3d62cc9SAdrien Mazarguil 			break;
758a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
759a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
760a5bf6af9SAdrien Mazarguil 			break;
761a5bf6af9SAdrien Mazarguil 		max -= segs_n;
762c3d62cc9SAdrien Mazarguil 		--pkts_n;
763230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
764230189d9SNélio Laranjeiro 		if (buf->ol_flags &
765230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
766230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
767a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
768a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
769a5bf6af9SAdrien Mazarguil 		assert(length);
770230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
771230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
772230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
773a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
7748688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
775230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
776230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
777230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
7788688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
779230189d9SNélio Laranjeiro 		}
780a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
781a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
782a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
783a5bf6af9SAdrien Mazarguil 		length = 0;
784a5bf6af9SAdrien Mazarguil #endif
785a5bf6af9SAdrien Mazarguil 		do {
786a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
787a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
788a5bf6af9SAdrien Mazarguil 
789a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
790a5bf6af9SAdrien Mazarguil 			assert(buf);
791a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
792230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
793a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
794230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
795a5bf6af9SAdrien Mazarguil 				.byte_count = htonl(DATA_LEN(buf)),
796230189d9SNélio Laranjeiro 				.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
797230189d9SNélio Laranjeiro 				.addr = htonll(addr),
798230189d9SNélio Laranjeiro 			};
799a5bf6af9SAdrien Mazarguil 			elts_head = elts_head_next;
800a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
801a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
802a5bf6af9SAdrien Mazarguil #endif
803a5bf6af9SAdrien Mazarguil 			buf = buf->next;
804230189d9SNélio Laranjeiro 			++mpw.pkts_n;
805a5bf6af9SAdrien Mazarguil 			++j;
806a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
807a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
808230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
809230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
810230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
811230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
812230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
813230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
814230189d9SNélio Laranjeiro #endif
815c3d62cc9SAdrien Mazarguil 		++i;
816c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
817230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
818230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
819230189d9SNélio Laranjeiro 		return 0;
820230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
821a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
822a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
823230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
8248688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
825230189d9SNélio Laranjeiro 
826230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
8278688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
828230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
8298688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
830230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
831230189d9SNélio Laranjeiro 	} else {
832230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
833230189d9SNélio Laranjeiro 	}
834230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
835230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
836230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
837230189d9SNélio Laranjeiro #endif
838230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
839230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
840230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
841230189d9SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
842230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
843230189d9SNélio Laranjeiro 	return i;
844230189d9SNélio Laranjeiro }
845230189d9SNélio Laranjeiro 
846230189d9SNélio Laranjeiro /**
847230189d9SNélio Laranjeiro  * Open a MPW inline session.
848230189d9SNélio Laranjeiro  *
849230189d9SNélio Laranjeiro  * @param txq
850230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
851230189d9SNélio Laranjeiro  * @param mpw
852230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
853230189d9SNélio Laranjeiro  * @param length
854230189d9SNélio Laranjeiro  *   Packet length.
855230189d9SNélio Laranjeiro  */
856230189d9SNélio Laranjeiro static inline void
857230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
858230189d9SNélio Laranjeiro {
859a821d09dSNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1);
8608688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
861230189d9SNélio Laranjeiro 
862230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
863230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
864230189d9SNélio Laranjeiro 	mpw->len = length;
865230189d9SNélio Laranjeiro 	mpw->total_len = 0;
866fdcb0f53SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx);
8678688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
868230189d9SNélio Laranjeiro 				  (txq->wqe_ci << 8) |
869c904ae25SNélio Laranjeiro 				  MLX5_OPCODE_TSO);
8708688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
8718688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
8728688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
8738688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
8748688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
8758688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
8768688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
8778688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
8788688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
8798688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
8808688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
881230189d9SNélio Laranjeiro }
882230189d9SNélio Laranjeiro 
883230189d9SNélio Laranjeiro /**
884230189d9SNélio Laranjeiro  * Close a MPW inline session.
885230189d9SNélio Laranjeiro  *
886230189d9SNélio Laranjeiro  * @param txq
887230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
888230189d9SNélio Laranjeiro  * @param mpw
889230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
890230189d9SNélio Laranjeiro  */
891230189d9SNélio Laranjeiro static inline void
892230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
893230189d9SNélio Laranjeiro {
894230189d9SNélio Laranjeiro 	unsigned int size;
8958688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
8968688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
897230189d9SNélio Laranjeiro 
8988688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
899230189d9SNélio Laranjeiro 	/*
900230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
901230189d9SNélio Laranjeiro 	 * count as 2.
902230189d9SNélio Laranjeiro 	 */
9038688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size));
904230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
9058688b2f8SNélio Laranjeiro 	inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG);
9068688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
907230189d9SNélio Laranjeiro }
908230189d9SNélio Laranjeiro 
909230189d9SNélio Laranjeiro /**
910230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
911230189d9SNélio Laranjeiro  *
912230189d9SNélio Laranjeiro  * @param dpdk_txq
913230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
914230189d9SNélio Laranjeiro  * @param[in] pkts
915230189d9SNélio Laranjeiro  *   Packets to transmit.
916230189d9SNélio Laranjeiro  * @param pkts_n
917230189d9SNélio Laranjeiro  *   Number of packets in array.
918230189d9SNélio Laranjeiro  *
919230189d9SNélio Laranjeiro  * @return
920230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
921230189d9SNélio Laranjeiro  */
922230189d9SNélio Laranjeiro uint16_t
923230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
924230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
925230189d9SNélio Laranjeiro {
926230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
927230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
928b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
929c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
930a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
931230189d9SNélio Laranjeiro 	unsigned int max;
932230189d9SNélio Laranjeiro 	unsigned int comp;
9330e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
934230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
935230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
936230189d9SNélio Laranjeiro 	};
937230189d9SNélio Laranjeiro 
938c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
939c3d62cc9SAdrien Mazarguil 		return 0;
940230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
941230189d9SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
942fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci));
943fdcb0f53SNélio Laranjeiro 	rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1));
944230189d9SNélio Laranjeiro 	/* Start processing. */
945230189d9SNélio Laranjeiro 	txq_complete(txq);
946230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
947230189d9SNélio Laranjeiro 	if (max > elts_n)
948230189d9SNélio Laranjeiro 		max -= elts_n;
949c3d62cc9SAdrien Mazarguil 	do {
950a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
951c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
952230189d9SNélio Laranjeiro 		uintptr_t addr;
953230189d9SNélio Laranjeiro 		uint32_t length;
954a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
955230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
956230189d9SNélio Laranjeiro 
957c3d62cc9SAdrien Mazarguil 		/*
958c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
959c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
960c3d62cc9SAdrien Mazarguil 		 */
961a5bf6af9SAdrien Mazarguil 		assert(segs_n);
962a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
963c3d62cc9SAdrien Mazarguil 			break;
964a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
965a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
966a5bf6af9SAdrien Mazarguil 			break;
967a5bf6af9SAdrien Mazarguil 		max -= segs_n;
968c3d62cc9SAdrien Mazarguil 		--pkts_n;
969230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
970230189d9SNélio Laranjeiro 		if (buf->ol_flags &
971230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
972230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
973a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
974a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
975230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
976230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
977230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
978a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
9798688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
980230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
981230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
982230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
983a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
984230189d9SNélio Laranjeiro 			    (length > inline_room) ||
9858688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
986230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
9870e8679fcSNélio Laranjeiro 				inline_room =
9880e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
989230189d9SNélio Laranjeiro 			}
990230189d9SNélio Laranjeiro 		}
991230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
992a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
993a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
994230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
9958688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
996230189d9SNélio Laranjeiro 			} else {
997230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
9988688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
999230189d9SNélio Laranjeiro 			}
1000230189d9SNélio Laranjeiro 		}
1001a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
1002a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
1003230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
10040e8679fcSNélio Laranjeiro 			assert(inline_room ==
10050e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
1006a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1007a5bf6af9SAdrien Mazarguil 			length = 0;
1008a5bf6af9SAdrien Mazarguil #endif
1009a5bf6af9SAdrien Mazarguil 			do {
1010230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
1011230189d9SNélio Laranjeiro 
1012a5bf6af9SAdrien Mazarguil 				elts_head_next =
1013a5bf6af9SAdrien Mazarguil 					(elts_head + 1) & (elts_n - 1);
1014a5bf6af9SAdrien Mazarguil 				assert(buf);
1015a5bf6af9SAdrien Mazarguil 				(*txq->elts)[elts_head] = buf;
1016230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
1017a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
1018230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
1019a5bf6af9SAdrien Mazarguil 					.byte_count = htonl(DATA_LEN(buf)),
1020230189d9SNélio Laranjeiro 					.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
1021230189d9SNélio Laranjeiro 					.addr = htonll(addr),
1022230189d9SNélio Laranjeiro 				};
1023a5bf6af9SAdrien Mazarguil 				elts_head = elts_head_next;
1024a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
1025a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
1026a5bf6af9SAdrien Mazarguil #endif
1027a5bf6af9SAdrien Mazarguil 				buf = buf->next;
1028230189d9SNélio Laranjeiro 				++mpw.pkts_n;
1029a5bf6af9SAdrien Mazarguil 				++j;
1030a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
1031a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
1032230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
1033230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
1034230189d9SNélio Laranjeiro 		} else {
1035230189d9SNélio Laranjeiro 			unsigned int max;
1036230189d9SNélio Laranjeiro 
1037230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
1038230189d9SNélio Laranjeiro 			assert(length <= inline_room);
1039a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
1040a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
1041a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1042a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
1043230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1044fdcb0f53SNélio Laranjeiro 			max = ((((uintptr_t)(txq->wqes)) +
1045fdcb0f53SNélio Laranjeiro 				(1 << txq->wqe_n) *
1046fdcb0f53SNélio Laranjeiro 				MLX5_WQE_SIZE) -
1047230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1048230189d9SNélio Laranjeiro 			if (length > max) {
1049230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1050230189d9SNélio Laranjeiro 					   (void *)addr,
1051230189d9SNélio Laranjeiro 					   max);
1052fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1053230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1054230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1055230189d9SNélio Laranjeiro 					   length - max);
1056230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1057230189d9SNélio Laranjeiro 			} else {
1058230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1059230189d9SNélio Laranjeiro 					   (void *)addr,
1060230189d9SNélio Laranjeiro 					   length);
1061230189d9SNélio Laranjeiro 				mpw.data.raw += length;
1062230189d9SNélio Laranjeiro 			}
1063230189d9SNélio Laranjeiro 			if ((uintptr_t)mpw.data.raw ==
1064fdcb0f53SNélio Laranjeiro 			    (uintptr_t)tx_mlx5_wqe(txq, 1 << txq->wqe_n))
1065fdcb0f53SNélio Laranjeiro 				mpw.data.raw = (volatile void *)txq->wqes;
1066230189d9SNélio Laranjeiro 			++mpw.pkts_n;
1067a5bf6af9SAdrien Mazarguil 			++j;
1068230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1069230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
10700e8679fcSNélio Laranjeiro 				inline_room =
10710e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1072230189d9SNélio Laranjeiro 			} else {
1073230189d9SNélio Laranjeiro 				inline_room -= length;
1074230189d9SNélio Laranjeiro 			}
1075230189d9SNélio Laranjeiro 		}
1076230189d9SNélio Laranjeiro 		mpw.total_len += length;
1077230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
1078230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1079230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1080230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1081230189d9SNélio Laranjeiro #endif
1082c3d62cc9SAdrien Mazarguil 		++i;
1083c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1084230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1085230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1086230189d9SNélio Laranjeiro 		return 0;
1087230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1088a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1089a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1090230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
10918688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1092230189d9SNélio Laranjeiro 
1093230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
10948688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1095230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
10968688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1097230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1098230189d9SNélio Laranjeiro 	} else {
1099230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1100230189d9SNélio Laranjeiro 	}
1101230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1102230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1103230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1104230189d9SNélio Laranjeiro #endif
1105230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1106230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1107230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1108230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1109230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
1110230189d9SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
1111230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1112230189d9SNélio Laranjeiro 	return i;
1113230189d9SNélio Laranjeiro }
1114230189d9SNélio Laranjeiro 
1115230189d9SNélio Laranjeiro /**
111667fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
111767fa62bcSAdrien Mazarguil  *
11186218063bSNélio Laranjeiro  * @param[in] cqe
11196218063bSNélio Laranjeiro  *   Pointer to CQE.
112067fa62bcSAdrien Mazarguil  *
112178a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
112278a38edfSJianfeng Tan  *
112367fa62bcSAdrien Mazarguil  * @return
112467fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
112567fa62bcSAdrien Mazarguil  */
112667fa62bcSAdrien Mazarguil static inline uint32_t
112797267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe)
112867fa62bcSAdrien Mazarguil {
112967fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
11306218063bSNélio Laranjeiro 	uint8_t flags = cqe->l4_hdr_type_etc;
113167fa62bcSAdrien Mazarguil 
113297267b8eSNelio Laranjeiro 	if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET)
113367fa62bcSAdrien Mazarguil 		pkt_type =
113467fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1135350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_OUTER_IPV4_PACKET,
113667fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
113767fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1138350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_OUTER_IPV6_PACKET,
113967fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6) |
114067fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1141350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV4_PACKET,
114267fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV4) |
114367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
1144350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_IPV6_PACKET,
114567fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV6);
114667fa62bcSAdrien Mazarguil 	else
114767fa62bcSAdrien Mazarguil 		pkt_type =
114867fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
11496218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV6,
11506218063bSNélio Laranjeiro 				  RTE_PTYPE_L3_IPV6) |
115167fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
11526218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV4,
11536218063bSNélio Laranjeiro 				  RTE_PTYPE_L3_IPV4);
115467fa62bcSAdrien Mazarguil 	return pkt_type;
115567fa62bcSAdrien Mazarguil }
115667fa62bcSAdrien Mazarguil 
115767fa62bcSAdrien Mazarguil /**
115899c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
115999c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
116099c12dccSNélio Laranjeiro  * been processed.
116199c12dccSNélio Laranjeiro  *
116299c12dccSNélio Laranjeiro  * @param rxq
116399c12dccSNélio Laranjeiro  *   Pointer to RX queue.
116499c12dccSNélio Laranjeiro  * @param cqe
116599c12dccSNélio Laranjeiro  *   CQE to process.
1166ecf60761SNélio Laranjeiro  * @param[out] rss_hash
1167ecf60761SNélio Laranjeiro  *   Packet RSS Hash result.
116899c12dccSNélio Laranjeiro  *
116999c12dccSNélio Laranjeiro  * @return
117099c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
117199c12dccSNélio Laranjeiro  *   with error.
117299c12dccSNélio Laranjeiro  */
117399c12dccSNélio Laranjeiro static inline int
117497267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe,
1175ecf60761SNélio Laranjeiro 		 uint16_t cqe_cnt, uint32_t *rss_hash)
117699c12dccSNélio Laranjeiro {
117799c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
117899c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
117999c12dccSNélio Laranjeiro 	int len = 0;
118099c12dccSNélio Laranjeiro 
118199c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
118299c12dccSNélio Laranjeiro 	if (zip->ai) {
118399c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
118499c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
118597267b8eSNelio Laranjeiro 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt]);
118699c12dccSNélio Laranjeiro 
118799c12dccSNélio Laranjeiro 		len = ntohl((*mc)[zip->ai & 7].byte_cnt);
1188ecf60761SNélio Laranjeiro 		*rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result);
118999c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
119099c12dccSNélio Laranjeiro 			/*
119199c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
119299c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
119399c12dccSNélio Laranjeiro 			 * ring for software use.
119499c12dccSNélio Laranjeiro 			 */
119599c12dccSNélio Laranjeiro 			zip->ca = zip->na;
119699c12dccSNélio Laranjeiro 			zip->na += 8;
119799c12dccSNélio Laranjeiro 		}
119899c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
1199b5750af6SNélio Laranjeiro 			uint16_t idx = rxq->cq_ci + 1;
120099c12dccSNélio Laranjeiro 			uint16_t end = zip->cq_ci;
120199c12dccSNélio Laranjeiro 
120299c12dccSNélio Laranjeiro 			while (idx != end) {
120397267b8eSNelio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].op_own =
120499c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
120599c12dccSNélio Laranjeiro 				++idx;
120699c12dccSNélio Laranjeiro 			}
120799c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
120899c12dccSNélio Laranjeiro 			zip->ai = 0;
120999c12dccSNélio Laranjeiro 		}
121099c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
121199c12dccSNélio Laranjeiro 	} else {
121299c12dccSNélio Laranjeiro 		int ret;
121399c12dccSNélio Laranjeiro 		int8_t op_own;
121499c12dccSNélio Laranjeiro 
121597267b8eSNelio Laranjeiro 		ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
121699c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
121799c12dccSNélio Laranjeiro 			return 0;
121899c12dccSNélio Laranjeiro 		++rxq->cq_ci;
121999c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
122099c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
122199c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
122299c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
122399c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
122497267b8eSNelio Laranjeiro 							  cqe_cnt]);
122599c12dccSNélio Laranjeiro 
122699c12dccSNélio Laranjeiro 			/* Fix endianness. */
122799c12dccSNélio Laranjeiro 			zip->cqe_cnt = ntohl(cqe->byte_cnt);
122899c12dccSNélio Laranjeiro 			/*
122999c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
123099c12dccSNélio Laranjeiro 			 * check_cqe64().
123199c12dccSNélio Laranjeiro 			 *
123299c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
123399c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
123499c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
123599c12dccSNélio Laranjeiro 			 */
123699c12dccSNélio Laranjeiro 			zip->ca = rxq->cq_ci & cqe_cnt;
123799c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
123899c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
123999c12dccSNélio Laranjeiro 			--rxq->cq_ci;
124099c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
124199c12dccSNélio Laranjeiro 			/* Get packet size to return. */
124299c12dccSNélio Laranjeiro 			len = ntohl((*mc)[0].byte_cnt);
1243ecf60761SNélio Laranjeiro 			*rss_hash = ntohl((*mc)[0].rx_hash_result);
124499c12dccSNélio Laranjeiro 			zip->ai = 1;
124599c12dccSNélio Laranjeiro 		} else {
124699c12dccSNélio Laranjeiro 			len = ntohl(cqe->byte_cnt);
1247ecf60761SNélio Laranjeiro 			*rss_hash = ntohl(cqe->rx_hash_res);
124899c12dccSNélio Laranjeiro 		}
124999c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
125099c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
125199c12dccSNélio Laranjeiro 			return -1;
125299c12dccSNélio Laranjeiro 	}
125399c12dccSNélio Laranjeiro 	return len;
125499c12dccSNélio Laranjeiro }
125599c12dccSNélio Laranjeiro 
125699c12dccSNélio Laranjeiro /**
125767fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
125867fa62bcSAdrien Mazarguil  *
125967fa62bcSAdrien Mazarguil  * @param[in] rxq
126067fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
12616218063bSNélio Laranjeiro  * @param[in] cqe
12626218063bSNélio Laranjeiro  *   Pointer to CQE.
126367fa62bcSAdrien Mazarguil  *
126467fa62bcSAdrien Mazarguil  * @return
126567fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
126667fa62bcSAdrien Mazarguil  */
126767fa62bcSAdrien Mazarguil static inline uint32_t
126897267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe)
126967fa62bcSAdrien Mazarguil {
127067fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
12716218063bSNélio Laranjeiro 	uint8_t l3_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L3_HDR_TYPE_MASK;
12726218063bSNélio Laranjeiro 	uint8_t l4_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L4_HDR_TYPE_MASK;
127367fa62bcSAdrien Mazarguil 
12746218063bSNélio Laranjeiro 	if ((l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV4) ||
12756218063bSNélio Laranjeiro 	    (l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV6))
127683e9d9a3SNelio Laranjeiro 		ol_flags |= TRANSPOSE(cqe->hds_ip_ext,
127783e9d9a3SNelio Laranjeiro 				      MLX5_CQE_L3_OK,
127883e9d9a3SNelio Laranjeiro 				      PKT_RX_IP_CKSUM_GOOD);
12796218063bSNélio Laranjeiro 	if ((l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP) ||
12806218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_EMP_ACK) ||
12816218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_ACK) ||
12826218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_UDP))
128383e9d9a3SNelio Laranjeiro 		ol_flags |= TRANSPOSE(cqe->hds_ip_ext,
128483e9d9a3SNelio Laranjeiro 				      MLX5_CQE_L4_OK,
128583e9d9a3SNelio Laranjeiro 				      PKT_RX_L4_CKSUM_GOOD);
128697267b8eSNelio Laranjeiro 	if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
128767fa62bcSAdrien Mazarguil 		ol_flags |=
128883e9d9a3SNelio Laranjeiro 			TRANSPOSE(cqe->l4_hdr_type_etc,
1289350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_OUTER_IP_CSUM_OK,
129083e9d9a3SNelio Laranjeiro 				  PKT_RX_IP_CKSUM_GOOD) |
129183e9d9a3SNelio Laranjeiro 			TRANSPOSE(cqe->l4_hdr_type_etc,
1292350f4c48SNelio Laranjeiro 				  MLX5_CQE_RX_OUTER_TCP_UDP_CSUM_OK,
129383e9d9a3SNelio Laranjeiro 				  PKT_RX_L4_CKSUM_GOOD);
129467fa62bcSAdrien Mazarguil 	return ol_flags;
129567fa62bcSAdrien Mazarguil }
129667fa62bcSAdrien Mazarguil 
129767fa62bcSAdrien Mazarguil /**
12982e22920bSAdrien Mazarguil  * DPDK callback for RX.
12992e22920bSAdrien Mazarguil  *
13002e22920bSAdrien Mazarguil  * @param dpdk_rxq
13012e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
13022e22920bSAdrien Mazarguil  * @param[out] pkts
13032e22920bSAdrien Mazarguil  *   Array to store received packets.
13042e22920bSAdrien Mazarguil  * @param pkts_n
13052e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
13062e22920bSAdrien Mazarguil  *
13072e22920bSAdrien Mazarguil  * @return
13082e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
13092e22920bSAdrien Mazarguil  */
13102e22920bSAdrien Mazarguil uint16_t
13112e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
13122e22920bSAdrien Mazarguil {
13136218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
1314b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1315e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
13169964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
13179964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
13189964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
131997267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
132097267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
13219964b965SNélio Laranjeiro 	unsigned int i = 0;
13229964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
1323ecf60761SNélio Laranjeiro 	int len; /* keep its value across iterations. */
13242e22920bSAdrien Mazarguil 
13259964b965SNélio Laranjeiro 	while (pkts_n) {
13269964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
13279964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
13289964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
1329ecf60761SNélio Laranjeiro 		uint32_t rss_hash_res = 0;
13309964b965SNélio Laranjeiro 
13319964b965SNélio Laranjeiro 		if (pkt)
13329964b965SNélio Laranjeiro 			NEXT(seg) = rep;
13339964b965SNélio Laranjeiro 		seg = rep;
13349964b965SNélio Laranjeiro 		rte_prefetch0(seg);
13356218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
13369964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1337fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
13382e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
133915a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
134015a756b6SSagi Grimberg 			if (!pkt) {
134115a756b6SSagi Grimberg 				/*
134215a756b6SSagi Grimberg 				 * no buffers before we even started,
134315a756b6SSagi Grimberg 				 * bail out silently.
134415a756b6SSagi Grimberg 				 */
134515a756b6SSagi Grimberg 				break;
134615a756b6SSagi Grimberg 			}
1347a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1348a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1349fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
13509964b965SNélio Laranjeiro 				rte_mbuf_refcnt_set(pkt, 0);
13519964b965SNélio Laranjeiro 				__rte_mbuf_raw_free(pkt);
1352fe5fe382SNélio Laranjeiro 				pkt = rep;
13539964b965SNélio Laranjeiro 			}
13546218063bSNélio Laranjeiro 			break;
13552e22920bSAdrien Mazarguil 		}
13569964b965SNélio Laranjeiro 		if (!pkt) {
135797267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
1358ecf60761SNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt,
1359ecf60761SNélio Laranjeiro 					       &rss_hash_res);
1360ecf60761SNélio Laranjeiro 			if (!len) {
13616218063bSNélio Laranjeiro 				rte_mbuf_refcnt_set(rep, 0);
13626218063bSNélio Laranjeiro 				__rte_mbuf_raw_free(rep);
13636218063bSNélio Laranjeiro 				break;
13646218063bSNélio Laranjeiro 			}
136599c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
136699c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
136799c12dccSNélio Laranjeiro 				rte_mbuf_refcnt_set(rep, 0);
136899c12dccSNélio Laranjeiro 				__rte_mbuf_raw_free(rep);
136999c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
137099c12dccSNélio Laranjeiro 				goto skip;
137199c12dccSNélio Laranjeiro 			}
13729964b965SNélio Laranjeiro 			pkt = seg;
13739964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
13749964b965SNélio Laranjeiro 			/* Update packet information. */
13750ac64846SMaxime Leroy 			pkt->packet_type = 0;
13760ac64846SMaxime Leroy 			pkt->ol_flags = 0;
137736ba0c00SNélio Laranjeiro 			if (rss_hash_res && rxq->rss_hash) {
1378ecf60761SNélio Laranjeiro 				pkt->hash.rss = rss_hash_res;
1379ecf60761SNélio Laranjeiro 				pkt->ol_flags = PKT_RX_RSS_HASH;
1380ecf60761SNélio Laranjeiro 			}
1381ea3bc3b1SNélio Laranjeiro 			if (rxq->mark &&
1382ea3bc3b1SNélio Laranjeiro 			    ((cqe->sop_drop_qpn !=
1383ea3bc3b1SNélio Laranjeiro 			      htonl(MLX5_FLOW_MARK_INVALID)) ||
1384ea3bc3b1SNélio Laranjeiro 			     (cqe->sop_drop_qpn !=
1385ea3bc3b1SNélio Laranjeiro 			      htonl(MLX5_FLOW_MARK_DEFAULT)))) {
1386ea3bc3b1SNélio Laranjeiro 				pkt->hash.fdir.hi =
1387ea3bc3b1SNélio Laranjeiro 					mlx5_flow_mark_get(cqe->sop_drop_qpn);
1388ea3bc3b1SNélio Laranjeiro 				pkt->ol_flags &= ~PKT_RX_RSS_HASH;
1389ea3bc3b1SNélio Laranjeiro 				pkt->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID;
1390ea3bc3b1SNélio Laranjeiro 			}
13916218063bSNélio Laranjeiro 			if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip |
13926218063bSNélio Laranjeiro 			    rxq->crc_present) {
13936218063bSNélio Laranjeiro 				if (rxq->csum) {
13949964b965SNélio Laranjeiro 					pkt->packet_type =
13959964b965SNélio Laranjeiro 						rxq_cq_to_pkt_type(cqe);
1396ecf60761SNélio Laranjeiro 					pkt->ol_flags |=
13979964b965SNélio Laranjeiro 						rxq_cq_to_ol_flags(rxq, cqe);
13986218063bSNélio Laranjeiro 				}
13999964b965SNélio Laranjeiro 				if (cqe->l4_hdr_type_etc &
14009964b965SNélio Laranjeiro 				    MLX5_CQE_VLAN_STRIPPED) {
14016218063bSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_VLAN_PKT |
1402b37b528dSOlivier Matz 						PKT_RX_VLAN_STRIPPED;
14036218063bSNélio Laranjeiro 					pkt->vlan_tci = ntohs(cqe->vlan_info);
1404f3db9489SYaacov Hazan 				}
14056218063bSNélio Laranjeiro 				if (rxq->crc_present)
14066218063bSNélio Laranjeiro 					len -= ETHER_CRC_LEN;
1407081f7eaeSNelio Laranjeiro 			}
14086218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
14099964b965SNélio Laranjeiro 		}
14109964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
14119964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
14129964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
14139964b965SNélio Laranjeiro 		NB_SEGS(rep) = NB_SEGS(seg);
14149964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
14159964b965SNélio Laranjeiro 		NEXT(rep) = NULL;
14169964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
14179964b965SNélio Laranjeiro 		/*
14189964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
14199964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
14209964b965SNélio Laranjeiro 		 * changes.
14219964b965SNélio Laranjeiro 		 */
14229964b965SNélio Laranjeiro 		wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
14239964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
14249964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
14259964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
14269964b965SNélio Laranjeiro 			++rq_ci;
14279964b965SNélio Laranjeiro 			continue;
14289964b965SNélio Laranjeiro 		}
14299964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
143087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
143187011737SAdrien Mazarguil 		/* Increment bytes counter. */
14329964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
143387011737SAdrien Mazarguil #endif
14346218063bSNélio Laranjeiro 		/* Return packet. */
14356218063bSNélio Laranjeiro 		*(pkts++) = pkt;
14369964b965SNélio Laranjeiro 		pkt = NULL;
14379964b965SNélio Laranjeiro 		--pkts_n;
14389964b965SNélio Laranjeiro 		++i;
143999c12dccSNélio Laranjeiro skip:
14409964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
14419964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
14426218063bSNélio Laranjeiro 		++rq_ci;
14439964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
14442e22920bSAdrien Mazarguil 	}
14459964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
14462e22920bSAdrien Mazarguil 		return 0;
14476218063bSNélio Laranjeiro 	/* Update the consumer index. */
14489964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
14496218063bSNélio Laranjeiro 	rte_wmb();
14506218063bSNélio Laranjeiro 	*rxq->cq_db = htonl(rxq->cq_ci);
14516218063bSNélio Laranjeiro 	rte_wmb();
14526218063bSNélio Laranjeiro 	*rxq->rq_db = htonl(rxq->rq_ci);
145387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
145487011737SAdrien Mazarguil 	/* Increment packets counter. */
14559964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
145687011737SAdrien Mazarguil #endif
14579964b965SNélio Laranjeiro 	return i;
14582e22920bSAdrien Mazarguil }
14592e22920bSAdrien Mazarguil 
14602e22920bSAdrien Mazarguil /**
14612e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
14622e22920bSAdrien Mazarguil  *
14632e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14642e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14652e22920bSAdrien Mazarguil  *
14662e22920bSAdrien Mazarguil  * @param dpdk_txq
14672e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
14682e22920bSAdrien Mazarguil  * @param[in] pkts
14692e22920bSAdrien Mazarguil  *   Packets to transmit.
14702e22920bSAdrien Mazarguil  * @param pkts_n
14712e22920bSAdrien Mazarguil  *   Number of packets in array.
14722e22920bSAdrien Mazarguil  *
14732e22920bSAdrien Mazarguil  * @return
14742e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
14752e22920bSAdrien Mazarguil  */
14762e22920bSAdrien Mazarguil uint16_t
14772e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
14782e22920bSAdrien Mazarguil {
14792e22920bSAdrien Mazarguil 	(void)dpdk_txq;
14802e22920bSAdrien Mazarguil 	(void)pkts;
14812e22920bSAdrien Mazarguil 	(void)pkts_n;
14822e22920bSAdrien Mazarguil 	return 0;
14832e22920bSAdrien Mazarguil }
14842e22920bSAdrien Mazarguil 
14852e22920bSAdrien Mazarguil /**
14862e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
14872e22920bSAdrien Mazarguil  *
14882e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14892e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14902e22920bSAdrien Mazarguil  *
14912e22920bSAdrien Mazarguil  * @param dpdk_rxq
14922e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
14932e22920bSAdrien Mazarguil  * @param[out] pkts
14942e22920bSAdrien Mazarguil  *   Array to store received packets.
14952e22920bSAdrien Mazarguil  * @param pkts_n
14962e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
14972e22920bSAdrien Mazarguil  *
14982e22920bSAdrien Mazarguil  * @return
14992e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
15002e22920bSAdrien Mazarguil  */
15012e22920bSAdrien Mazarguil uint16_t
15022e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
15032e22920bSAdrien Mazarguil {
15042e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
15052e22920bSAdrien Mazarguil 	(void)pkts;
15062e22920bSAdrien Mazarguil 	(void)pkts_n;
15072e22920bSAdrien Mazarguil 	return 0;
15082e22920bSAdrien Mazarguil }
1509