xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision b4b12e55a041168a1fb12d68ebdaa5fd37f4b135)
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 
7299c12dccSNélio Laranjeiro #ifndef NDEBUG
7399c12dccSNélio Laranjeiro 
7499c12dccSNélio Laranjeiro /**
7599c12dccSNélio Laranjeiro  * Verify or set magic value in CQE.
7699c12dccSNélio Laranjeiro  *
7799c12dccSNélio Laranjeiro  * @param cqe
7899c12dccSNélio Laranjeiro  *   Pointer to CQE.
7999c12dccSNélio Laranjeiro  *
8099c12dccSNélio Laranjeiro  * @return
8199c12dccSNélio Laranjeiro  *   0 the first time.
8299c12dccSNélio Laranjeiro  */
8399c12dccSNélio Laranjeiro static inline int
8499c12dccSNélio Laranjeiro check_cqe64_seen(volatile struct mlx5_cqe64 *cqe)
8599c12dccSNélio Laranjeiro {
8699c12dccSNélio Laranjeiro 	static const uint8_t magic[] = "seen";
8799c12dccSNélio Laranjeiro 	volatile uint8_t (*buf)[sizeof(cqe->rsvd40)] = &cqe->rsvd40;
8899c12dccSNélio Laranjeiro 	int ret = 1;
8999c12dccSNélio Laranjeiro 	unsigned int i;
9099c12dccSNélio Laranjeiro 
9199c12dccSNélio Laranjeiro 	for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i)
9299c12dccSNélio Laranjeiro 		if (!ret || (*buf)[i] != magic[i]) {
9399c12dccSNélio Laranjeiro 			ret = 0;
9499c12dccSNélio Laranjeiro 			(*buf)[i] = magic[i];
9599c12dccSNélio Laranjeiro 		}
9699c12dccSNélio Laranjeiro 	return ret;
9799c12dccSNélio Laranjeiro }
9899c12dccSNélio Laranjeiro 
9999c12dccSNélio Laranjeiro #endif /* NDEBUG */
1006218063bSNélio Laranjeiro 
1016218063bSNélio Laranjeiro static inline int
10299c12dccSNélio Laranjeiro check_cqe64(volatile struct mlx5_cqe64 *cqe,
10399c12dccSNélio Laranjeiro 	    unsigned int cqes_n, const uint16_t ci)
10499c12dccSNélio Laranjeiro 	    __attribute__((always_inline));
1056218063bSNélio Laranjeiro 
10699c12dccSNélio Laranjeiro /**
10799c12dccSNélio Laranjeiro  * Check whether CQE is valid.
10899c12dccSNélio Laranjeiro  *
10999c12dccSNélio Laranjeiro  * @param cqe
11099c12dccSNélio Laranjeiro  *   Pointer to CQE.
11199c12dccSNélio Laranjeiro  * @param cqes_n
11299c12dccSNélio Laranjeiro  *   Size of completion queue.
11399c12dccSNélio Laranjeiro  * @param ci
11499c12dccSNélio Laranjeiro  *   Consumer index.
11599c12dccSNélio Laranjeiro  *
11699c12dccSNélio Laranjeiro  * @return
11799c12dccSNélio Laranjeiro  *   0 on success, 1 on failure.
11899c12dccSNélio Laranjeiro  */
11999c12dccSNélio Laranjeiro static inline int
12099c12dccSNélio Laranjeiro check_cqe64(volatile struct mlx5_cqe64 *cqe,
12199c12dccSNélio Laranjeiro 		unsigned int cqes_n, const uint16_t ci)
1226218063bSNélio Laranjeiro {
12399c12dccSNélio Laranjeiro 	uint16_t idx = ci & cqes_n;
12499c12dccSNélio Laranjeiro 	uint8_t op_own = cqe->op_own;
12599c12dccSNélio Laranjeiro 	uint8_t op_owner = MLX5_CQE_OWNER(op_own);
12699c12dccSNélio Laranjeiro 	uint8_t op_code = MLX5_CQE_OPCODE(op_own);
1276218063bSNélio Laranjeiro 
12899c12dccSNélio Laranjeiro 	if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID)))
12999c12dccSNélio Laranjeiro 		return 1; /* No CQE. */
13099c12dccSNélio Laranjeiro #ifndef NDEBUG
13199c12dccSNélio Laranjeiro 	if ((op_code == MLX5_CQE_RESP_ERR) ||
13299c12dccSNélio Laranjeiro 	    (op_code == MLX5_CQE_REQ_ERR)) {
13399c12dccSNélio Laranjeiro 		volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe;
13499c12dccSNélio Laranjeiro 		uint8_t syndrome = err_cqe->syndrome;
13599c12dccSNélio Laranjeiro 
13699c12dccSNélio Laranjeiro 		if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) ||
13799c12dccSNélio Laranjeiro 		    (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR))
13899c12dccSNélio Laranjeiro 			return 0;
13999c12dccSNélio Laranjeiro 		if (!check_cqe64_seen(cqe))
14099c12dccSNélio Laranjeiro 			ERROR("unexpected CQE error %u (0x%02x)"
14199c12dccSNélio Laranjeiro 			      " syndrome 0x%02x",
14299c12dccSNélio Laranjeiro 			      op_code, op_code, syndrome);
14399c12dccSNélio Laranjeiro 		return 1;
14499c12dccSNélio Laranjeiro 	} else if ((op_code != MLX5_CQE_RESP_SEND) &&
14599c12dccSNélio Laranjeiro 		   (op_code != MLX5_CQE_REQ)) {
14699c12dccSNélio Laranjeiro 		if (!check_cqe64_seen(cqe))
14799c12dccSNélio Laranjeiro 			ERROR("unexpected CQE opcode %u (0x%02x)",
14899c12dccSNélio Laranjeiro 			      op_code, op_code);
14999c12dccSNélio Laranjeiro 		return 1;
1506218063bSNélio Laranjeiro 	}
15199c12dccSNélio Laranjeiro #endif /* NDEBUG */
15299c12dccSNélio Laranjeiro 	return 0;
1536218063bSNélio Laranjeiro }
1542e22920bSAdrien Mazarguil 
155a6ca35aaSNélio Laranjeiro static inline void
156a6ca35aaSNélio Laranjeiro txq_complete(struct txq *txq) __attribute__((always_inline));
157a6ca35aaSNélio Laranjeiro 
1582e22920bSAdrien Mazarguil /**
1592e22920bSAdrien Mazarguil  * Manage TX completions.
1602e22920bSAdrien Mazarguil  *
1612e22920bSAdrien Mazarguil  * When sending a burst, mlx5_tx_burst() posts several WRs.
1622e22920bSAdrien Mazarguil  *
1632e22920bSAdrien Mazarguil  * @param txq
1642e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
1652e22920bSAdrien Mazarguil  */
166a6ca35aaSNélio Laranjeiro static inline void
1672e22920bSAdrien Mazarguil txq_complete(struct txq *txq)
1682e22920bSAdrien Mazarguil {
1691d88ba17SNélio Laranjeiro 	const unsigned int cqe_n = txq->cqe_n;
170*b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
17199c12dccSNélio Laranjeiro 	const unsigned int cqe_cnt = cqe_n - 1;
1721d88ba17SNélio Laranjeiro 	uint16_t elts_free = txq->elts_tail;
1731d88ba17SNélio Laranjeiro 	uint16_t elts_tail;
1741d88ba17SNélio Laranjeiro 	uint16_t cq_ci = txq->cq_ci;
175c305090bSAdrien Mazarguil 	volatile struct mlx5_cqe64 *cqe = NULL;
1768688b2f8SNélio Laranjeiro 	volatile struct mlx5_wqe *wqe;
1772e22920bSAdrien Mazarguil 
17899c12dccSNélio Laranjeiro 	do {
179c305090bSAdrien Mazarguil 		volatile struct mlx5_cqe64 *tmp;
1801d88ba17SNélio Laranjeiro 
181c305090bSAdrien Mazarguil 		tmp = &(*txq->cqes)[cq_ci & cqe_cnt].cqe64;
182c305090bSAdrien Mazarguil 		if (check_cqe64(tmp, cqe_n, cq_ci))
1831d88ba17SNélio Laranjeiro 			break;
184c305090bSAdrien Mazarguil 		cqe = tmp;
18599c12dccSNélio Laranjeiro #ifndef NDEBUG
18699c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) {
18799c12dccSNélio Laranjeiro 			if (!check_cqe64_seen(cqe))
18899c12dccSNélio Laranjeiro 				ERROR("unexpected compressed CQE, TX stopped");
18999c12dccSNélio Laranjeiro 			return;
1902e22920bSAdrien Mazarguil 		}
19199c12dccSNélio Laranjeiro 		if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) ||
19299c12dccSNélio Laranjeiro 		    (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) {
19399c12dccSNélio Laranjeiro 			if (!check_cqe64_seen(cqe))
19499c12dccSNélio Laranjeiro 				ERROR("unexpected error CQE, TX stopped");
19599c12dccSNélio Laranjeiro 			return;
19699c12dccSNélio Laranjeiro 		}
19799c12dccSNélio Laranjeiro #endif /* NDEBUG */
19899c12dccSNélio Laranjeiro 		++cq_ci;
19999c12dccSNélio Laranjeiro 	} while (1);
200c305090bSAdrien Mazarguil 	if (unlikely(cqe == NULL))
2011d88ba17SNélio Laranjeiro 		return;
2028688b2f8SNélio Laranjeiro 	wqe = &(*txq->wqes)[htons(cqe->wqe_counter) & (txq->wqe_n - 1)].hdr;
2038688b2f8SNélio Laranjeiro 	elts_tail = wqe->ctrl[3];
204c305090bSAdrien Mazarguil 	assert(elts_tail < txq->wqe_n);
2051d88ba17SNélio Laranjeiro 	/* Free buffers. */
206c305090bSAdrien Mazarguil 	while (elts_free != elts_tail) {
2071d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt = (*txq->elts)[elts_free];
208a859e8a9SNelio Laranjeiro 		unsigned int elts_free_next =
2091d88ba17SNélio Laranjeiro 			(elts_free + 1) & (elts_n - 1);
2101d88ba17SNélio Laranjeiro 		struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next];
211a859e8a9SNelio Laranjeiro 
212b185e63fSAdrien Mazarguil #ifndef NDEBUG
213b185e63fSAdrien Mazarguil 		/* Poisoning. */
2141d88ba17SNélio Laranjeiro 		memset(&(*txq->elts)[elts_free],
2151d88ba17SNélio Laranjeiro 		       0x66,
2161d88ba17SNélio Laranjeiro 		       sizeof((*txq->elts)[elts_free]));
217b185e63fSAdrien Mazarguil #endif
2181d88ba17SNélio Laranjeiro 		RTE_MBUF_PREFETCH_TO_FREE(elt_next);
2191d88ba17SNélio Laranjeiro 		/* Only one segment needs to be freed. */
2201d88ba17SNélio Laranjeiro 		rte_pktmbuf_free_seg(elt);
221a859e8a9SNelio Laranjeiro 		elts_free = elts_free_next;
222c305090bSAdrien Mazarguil 	}
2231d88ba17SNélio Laranjeiro 	txq->cq_ci = cq_ci;
2242e22920bSAdrien Mazarguil 	txq->elts_tail = elts_tail;
2251d88ba17SNélio Laranjeiro 	/* Update the consumer index. */
2261d88ba17SNélio Laranjeiro 	rte_wmb();
2271d88ba17SNélio Laranjeiro 	*txq->cq_db = htonl(cq_ci);
2282e22920bSAdrien Mazarguil }
2292e22920bSAdrien Mazarguil 
2302e22920bSAdrien Mazarguil /**
2318340392eSAdrien Mazarguil  * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
2328340392eSAdrien Mazarguil  * the cloned mbuf is allocated is returned instead.
2338340392eSAdrien Mazarguil  *
2348340392eSAdrien Mazarguil  * @param buf
2358340392eSAdrien Mazarguil  *   Pointer to mbuf.
2368340392eSAdrien Mazarguil  *
2378340392eSAdrien Mazarguil  * @return
2388340392eSAdrien Mazarguil  *   Memory pool where data is located for given mbuf.
2398340392eSAdrien Mazarguil  */
2408340392eSAdrien Mazarguil static struct rte_mempool *
2418340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf)
2428340392eSAdrien Mazarguil {
2438340392eSAdrien Mazarguil 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
2448340392eSAdrien Mazarguil 		return rte_mbuf_from_indirect(buf)->pool;
2458340392eSAdrien Mazarguil 	return buf->pool;
2468340392eSAdrien Mazarguil }
2478340392eSAdrien Mazarguil 
248491770faSNélio Laranjeiro static inline uint32_t
249491770faSNélio Laranjeiro txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
250491770faSNélio Laranjeiro 	__attribute__((always_inline));
251491770faSNélio Laranjeiro 
2528340392eSAdrien Mazarguil /**
2532e22920bSAdrien Mazarguil  * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[].
2542e22920bSAdrien Mazarguil  * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
2552e22920bSAdrien Mazarguil  * remove an entry first.
2562e22920bSAdrien Mazarguil  *
2572e22920bSAdrien Mazarguil  * @param txq
2582e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
2592e22920bSAdrien Mazarguil  * @param[in] mp
2602e22920bSAdrien Mazarguil  *   Memory Pool for which a Memory Region lkey must be returned.
2612e22920bSAdrien Mazarguil  *
2622e22920bSAdrien Mazarguil  * @return
2632e22920bSAdrien Mazarguil  *   mr->lkey on success, (uint32_t)-1 on failure.
2642e22920bSAdrien Mazarguil  */
265491770faSNélio Laranjeiro static inline uint32_t
266d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
2672e22920bSAdrien Mazarguil {
2682e22920bSAdrien Mazarguil 	unsigned int i;
269491770faSNélio Laranjeiro 	uint32_t lkey = (uint32_t)-1;
2702e22920bSAdrien Mazarguil 
2712e22920bSAdrien Mazarguil 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
2722e22920bSAdrien Mazarguil 		if (unlikely(txq->mp2mr[i].mp == NULL)) {
2732e22920bSAdrien Mazarguil 			/* Unknown MP, add a new MR for it. */
2742e22920bSAdrien Mazarguil 			break;
2752e22920bSAdrien Mazarguil 		}
2762e22920bSAdrien Mazarguil 		if (txq->mp2mr[i].mp == mp) {
2772e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].lkey != (uint32_t)-1);
2781d88ba17SNélio Laranjeiro 			assert(htonl(txq->mp2mr[i].mr->lkey) ==
2791d88ba17SNélio Laranjeiro 			       txq->mp2mr[i].lkey);
280491770faSNélio Laranjeiro 			lkey = txq->mp2mr[i].lkey;
281491770faSNélio Laranjeiro 			break;
2822e22920bSAdrien Mazarguil 		}
2832e22920bSAdrien Mazarguil 	}
284491770faSNélio Laranjeiro 	if (unlikely(lkey == (uint32_t)-1))
285491770faSNélio Laranjeiro 		lkey = txq_mp2mr_reg(txq, mp, i);
286491770faSNélio Laranjeiro 	return lkey;
2870a3b350dSOlga Shern }
2880a3b350dSOlga Shern 
289e192ef80SYaacov Hazan /**
2901d88ba17SNélio Laranjeiro  * Write a regular WQE.
291e192ef80SYaacov Hazan  *
2921d88ba17SNélio Laranjeiro  * @param txq
2931d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
2941d88ba17SNélio Laranjeiro  * @param wqe
2951d88ba17SNélio Laranjeiro  *   Pointer to the WQE to fill.
296d772d440SNélio Laranjeiro  * @param buf
297d772d440SNélio Laranjeiro  *   Buffer.
2981d88ba17SNélio Laranjeiro  * @param length
2991d88ba17SNélio Laranjeiro  *   Packet length.
3000e8679fcSNélio Laranjeiro  *
3010e8679fcSNélio Laranjeiro  * @return ds
3020e8679fcSNélio Laranjeiro  *   Number of DS elements consumed.
303e192ef80SYaacov Hazan  */
3040e8679fcSNélio Laranjeiro static inline unsigned int
3058688b2f8SNélio Laranjeiro mlx5_wqe_write(struct txq *txq, volatile struct mlx5_wqe *wqe,
3060e8679fcSNélio Laranjeiro 	       struct rte_mbuf *buf, uint32_t length)
307e192ef80SYaacov Hazan {
3088688b2f8SNélio Laranjeiro 	uint8_t *raw = (uint8_t *)(uintptr_t)&wqe->eseg.inline_hdr[0];
3090e8679fcSNélio Laranjeiro 	uint16_t ds;
3108688b2f8SNélio Laranjeiro 	uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE;
311d772d440SNélio Laranjeiro 	uintptr_t addr = rte_pktmbuf_mtod(buf, uintptr_t);
3120e8679fcSNélio Laranjeiro 	struct mlx5_wqe_data_seg *dseg = NULL;
313e192ef80SYaacov Hazan 
3148688b2f8SNélio Laranjeiro 	assert(length >= MLX5_WQE_DWORD_SIZE);
3150e8679fcSNélio Laranjeiro 	/* Start the know and common part of the WQE structure. */
3168688b2f8SNélio Laranjeiro 	wqe->ctrl[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND);
3178688b2f8SNélio Laranjeiro 	wqe->ctrl[2] = 0;
3188688b2f8SNélio Laranjeiro 	wqe->ctrl[3] = 0;
3198688b2f8SNélio Laranjeiro 	wqe->eseg.rsvd0 = 0;
3208688b2f8SNélio Laranjeiro 	wqe->eseg.rsvd1 = 0;
3218688b2f8SNélio Laranjeiro 	wqe->eseg.mss = 0;
3228688b2f8SNélio Laranjeiro 	wqe->eseg.rsvd2 = 0;
3230e8679fcSNélio Laranjeiro 	/* Start by copying the Ethernet Header. */
3240e8679fcSNélio Laranjeiro 	rte_mov16((uint8_t *)raw, (uint8_t *)addr);
3258688b2f8SNélio Laranjeiro 	length -= MLX5_WQE_DWORD_SIZE;
3268688b2f8SNélio Laranjeiro 	addr += MLX5_WQE_DWORD_SIZE;
3270e8679fcSNélio Laranjeiro 	/* Replace the Ethernet type by the VLAN if necessary. */
328d772d440SNélio Laranjeiro 	if (buf->ol_flags & PKT_TX_VLAN_PKT) {
329d772d440SNélio Laranjeiro 		uint32_t vlan = htonl(0x81000000 | buf->vlan_tci);
330e192ef80SYaacov Hazan 
3318688b2f8SNélio Laranjeiro 		memcpy((uint8_t *)(raw + MLX5_WQE_DWORD_SIZE - sizeof(vlan)),
3321d88ba17SNélio Laranjeiro 		       &vlan, sizeof(vlan));
333d772d440SNélio Laranjeiro 		addr -= sizeof(vlan);
334d772d440SNélio Laranjeiro 		length += sizeof(vlan);
335d772d440SNélio Laranjeiro 	}
3360e8679fcSNélio Laranjeiro 	/* Inline if enough room. */
3370e8679fcSNélio Laranjeiro 	if (txq->max_inline != 0) {
3380e8679fcSNélio Laranjeiro 		uintptr_t end = (uintptr_t)&(*txq->wqes)[txq->wqe_n];
3390e8679fcSNélio Laranjeiro 		uint16_t max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE;
3400e8679fcSNélio Laranjeiro 		uint16_t room;
3410e8679fcSNélio Laranjeiro 
3428688b2f8SNélio Laranjeiro 		raw += MLX5_WQE_DWORD_SIZE;
3430e8679fcSNélio Laranjeiro 		room = end - (uintptr_t)raw;
3440e8679fcSNélio Laranjeiro 		if (room > max_inline) {
3450e8679fcSNélio Laranjeiro 			uintptr_t addr_end = (addr + max_inline) &
3460e8679fcSNélio Laranjeiro 				~(RTE_CACHE_LINE_SIZE - 1);
3470e8679fcSNélio Laranjeiro 			uint16_t copy_b = ((addr_end - addr) > length) ?
3480e8679fcSNélio Laranjeiro 					  length :
3490e8679fcSNélio Laranjeiro 					  (addr_end - addr);
3500e8679fcSNélio Laranjeiro 
3510e8679fcSNélio Laranjeiro 			rte_memcpy((void *)raw, (void *)addr, copy_b);
3520e8679fcSNélio Laranjeiro 			addr += copy_b;
3530e8679fcSNélio Laranjeiro 			length -= copy_b;
3540e8679fcSNélio Laranjeiro 			pkt_inline_sz += copy_b;
3550e8679fcSNélio Laranjeiro 			/* Sanity check. */
3560e8679fcSNélio Laranjeiro 			assert(addr <= addr_end);
3571d88ba17SNélio Laranjeiro 		}
3580e8679fcSNélio Laranjeiro 		/* Store the inlined packet size in the WQE. */
3598688b2f8SNélio Laranjeiro 		wqe->eseg.inline_hdr_sz = htons(pkt_inline_sz);
3602a66cf37SYaacov Hazan 		/*
3610e8679fcSNélio Laranjeiro 		 * 2 DWORDs consumed by the WQE header + 1 DSEG +
3620e8679fcSNélio Laranjeiro 		 * the size of the inline part of the packet.
3632a66cf37SYaacov Hazan 		 */
3648688b2f8SNélio Laranjeiro 		ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2);
3650e8679fcSNélio Laranjeiro 		if (length > 0) {
3660e8679fcSNélio Laranjeiro 			dseg = (struct mlx5_wqe_data_seg *)
3678688b2f8SNélio Laranjeiro 				((uintptr_t)wqe + (ds * MLX5_WQE_DWORD_SIZE));
3680e8679fcSNélio Laranjeiro 			if ((uintptr_t)dseg >= end)
3690e8679fcSNélio Laranjeiro 				dseg = (struct mlx5_wqe_data_seg *)
3700e8679fcSNélio Laranjeiro 					((uintptr_t)&(*txq->wqes)[0]);
3710e8679fcSNélio Laranjeiro 			goto use_dseg;
3722a66cf37SYaacov Hazan 		}
3730e8679fcSNélio Laranjeiro 	} else {
3740e8679fcSNélio Laranjeiro 		/* Add the remaining packet as a simple ds. */
3750e8679fcSNélio Laranjeiro 		ds = 3;
3760e8679fcSNélio Laranjeiro 		/*
3770e8679fcSNélio Laranjeiro 		 * No inline has been done in the packet, only the Ethernet
3780e8679fcSNélio Laranjeiro 		 * Header as been stored.
3790e8679fcSNélio Laranjeiro 		 */
3808688b2f8SNélio Laranjeiro 		wqe->eseg.inline_hdr_sz = htons(MLX5_WQE_DWORD_SIZE);
3810e8679fcSNélio Laranjeiro 		dseg = (struct mlx5_wqe_data_seg *)
3828688b2f8SNélio Laranjeiro 			((uintptr_t)wqe + (ds * MLX5_WQE_DWORD_SIZE));
3830e8679fcSNélio Laranjeiro use_dseg:
3840e8679fcSNélio Laranjeiro 		*dseg = (struct mlx5_wqe_data_seg) {
3850e8679fcSNélio Laranjeiro 			.addr = htonll(addr),
3860e8679fcSNélio Laranjeiro 			.byte_count = htonl(length),
3870e8679fcSNélio Laranjeiro 			.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
3880e8679fcSNélio Laranjeiro 		};
3890e8679fcSNélio Laranjeiro 		++ds;
3900e8679fcSNélio Laranjeiro 	}
3918688b2f8SNélio Laranjeiro 	wqe->ctrl[1] = htonl(txq->qp_num_8s | ds);
3920e8679fcSNélio Laranjeiro 	return ds;
3932a66cf37SYaacov Hazan }
3942a66cf37SYaacov Hazan 
3952a66cf37SYaacov Hazan /**
3961d88ba17SNélio Laranjeiro  * Ring TX queue doorbell.
3971d88ba17SNélio Laranjeiro  *
3981d88ba17SNélio Laranjeiro  * @param txq
3991d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
4001d88ba17SNélio Laranjeiro  */
4011d88ba17SNélio Laranjeiro static inline void
4021d88ba17SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq)
4031d88ba17SNélio Laranjeiro {
4041d88ba17SNélio Laranjeiro 	uint8_t *dst = (uint8_t *)((uintptr_t)txq->bf_reg + txq->bf_offset);
4051d88ba17SNélio Laranjeiro 	uint32_t data[4] = {
4061d88ba17SNélio Laranjeiro 		htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND),
4071d88ba17SNélio Laranjeiro 		htonl(txq->qp_num_8s),
4081d88ba17SNélio Laranjeiro 		0,
4091d88ba17SNélio Laranjeiro 		0,
4101d88ba17SNélio Laranjeiro 	};
4111d88ba17SNélio Laranjeiro 	rte_wmb();
4121d88ba17SNélio Laranjeiro 	*txq->qp_db = htonl(txq->wqe_ci);
4131d88ba17SNélio Laranjeiro 	/* Ensure ordering between DB record and BF copy. */
4141d88ba17SNélio Laranjeiro 	rte_wmb();
4151d88ba17SNélio Laranjeiro 	rte_mov16(dst, (uint8_t *)data);
4161d88ba17SNélio Laranjeiro 	txq->bf_offset ^= txq->bf_buf_size;
4171d88ba17SNélio Laranjeiro }
418e192ef80SYaacov Hazan 
4191d88ba17SNélio Laranjeiro /**
4201d88ba17SNélio Laranjeiro  * Prefetch a CQE.
4211d88ba17SNélio Laranjeiro  *
4221d88ba17SNélio Laranjeiro  * @param txq
4231d88ba17SNélio Laranjeiro  *   Pointer to TX queue structure.
4241d88ba17SNélio Laranjeiro  * @param cqe_ci
4251d88ba17SNélio Laranjeiro  *   CQE consumer index.
4261d88ba17SNélio Laranjeiro  */
4271d88ba17SNélio Laranjeiro static inline void
4281d88ba17SNélio Laranjeiro tx_prefetch_cqe(struct txq *txq, uint16_t ci)
4291d88ba17SNélio Laranjeiro {
4301d88ba17SNélio Laranjeiro 	volatile struct mlx5_cqe64 *cqe;
4311d88ba17SNélio Laranjeiro 
4321d88ba17SNélio Laranjeiro 	cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64;
4331d88ba17SNélio Laranjeiro 	rte_prefetch0(cqe);
434e192ef80SYaacov Hazan }
435e192ef80SYaacov Hazan 
4362e22920bSAdrien Mazarguil /**
4372a66cf37SYaacov Hazan  * Prefetch a WQE.
4382a66cf37SYaacov Hazan  *
4392a66cf37SYaacov Hazan  * @param txq
4402a66cf37SYaacov Hazan  *   Pointer to TX queue structure.
4412a66cf37SYaacov Hazan  * @param  wqe_ci
4422a66cf37SYaacov Hazan  *   WQE consumer index.
4432a66cf37SYaacov Hazan  */
4442a66cf37SYaacov Hazan static inline void
4452a66cf37SYaacov Hazan tx_prefetch_wqe(struct txq *txq, uint16_t ci)
4462a66cf37SYaacov Hazan {
4478688b2f8SNélio Laranjeiro 	volatile struct mlx5_wqe64 *wqe;
4482a66cf37SYaacov Hazan 
4492a66cf37SYaacov Hazan 	wqe = &(*txq->wqes)[ci & (txq->wqe_n - 1)];
4502a66cf37SYaacov Hazan 	rte_prefetch0(wqe);
4512a66cf37SYaacov Hazan }
4522a66cf37SYaacov Hazan 
4532a66cf37SYaacov Hazan /**
4542e22920bSAdrien Mazarguil  * DPDK callback for TX.
4552e22920bSAdrien Mazarguil  *
4562e22920bSAdrien Mazarguil  * @param dpdk_txq
4572e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
4582e22920bSAdrien Mazarguil  * @param[in] pkts
4592e22920bSAdrien Mazarguil  *   Packets to transmit.
4602e22920bSAdrien Mazarguil  * @param pkts_n
4612e22920bSAdrien Mazarguil  *   Number of packets in array.
4622e22920bSAdrien Mazarguil  *
4632e22920bSAdrien Mazarguil  * @return
4642e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
4652e22920bSAdrien Mazarguil  */
4662e22920bSAdrien Mazarguil uint16_t
4672e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
4682e22920bSAdrien Mazarguil {
4692e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
4701d88ba17SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
471*b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
472c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
473a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
4742e22920bSAdrien Mazarguil 	unsigned int max;
475c305090bSAdrien Mazarguil 	unsigned int comp;
4768688b2f8SNélio Laranjeiro 	volatile struct mlx5_wqe *wqe = NULL;
4772e22920bSAdrien Mazarguil 
4781d88ba17SNélio Laranjeiro 	if (unlikely(!pkts_n))
4791d88ba17SNélio Laranjeiro 		return 0;
4805e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
4811d88ba17SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
4821d88ba17SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci + 1);
483c3d62cc9SAdrien Mazarguil 	rte_prefetch0(*pkts);
4841d88ba17SNélio Laranjeiro 	/* Start processing. */
4852e22920bSAdrien Mazarguil 	txq_complete(txq);
4864f52bbfbSNelio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
4872e22920bSAdrien Mazarguil 	if (max > elts_n)
4882e22920bSAdrien Mazarguil 		max -= elts_n;
489c3d62cc9SAdrien Mazarguil 	do {
490a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
491c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
492573f54afSNélio Laranjeiro 		uint32_t length;
493a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
494a5bf6af9SAdrien Mazarguil 		volatile struct mlx5_wqe_data_seg *dseg;
4958688b2f8SNélio Laranjeiro 		unsigned int ds = 0;
4962e22920bSAdrien Mazarguil 
497c3d62cc9SAdrien Mazarguil 		/*
498c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
499c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
500c3d62cc9SAdrien Mazarguil 		 */
501a5bf6af9SAdrien Mazarguil 		assert(segs_n);
502a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
503c3d62cc9SAdrien Mazarguil 			break;
504a5bf6af9SAdrien Mazarguil 		max -= segs_n;
505c3d62cc9SAdrien Mazarguil 		--pkts_n;
506c3d62cc9SAdrien Mazarguil 		elts_head_next = (elts_head + 1) & (elts_n - 1);
5078688b2f8SNélio Laranjeiro 		wqe = &(*txq->wqes)[txq->wqe_ci & (txq->wqe_n - 1)].hdr;
5080e8679fcSNélio Laranjeiro 		tx_prefetch_wqe(txq, txq->wqe_ci);
5090e8679fcSNélio Laranjeiro 		tx_prefetch_wqe(txq, txq->wqe_ci + 1);
510c3d62cc9SAdrien Mazarguil 		if (pkts_n)
511c3d62cc9SAdrien Mazarguil 			rte_prefetch0(*pkts);
5122e22920bSAdrien Mazarguil 		length = DATA_LEN(buf);
5132e22920bSAdrien Mazarguil 		/* Update element. */
5141d88ba17SNélio Laranjeiro 		(*txq->elts)[elts_head] = buf;
5155e1d11ecSNelio Laranjeiro 		/* Prefetch next buffer data. */
516c3d62cc9SAdrien Mazarguil 		if (pkts_n)
517c3d62cc9SAdrien Mazarguil 			rte_prefetch0(rte_pktmbuf_mtod(*pkts,
5181d88ba17SNélio Laranjeiro 						       volatile void *));
5191d88ba17SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
5201d88ba17SNélio Laranjeiro 		if (buf->ol_flags &
5211d88ba17SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
5228688b2f8SNélio Laranjeiro 			wqe->eseg.cs_flags =
5231d88ba17SNélio Laranjeiro 				MLX5_ETH_WQE_L3_CSUM |
5241d88ba17SNélio Laranjeiro 				MLX5_ETH_WQE_L4_CSUM;
5251d88ba17SNélio Laranjeiro 		} else {
5268688b2f8SNélio Laranjeiro 			wqe->eseg.cs_flags = 0;
5271d88ba17SNélio Laranjeiro 		}
5280e8679fcSNélio Laranjeiro 		ds = mlx5_wqe_write(txq, wqe, buf, length);
5290e8679fcSNélio Laranjeiro 		if (segs_n == 1)
5300e8679fcSNélio Laranjeiro 			goto skip_segs;
5310e8679fcSNélio Laranjeiro 		dseg = (volatile struct mlx5_wqe_data_seg *)
5328688b2f8SNélio Laranjeiro 			(((uintptr_t)wqe) + ds * MLX5_WQE_DWORD_SIZE);
533a5bf6af9SAdrien Mazarguil 		while (--segs_n) {
534a5bf6af9SAdrien Mazarguil 			/*
535a5bf6af9SAdrien Mazarguil 			 * Spill on next WQE when the current one does not have
536a5bf6af9SAdrien Mazarguil 			 * enough room left. Size of WQE must a be a multiple
537a5bf6af9SAdrien Mazarguil 			 * of data segment size.
538a5bf6af9SAdrien Mazarguil 			 */
5398688b2f8SNélio Laranjeiro 			assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE));
5408688b2f8SNélio Laranjeiro 			if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE)))
541a5bf6af9SAdrien Mazarguil 				dseg = (volatile void *)
542a5bf6af9SAdrien Mazarguil 					&(*txq->wqes)[txq->wqe_ci++ &
543a5bf6af9SAdrien Mazarguil 						      (txq->wqe_n - 1)];
544a5bf6af9SAdrien Mazarguil 			else
545a5bf6af9SAdrien Mazarguil 				++dseg;
546a5bf6af9SAdrien Mazarguil 			++ds;
547a5bf6af9SAdrien Mazarguil 			buf = buf->next;
548a5bf6af9SAdrien Mazarguil 			assert(buf);
549a5bf6af9SAdrien Mazarguil 			/* Store segment information. */
550a5bf6af9SAdrien Mazarguil 			dseg->byte_count = htonl(DATA_LEN(buf));
551a5bf6af9SAdrien Mazarguil 			dseg->lkey = txq_mp2mr(txq, txq_mb2mp(buf));
552a5bf6af9SAdrien Mazarguil 			dseg->addr = htonll(rte_pktmbuf_mtod(buf, uintptr_t));
553a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head_next] = buf;
554a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head_next + 1) & (elts_n - 1);
555a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
556a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
557a5bf6af9SAdrien Mazarguil #endif
558a5bf6af9SAdrien Mazarguil 			++j;
559a5bf6af9SAdrien Mazarguil 		}
560a5bf6af9SAdrien Mazarguil 		/* Update DS field in WQE. */
5618688b2f8SNélio Laranjeiro 		wqe->ctrl[1] &= htonl(0xffffffc0);
5628688b2f8SNélio Laranjeiro 		wqe->ctrl[1] |= htonl(ds & 0x3f);
5630e8679fcSNélio Laranjeiro skip_segs:
56487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
565573f54afSNélio Laranjeiro 		/* Increment sent bytes counter. */
566573f54afSNélio Laranjeiro 		txq->stats.obytes += length;
56787011737SAdrien Mazarguil #endif
5680e8679fcSNélio Laranjeiro 		/* Increment consumer index. */
5690e8679fcSNélio Laranjeiro 		txq->wqe_ci += (ds + 3) / 4;
5702e22920bSAdrien Mazarguil 		elts_head = elts_head_next;
571c3d62cc9SAdrien Mazarguil 		++i;
572c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
5732e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
5742e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
5752e22920bSAdrien Mazarguil 		return 0;
576c305090bSAdrien Mazarguil 	/* Check whether completion threshold has been reached. */
577a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + i + j;
578c305090bSAdrien Mazarguil 	if (comp >= MLX5_TX_COMP_THRESH) {
579c305090bSAdrien Mazarguil 		/* Request completion on last WQE. */
5808688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
581c305090bSAdrien Mazarguil 		/* Save elts_head in unused "immediate" field of WQE. */
5828688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
583c305090bSAdrien Mazarguil 		txq->elts_comp = 0;
584c305090bSAdrien Mazarguil 	} else {
585c305090bSAdrien Mazarguil 		txq->elts_comp = comp;
586c305090bSAdrien Mazarguil 	}
58787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
58887011737SAdrien Mazarguil 	/* Increment sent packets counter. */
58987011737SAdrien Mazarguil 	txq->stats.opackets += i;
59087011737SAdrien Mazarguil #endif
5912e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
5921d88ba17SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
5932e22920bSAdrien Mazarguil 	txq->elts_head = elts_head;
5942e22920bSAdrien Mazarguil 	return i;
5952e22920bSAdrien Mazarguil }
5962e22920bSAdrien Mazarguil 
5972e22920bSAdrien Mazarguil /**
598230189d9SNélio Laranjeiro  * Open a MPW session.
599230189d9SNélio Laranjeiro  *
600230189d9SNélio Laranjeiro  * @param txq
601230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
602230189d9SNélio Laranjeiro  * @param mpw
603230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
604230189d9SNélio Laranjeiro  * @param length
605230189d9SNélio Laranjeiro  *   Packet length.
606230189d9SNélio Laranjeiro  */
607230189d9SNélio Laranjeiro static inline void
608230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
609230189d9SNélio Laranjeiro {
610230189d9SNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1);
611230189d9SNélio Laranjeiro 	volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] =
612230189d9SNélio Laranjeiro 		(volatile struct mlx5_wqe_data_seg (*)[])
613230189d9SNélio Laranjeiro 		(uintptr_t)&(*txq->wqes)[(idx + 1) & (txq->wqe_n - 1)];
614230189d9SNélio Laranjeiro 
615230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_OPENED;
616230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
617230189d9SNélio Laranjeiro 	mpw->len = length;
618230189d9SNélio Laranjeiro 	mpw->total_len = 0;
6198688b2f8SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)&(*txq->wqes)[idx].hdr;
6208688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
6218688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
6228688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
6238688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
6248688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
6258688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
6268688b2f8SNélio Laranjeiro 				  (txq->wqe_ci << 8) | MLX5_OPCODE_LSO_MPW);
6278688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
6288688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
6298688b2f8SNélio Laranjeiro 	mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *)
6308688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
6318688b2f8SNélio Laranjeiro 	mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *)
6328688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE));
633230189d9SNélio Laranjeiro 	mpw->data.dseg[2] = &(*dseg)[0];
634230189d9SNélio Laranjeiro 	mpw->data.dseg[3] = &(*dseg)[1];
635230189d9SNélio Laranjeiro 	mpw->data.dseg[4] = &(*dseg)[2];
636230189d9SNélio Laranjeiro }
637230189d9SNélio Laranjeiro 
638230189d9SNélio Laranjeiro /**
639230189d9SNélio Laranjeiro  * Close 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  */
646230189d9SNélio Laranjeiro static inline void
647230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw)
648230189d9SNélio Laranjeiro {
649230189d9SNélio Laranjeiro 	unsigned int num = mpw->pkts_n;
650230189d9SNélio Laranjeiro 
651230189d9SNélio Laranjeiro 	/*
652230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
653230189d9SNélio Laranjeiro 	 * count as 2.
654230189d9SNélio Laranjeiro 	 */
6558688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num));
656230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
657230189d9SNélio Laranjeiro 	if (num < 3)
658230189d9SNélio Laranjeiro 		++txq->wqe_ci;
659230189d9SNélio Laranjeiro 	else
660230189d9SNélio Laranjeiro 		txq->wqe_ci += 2;
661230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci);
662230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci + 1);
663230189d9SNélio Laranjeiro }
664230189d9SNélio Laranjeiro 
665230189d9SNélio Laranjeiro /**
666230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW support.
667230189d9SNélio Laranjeiro  *
668230189d9SNélio Laranjeiro  * @param dpdk_txq
669230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
670230189d9SNélio Laranjeiro  * @param[in] pkts
671230189d9SNélio Laranjeiro  *   Packets to transmit.
672230189d9SNélio Laranjeiro  * @param pkts_n
673230189d9SNélio Laranjeiro  *   Number of packets in array.
674230189d9SNélio Laranjeiro  *
675230189d9SNélio Laranjeiro  * @return
676230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
677230189d9SNélio Laranjeiro  */
678230189d9SNélio Laranjeiro uint16_t
679230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
680230189d9SNélio Laranjeiro {
681230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
682230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
683*b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
684c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
685a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
686230189d9SNélio Laranjeiro 	unsigned int max;
687230189d9SNélio Laranjeiro 	unsigned int comp;
688230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
689230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
690230189d9SNélio Laranjeiro 	};
691230189d9SNélio Laranjeiro 
692c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
693c3d62cc9SAdrien Mazarguil 		return 0;
694230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
695230189d9SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
696230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci);
697230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci + 1);
698230189d9SNélio Laranjeiro 	/* Start processing. */
699230189d9SNélio Laranjeiro 	txq_complete(txq);
700230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
701230189d9SNélio Laranjeiro 	if (max > elts_n)
702230189d9SNélio Laranjeiro 		max -= elts_n;
703c3d62cc9SAdrien Mazarguil 	do {
704a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
705c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
706230189d9SNélio Laranjeiro 		uint32_t length;
707a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
708230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
709230189d9SNélio Laranjeiro 
710c3d62cc9SAdrien Mazarguil 		/*
711c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
712c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
713c3d62cc9SAdrien Mazarguil 		 */
714a5bf6af9SAdrien Mazarguil 		assert(segs_n);
715a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
716c3d62cc9SAdrien Mazarguil 			break;
717a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
718a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
719a5bf6af9SAdrien Mazarguil 			break;
720a5bf6af9SAdrien Mazarguil 		max -= segs_n;
721c3d62cc9SAdrien Mazarguil 		--pkts_n;
722230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
723230189d9SNélio Laranjeiro 		if (buf->ol_flags &
724230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
725230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
726a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
727a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
728a5bf6af9SAdrien Mazarguil 		assert(length);
729230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
730230189d9SNélio Laranjeiro 		if ((mpw.state == MLX5_MPW_STATE_OPENED) &&
731230189d9SNélio Laranjeiro 		    ((mpw.len != length) ||
732a5bf6af9SAdrien Mazarguil 		     (segs_n != 1) ||
7338688b2f8SNélio Laranjeiro 		     (mpw.wqe->eseg.cs_flags != cs_flags)))
734230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
735230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
736230189d9SNélio Laranjeiro 			mlx5_mpw_new(txq, &mpw, length);
7378688b2f8SNélio Laranjeiro 			mpw.wqe->eseg.cs_flags = cs_flags;
738230189d9SNélio Laranjeiro 		}
739a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
740a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
741a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
742a5bf6af9SAdrien Mazarguil 		length = 0;
743a5bf6af9SAdrien Mazarguil #endif
744a5bf6af9SAdrien Mazarguil 		do {
745a5bf6af9SAdrien Mazarguil 			volatile struct mlx5_wqe_data_seg *dseg;
746a5bf6af9SAdrien Mazarguil 			uintptr_t addr;
747a5bf6af9SAdrien Mazarguil 
748a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
749a5bf6af9SAdrien Mazarguil 			assert(buf);
750a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
751230189d9SNélio Laranjeiro 			dseg = mpw.data.dseg[mpw.pkts_n];
752a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
753230189d9SNélio Laranjeiro 			*dseg = (struct mlx5_wqe_data_seg){
754a5bf6af9SAdrien Mazarguil 				.byte_count = htonl(DATA_LEN(buf)),
755230189d9SNélio Laranjeiro 				.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
756230189d9SNélio Laranjeiro 				.addr = htonll(addr),
757230189d9SNélio Laranjeiro 			};
758a5bf6af9SAdrien Mazarguil 			elts_head = elts_head_next;
759a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
760a5bf6af9SAdrien Mazarguil 			length += DATA_LEN(buf);
761a5bf6af9SAdrien Mazarguil #endif
762a5bf6af9SAdrien Mazarguil 			buf = buf->next;
763230189d9SNélio Laranjeiro 			++mpw.pkts_n;
764a5bf6af9SAdrien Mazarguil 			++j;
765a5bf6af9SAdrien Mazarguil 		} while (--segs_n);
766a5bf6af9SAdrien Mazarguil 		assert(length == mpw.len);
767230189d9SNélio Laranjeiro 		if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
768230189d9SNélio Laranjeiro 			mlx5_mpw_close(txq, &mpw);
769230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
770230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
771230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
772230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
773230189d9SNélio Laranjeiro #endif
774c3d62cc9SAdrien Mazarguil 		++i;
775c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
776230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
777230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
778230189d9SNélio Laranjeiro 		return 0;
779230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
780a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
781a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
782230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
7838688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
784230189d9SNélio Laranjeiro 
785230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
7868688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
787230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
7888688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
789230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
790230189d9SNélio Laranjeiro 	} else {
791230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
792230189d9SNélio Laranjeiro 	}
793230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
794230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
795230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
796230189d9SNélio Laranjeiro #endif
797230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
798230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_STATE_OPENED)
799230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
800230189d9SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
801230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
802230189d9SNélio Laranjeiro 	return i;
803230189d9SNélio Laranjeiro }
804230189d9SNélio Laranjeiro 
805230189d9SNélio Laranjeiro /**
806230189d9SNélio Laranjeiro  * Open a MPW inline session.
807230189d9SNélio Laranjeiro  *
808230189d9SNélio Laranjeiro  * @param txq
809230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
810230189d9SNélio Laranjeiro  * @param mpw
811230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
812230189d9SNélio Laranjeiro  * @param length
813230189d9SNélio Laranjeiro  *   Packet length.
814230189d9SNélio Laranjeiro  */
815230189d9SNélio Laranjeiro static inline void
816230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length)
817230189d9SNélio Laranjeiro {
818230189d9SNélio Laranjeiro 	uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1);
8198688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl;
820230189d9SNélio Laranjeiro 
821230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_INL_STATE_OPENED;
822230189d9SNélio Laranjeiro 	mpw->pkts_n = 0;
823230189d9SNélio Laranjeiro 	mpw->len = length;
824230189d9SNélio Laranjeiro 	mpw->total_len = 0;
8258688b2f8SNélio Laranjeiro 	mpw->wqe = (volatile struct mlx5_wqe *)&(*txq->wqes)[idx].hdr;
8268688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) |
827230189d9SNélio Laranjeiro 				  (txq->wqe_ci << 8) |
828230189d9SNélio Laranjeiro 				  MLX5_OPCODE_LSO_MPW);
8298688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[2] = 0;
8308688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[3] = 0;
8318688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.mss = htons(length);
8328688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.inline_hdr_sz = 0;
8338688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.cs_flags = 0;
8348688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd0 = 0;
8358688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd1 = 0;
8368688b2f8SNélio Laranjeiro 	mpw->wqe->eseg.rsvd2 = 0;
8378688b2f8SNélio Laranjeiro 	inl = (struct mlx5_wqe_inl_small *)
8388688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE);
8398688b2f8SNélio Laranjeiro 	mpw->data.raw = (uint8_t *)&inl->raw;
840230189d9SNélio Laranjeiro }
841230189d9SNélio Laranjeiro 
842230189d9SNélio Laranjeiro /**
843230189d9SNélio Laranjeiro  * Close a MPW inline session.
844230189d9SNélio Laranjeiro  *
845230189d9SNélio Laranjeiro  * @param txq
846230189d9SNélio Laranjeiro  *   Pointer to TX queue structure.
847230189d9SNélio Laranjeiro  * @param mpw
848230189d9SNélio Laranjeiro  *   Pointer to MPW session structure.
849230189d9SNélio Laranjeiro  */
850230189d9SNélio Laranjeiro static inline void
851230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw)
852230189d9SNélio Laranjeiro {
853230189d9SNélio Laranjeiro 	unsigned int size;
8548688b2f8SNélio Laranjeiro 	struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *)
8558688b2f8SNélio Laranjeiro 		(((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE));
856230189d9SNélio Laranjeiro 
8578688b2f8SNélio Laranjeiro 	size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len;
858230189d9SNélio Laranjeiro 	/*
859230189d9SNélio Laranjeiro 	 * Store size in multiple of 16 bytes. Control and Ethernet segments
860230189d9SNélio Laranjeiro 	 * count as 2.
861230189d9SNélio Laranjeiro 	 */
8628688b2f8SNélio Laranjeiro 	mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size));
863230189d9SNélio Laranjeiro 	mpw->state = MLX5_MPW_STATE_CLOSED;
8648688b2f8SNélio Laranjeiro 	inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG);
8658688b2f8SNélio Laranjeiro 	txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE;
866230189d9SNélio Laranjeiro }
867230189d9SNélio Laranjeiro 
868230189d9SNélio Laranjeiro /**
869230189d9SNélio Laranjeiro  * DPDK callback for TX with MPW inline support.
870230189d9SNélio Laranjeiro  *
871230189d9SNélio Laranjeiro  * @param dpdk_txq
872230189d9SNélio Laranjeiro  *   Generic pointer to TX queue structure.
873230189d9SNélio Laranjeiro  * @param[in] pkts
874230189d9SNélio Laranjeiro  *   Packets to transmit.
875230189d9SNélio Laranjeiro  * @param pkts_n
876230189d9SNélio Laranjeiro  *   Number of packets in array.
877230189d9SNélio Laranjeiro  *
878230189d9SNélio Laranjeiro  * @return
879230189d9SNélio Laranjeiro  *   Number of packets successfully transmitted (<= pkts_n).
880230189d9SNélio Laranjeiro  */
881230189d9SNélio Laranjeiro uint16_t
882230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts,
883230189d9SNélio Laranjeiro 			 uint16_t pkts_n)
884230189d9SNélio Laranjeiro {
885230189d9SNélio Laranjeiro 	struct txq *txq = (struct txq *)dpdk_txq;
886230189d9SNélio Laranjeiro 	uint16_t elts_head = txq->elts_head;
887*b4b12e55SNélio Laranjeiro 	const unsigned int elts_n = 1 << txq->elts_n;
888c3d62cc9SAdrien Mazarguil 	unsigned int i = 0;
889a5bf6af9SAdrien Mazarguil 	unsigned int j = 0;
890230189d9SNélio Laranjeiro 	unsigned int max;
891230189d9SNélio Laranjeiro 	unsigned int comp;
8920e8679fcSNélio Laranjeiro 	unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE;
893230189d9SNélio Laranjeiro 	struct mlx5_mpw mpw = {
894230189d9SNélio Laranjeiro 		.state = MLX5_MPW_STATE_CLOSED,
895230189d9SNélio Laranjeiro 	};
896230189d9SNélio Laranjeiro 
897c3d62cc9SAdrien Mazarguil 	if (unlikely(!pkts_n))
898c3d62cc9SAdrien Mazarguil 		return 0;
899230189d9SNélio Laranjeiro 	/* Prefetch first packet cacheline. */
900230189d9SNélio Laranjeiro 	tx_prefetch_cqe(txq, txq->cq_ci);
901230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci);
902230189d9SNélio Laranjeiro 	tx_prefetch_wqe(txq, txq->wqe_ci + 1);
903230189d9SNélio Laranjeiro 	/* Start processing. */
904230189d9SNélio Laranjeiro 	txq_complete(txq);
905230189d9SNélio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
906230189d9SNélio Laranjeiro 	if (max > elts_n)
907230189d9SNélio Laranjeiro 		max -= elts_n;
908c3d62cc9SAdrien Mazarguil 	do {
909a5bf6af9SAdrien Mazarguil 		struct rte_mbuf *buf = *(pkts++);
910c3d62cc9SAdrien Mazarguil 		unsigned int elts_head_next;
911230189d9SNélio Laranjeiro 		uintptr_t addr;
912230189d9SNélio Laranjeiro 		uint32_t length;
913a5bf6af9SAdrien Mazarguil 		unsigned int segs_n = buf->nb_segs;
914230189d9SNélio Laranjeiro 		uint32_t cs_flags = 0;
915230189d9SNélio Laranjeiro 
916c3d62cc9SAdrien Mazarguil 		/*
917c3d62cc9SAdrien Mazarguil 		 * Make sure there is enough room to store this packet and
918c3d62cc9SAdrien Mazarguil 		 * that one ring entry remains unused.
919c3d62cc9SAdrien Mazarguil 		 */
920a5bf6af9SAdrien Mazarguil 		assert(segs_n);
921a5bf6af9SAdrien Mazarguil 		if (max < segs_n + 1)
922c3d62cc9SAdrien Mazarguil 			break;
923a5bf6af9SAdrien Mazarguil 		/* Do not bother with large packets MPW cannot handle. */
924a5bf6af9SAdrien Mazarguil 		if (segs_n > MLX5_MPW_DSEG_MAX)
925a5bf6af9SAdrien Mazarguil 			break;
926a5bf6af9SAdrien Mazarguil 		max -= segs_n;
927c3d62cc9SAdrien Mazarguil 		--pkts_n;
928230189d9SNélio Laranjeiro 		/* Should we enable HW CKSUM offload */
929230189d9SNélio Laranjeiro 		if (buf->ol_flags &
930230189d9SNélio Laranjeiro 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))
931230189d9SNélio Laranjeiro 			cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
932a5bf6af9SAdrien Mazarguil 		/* Retrieve packet information. */
933a5bf6af9SAdrien Mazarguil 		length = PKT_LEN(buf);
934230189d9SNélio Laranjeiro 		/* Start new session if packet differs. */
935230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
936230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
937a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
9388688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags))
939230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
940230189d9SNélio Laranjeiro 		} else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) {
941230189d9SNélio Laranjeiro 			if ((mpw.len != length) ||
942a5bf6af9SAdrien Mazarguil 			    (segs_n != 1) ||
943230189d9SNélio Laranjeiro 			    (length > inline_room) ||
9448688b2f8SNélio Laranjeiro 			    (mpw.wqe->eseg.cs_flags != cs_flags)) {
945230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
9460e8679fcSNélio Laranjeiro 				inline_room =
9470e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
948230189d9SNélio Laranjeiro 			}
949230189d9SNélio Laranjeiro 		}
950230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_CLOSED) {
951a5bf6af9SAdrien Mazarguil 			if ((segs_n != 1) ||
952a5bf6af9SAdrien Mazarguil 			    (length > inline_room)) {
953230189d9SNélio Laranjeiro 				mlx5_mpw_new(txq, &mpw, length);
9548688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
955230189d9SNélio Laranjeiro 			} else {
956230189d9SNélio Laranjeiro 				mlx5_mpw_inline_new(txq, &mpw, length);
9578688b2f8SNélio Laranjeiro 				mpw.wqe->eseg.cs_flags = cs_flags;
958230189d9SNélio Laranjeiro 			}
959230189d9SNélio Laranjeiro 		}
960a5bf6af9SAdrien Mazarguil 		/* Multi-segment packets must be alone in their MPW. */
961a5bf6af9SAdrien Mazarguil 		assert((segs_n == 1) || (mpw.pkts_n == 0));
962230189d9SNélio Laranjeiro 		if (mpw.state == MLX5_MPW_STATE_OPENED) {
9630e8679fcSNélio Laranjeiro 			assert(inline_room ==
9640e8679fcSNélio Laranjeiro 			       txq->max_inline * RTE_CACHE_LINE_SIZE);
965a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
966a5bf6af9SAdrien Mazarguil 			length = 0;
967a5bf6af9SAdrien Mazarguil #endif
968a5bf6af9SAdrien Mazarguil 			do {
969230189d9SNélio Laranjeiro 				volatile struct mlx5_wqe_data_seg *dseg;
970230189d9SNélio Laranjeiro 
971a5bf6af9SAdrien Mazarguil 				elts_head_next =
972a5bf6af9SAdrien Mazarguil 					(elts_head + 1) & (elts_n - 1);
973a5bf6af9SAdrien Mazarguil 				assert(buf);
974a5bf6af9SAdrien Mazarguil 				(*txq->elts)[elts_head] = buf;
975230189d9SNélio Laranjeiro 				dseg = mpw.data.dseg[mpw.pkts_n];
976a5bf6af9SAdrien Mazarguil 				addr = rte_pktmbuf_mtod(buf, uintptr_t);
977230189d9SNélio Laranjeiro 				*dseg = (struct mlx5_wqe_data_seg){
978a5bf6af9SAdrien Mazarguil 					.byte_count = htonl(DATA_LEN(buf)),
979230189d9SNélio Laranjeiro 					.lkey = txq_mp2mr(txq, txq_mb2mp(buf)),
980230189d9SNélio Laranjeiro 					.addr = htonll(addr),
981230189d9SNélio Laranjeiro 				};
982a5bf6af9SAdrien Mazarguil 				elts_head = elts_head_next;
983a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG)
984a5bf6af9SAdrien Mazarguil 				length += DATA_LEN(buf);
985a5bf6af9SAdrien Mazarguil #endif
986a5bf6af9SAdrien Mazarguil 				buf = buf->next;
987230189d9SNélio Laranjeiro 				++mpw.pkts_n;
988a5bf6af9SAdrien Mazarguil 				++j;
989a5bf6af9SAdrien Mazarguil 			} while (--segs_n);
990a5bf6af9SAdrien Mazarguil 			assert(length == mpw.len);
991230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX)
992230189d9SNélio Laranjeiro 				mlx5_mpw_close(txq, &mpw);
993230189d9SNélio Laranjeiro 		} else {
994230189d9SNélio Laranjeiro 			unsigned int max;
995230189d9SNélio Laranjeiro 
996230189d9SNélio Laranjeiro 			assert(mpw.state == MLX5_MPW_INL_STATE_OPENED);
997230189d9SNélio Laranjeiro 			assert(length <= inline_room);
998a5bf6af9SAdrien Mazarguil 			assert(length == DATA_LEN(buf));
999a5bf6af9SAdrien Mazarguil 			elts_head_next = (elts_head + 1) & (elts_n - 1);
1000a5bf6af9SAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
1001a5bf6af9SAdrien Mazarguil 			(*txq->elts)[elts_head] = buf;
1002230189d9SNélio Laranjeiro 			/* Maximum number of bytes before wrapping. */
1003230189d9SNélio Laranjeiro 			max = ((uintptr_t)&(*txq->wqes)[txq->wqe_n] -
1004230189d9SNélio Laranjeiro 			       (uintptr_t)mpw.data.raw);
1005230189d9SNélio Laranjeiro 			if (length > max) {
1006230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1007230189d9SNélio Laranjeiro 					   (void *)addr,
1008230189d9SNélio Laranjeiro 					   max);
1009230189d9SNélio Laranjeiro 				mpw.data.raw =
1010230189d9SNélio Laranjeiro 					(volatile void *)&(*txq->wqes)[0];
1011230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1012230189d9SNélio Laranjeiro 					   (void *)(addr + max),
1013230189d9SNélio Laranjeiro 					   length - max);
1014230189d9SNélio Laranjeiro 				mpw.data.raw += length - max;
1015230189d9SNélio Laranjeiro 			} else {
1016230189d9SNélio Laranjeiro 				rte_memcpy((void *)(uintptr_t)mpw.data.raw,
1017230189d9SNélio Laranjeiro 					   (void *)addr,
1018230189d9SNélio Laranjeiro 					   length);
1019230189d9SNélio Laranjeiro 				mpw.data.raw += length;
1020230189d9SNélio Laranjeiro 			}
1021230189d9SNélio Laranjeiro 			if ((uintptr_t)mpw.data.raw ==
1022230189d9SNélio Laranjeiro 			    (uintptr_t)&(*txq->wqes)[txq->wqe_n])
1023230189d9SNélio Laranjeiro 				mpw.data.raw =
1024230189d9SNélio Laranjeiro 					(volatile void *)&(*txq->wqes)[0];
1025230189d9SNélio Laranjeiro 			++mpw.pkts_n;
1026a5bf6af9SAdrien Mazarguil 			++j;
1027230189d9SNélio Laranjeiro 			if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) {
1028230189d9SNélio Laranjeiro 				mlx5_mpw_inline_close(txq, &mpw);
10290e8679fcSNélio Laranjeiro 				inline_room =
10300e8679fcSNélio Laranjeiro 					txq->max_inline * RTE_CACHE_LINE_SIZE;
1031230189d9SNélio Laranjeiro 			} else {
1032230189d9SNélio Laranjeiro 				inline_room -= length;
1033230189d9SNélio Laranjeiro 			}
1034230189d9SNélio Laranjeiro 		}
1035230189d9SNélio Laranjeiro 		mpw.total_len += length;
1036230189d9SNélio Laranjeiro 		elts_head = elts_head_next;
1037230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1038230189d9SNélio Laranjeiro 		/* Increment sent bytes counter. */
1039230189d9SNélio Laranjeiro 		txq->stats.obytes += length;
1040230189d9SNélio Laranjeiro #endif
1041c3d62cc9SAdrien Mazarguil 		++i;
1042c3d62cc9SAdrien Mazarguil 	} while (pkts_n);
1043230189d9SNélio Laranjeiro 	/* Take a shortcut if nothing must be sent. */
1044230189d9SNélio Laranjeiro 	if (unlikely(i == 0))
1045230189d9SNélio Laranjeiro 		return 0;
1046230189d9SNélio Laranjeiro 	/* Check whether completion threshold has been reached. */
1047a5bf6af9SAdrien Mazarguil 	/* "j" includes both packets and segments. */
1048a5bf6af9SAdrien Mazarguil 	comp = txq->elts_comp + j;
1049230189d9SNélio Laranjeiro 	if (comp >= MLX5_TX_COMP_THRESH) {
10508688b2f8SNélio Laranjeiro 		volatile struct mlx5_wqe *wqe = mpw.wqe;
1051230189d9SNélio Laranjeiro 
1052230189d9SNélio Laranjeiro 		/* Request completion on last WQE. */
10538688b2f8SNélio Laranjeiro 		wqe->ctrl[2] = htonl(8);
1054230189d9SNélio Laranjeiro 		/* Save elts_head in unused "immediate" field of WQE. */
10558688b2f8SNélio Laranjeiro 		wqe->ctrl[3] = elts_head;
1056230189d9SNélio Laranjeiro 		txq->elts_comp = 0;
1057230189d9SNélio Laranjeiro 	} else {
1058230189d9SNélio Laranjeiro 		txq->elts_comp = comp;
1059230189d9SNélio Laranjeiro 	}
1060230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS
1061230189d9SNélio Laranjeiro 	/* Increment sent packets counter. */
1062230189d9SNélio Laranjeiro 	txq->stats.opackets += i;
1063230189d9SNélio Laranjeiro #endif
1064230189d9SNélio Laranjeiro 	/* Ring QP doorbell. */
1065230189d9SNélio Laranjeiro 	if (mpw.state == MLX5_MPW_INL_STATE_OPENED)
1066230189d9SNélio Laranjeiro 		mlx5_mpw_inline_close(txq, &mpw);
1067230189d9SNélio Laranjeiro 	else if (mpw.state == MLX5_MPW_STATE_OPENED)
1068230189d9SNélio Laranjeiro 		mlx5_mpw_close(txq, &mpw);
1069230189d9SNélio Laranjeiro 	mlx5_tx_dbrec(txq);
1070230189d9SNélio Laranjeiro 	txq->elts_head = elts_head;
1071230189d9SNélio Laranjeiro 	return i;
1072230189d9SNélio Laranjeiro }
1073230189d9SNélio Laranjeiro 
1074230189d9SNélio Laranjeiro /**
107567fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
107667fa62bcSAdrien Mazarguil  *
10776218063bSNélio Laranjeiro  * @param[in] cqe
10786218063bSNélio Laranjeiro  *   Pointer to CQE.
107967fa62bcSAdrien Mazarguil  *
108078a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
108178a38edfSJianfeng Tan  *
108267fa62bcSAdrien Mazarguil  * @return
108367fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
108467fa62bcSAdrien Mazarguil  */
108567fa62bcSAdrien Mazarguil static inline uint32_t
10866218063bSNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe64 *cqe)
108767fa62bcSAdrien Mazarguil {
108867fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
10896218063bSNélio Laranjeiro 	uint8_t flags = cqe->l4_hdr_type_etc;
10906218063bSNélio Laranjeiro 	uint8_t info = cqe->rsvd0[0];
109167fa62bcSAdrien Mazarguil 
10926218063bSNélio Laranjeiro 	if (info & IBV_EXP_CQ_RX_TUNNEL_PACKET)
109367fa62bcSAdrien Mazarguil 		pkt_type =
109467fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
109567fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV4_PACKET,
109667fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
109767fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
109867fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV6_PACKET,
109967fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6) |
110067fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
110167fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV4_PACKET,
110267fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV4) |
110367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
110467fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV6_PACKET,
110567fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV6);
110667fa62bcSAdrien Mazarguil 	else
110767fa62bcSAdrien Mazarguil 		pkt_type =
110867fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
11096218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV6,
11106218063bSNélio Laranjeiro 				  RTE_PTYPE_L3_IPV6) |
111167fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
11126218063bSNélio Laranjeiro 				  MLX5_CQE_L3_HDR_TYPE_IPV4,
11136218063bSNélio Laranjeiro 				  RTE_PTYPE_L3_IPV4);
111467fa62bcSAdrien Mazarguil 	return pkt_type;
111567fa62bcSAdrien Mazarguil }
111667fa62bcSAdrien Mazarguil 
111767fa62bcSAdrien Mazarguil /**
111899c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
111999c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
112099c12dccSNélio Laranjeiro  * been processed.
112199c12dccSNélio Laranjeiro  *
112299c12dccSNélio Laranjeiro  * @param rxq
112399c12dccSNélio Laranjeiro  *   Pointer to RX queue.
112499c12dccSNélio Laranjeiro  * @param cqe
112599c12dccSNélio Laranjeiro  *   CQE to process.
112699c12dccSNélio Laranjeiro  *
112799c12dccSNélio Laranjeiro  * @return
112899c12dccSNélio Laranjeiro  *   Packet size in bytes (0 if there is none), -1 in case of completion
112999c12dccSNélio Laranjeiro  *   with error.
113099c12dccSNélio Laranjeiro  */
113199c12dccSNélio Laranjeiro static inline int
113299c12dccSNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe,
113399c12dccSNélio Laranjeiro 		 uint16_t cqe_cnt)
113499c12dccSNélio Laranjeiro {
113599c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
113699c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
113799c12dccSNélio Laranjeiro 	int len = 0;
113899c12dccSNélio Laranjeiro 
113999c12dccSNélio Laranjeiro 	/* Process compressed data in the CQE and mini arrays. */
114099c12dccSNélio Laranjeiro 	if (zip->ai) {
114199c12dccSNélio Laranjeiro 		volatile struct mlx5_mini_cqe8 (*mc)[8] =
114299c12dccSNélio Laranjeiro 			(volatile struct mlx5_mini_cqe8 (*)[8])
114399c12dccSNélio Laranjeiro 			(uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].cqe64);
114499c12dccSNélio Laranjeiro 
114599c12dccSNélio Laranjeiro 		len = ntohl((*mc)[zip->ai & 7].byte_cnt);
114699c12dccSNélio Laranjeiro 		if ((++zip->ai & 7) == 0) {
114799c12dccSNélio Laranjeiro 			/*
114899c12dccSNélio Laranjeiro 			 * Increment consumer index to skip the number of
114999c12dccSNélio Laranjeiro 			 * CQEs consumed. Hardware leaves holes in the CQ
115099c12dccSNélio Laranjeiro 			 * ring for software use.
115199c12dccSNélio Laranjeiro 			 */
115299c12dccSNélio Laranjeiro 			zip->ca = zip->na;
115399c12dccSNélio Laranjeiro 			zip->na += 8;
115499c12dccSNélio Laranjeiro 		}
115599c12dccSNélio Laranjeiro 		if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
115699c12dccSNélio Laranjeiro 			uint16_t idx = rxq->cq_ci;
115799c12dccSNélio Laranjeiro 			uint16_t end = zip->cq_ci;
115899c12dccSNélio Laranjeiro 
115999c12dccSNélio Laranjeiro 			while (idx != end) {
116099c12dccSNélio Laranjeiro 				(*rxq->cqes)[idx & cqe_cnt].cqe64.op_own =
116199c12dccSNélio Laranjeiro 					MLX5_CQE_INVALIDATE;
116299c12dccSNélio Laranjeiro 				++idx;
116399c12dccSNélio Laranjeiro 			}
116499c12dccSNélio Laranjeiro 			rxq->cq_ci = zip->cq_ci;
116599c12dccSNélio Laranjeiro 			zip->ai = 0;
116699c12dccSNélio Laranjeiro 		}
116799c12dccSNélio Laranjeiro 	/* No compressed data, get next CQE and verify if it is compressed. */
116899c12dccSNélio Laranjeiro 	} else {
116999c12dccSNélio Laranjeiro 		int ret;
117099c12dccSNélio Laranjeiro 		int8_t op_own;
117199c12dccSNélio Laranjeiro 
117299c12dccSNélio Laranjeiro 		ret = check_cqe64(cqe, cqe_n, rxq->cq_ci);
117399c12dccSNélio Laranjeiro 		if (unlikely(ret == 1))
117499c12dccSNélio Laranjeiro 			return 0;
117599c12dccSNélio Laranjeiro 		++rxq->cq_ci;
117699c12dccSNélio Laranjeiro 		op_own = cqe->op_own;
117799c12dccSNélio Laranjeiro 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
117899c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
117999c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
118099c12dccSNélio Laranjeiro 				(uintptr_t)(&(*rxq->cqes)[rxq->cq_ci &
118199c12dccSNélio Laranjeiro 							  cqe_cnt].cqe64);
118299c12dccSNélio Laranjeiro 
118399c12dccSNélio Laranjeiro 			/* Fix endianness. */
118499c12dccSNélio Laranjeiro 			zip->cqe_cnt = ntohl(cqe->byte_cnt);
118599c12dccSNélio Laranjeiro 			/*
118699c12dccSNélio Laranjeiro 			 * Current mini array position is the one returned by
118799c12dccSNélio Laranjeiro 			 * check_cqe64().
118899c12dccSNélio Laranjeiro 			 *
118999c12dccSNélio Laranjeiro 			 * If completion comprises several mini arrays, as a
119099c12dccSNélio Laranjeiro 			 * special case the second one is located 7 CQEs after
119199c12dccSNélio Laranjeiro 			 * the initial CQE instead of 8 for subsequent ones.
119299c12dccSNélio Laranjeiro 			 */
119399c12dccSNélio Laranjeiro 			zip->ca = rxq->cq_ci & cqe_cnt;
119499c12dccSNélio Laranjeiro 			zip->na = zip->ca + 7;
119599c12dccSNélio Laranjeiro 			/* Compute the next non compressed CQE. */
119699c12dccSNélio Laranjeiro 			--rxq->cq_ci;
119799c12dccSNélio Laranjeiro 			zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
119899c12dccSNélio Laranjeiro 			/* Get packet size to return. */
119999c12dccSNélio Laranjeiro 			len = ntohl((*mc)[0].byte_cnt);
120099c12dccSNélio Laranjeiro 			zip->ai = 1;
120199c12dccSNélio Laranjeiro 		} else {
120299c12dccSNélio Laranjeiro 			len = ntohl(cqe->byte_cnt);
120399c12dccSNélio Laranjeiro 		}
120499c12dccSNélio Laranjeiro 		/* Error while receiving packet. */
120599c12dccSNélio Laranjeiro 		if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR))
120699c12dccSNélio Laranjeiro 			return -1;
120799c12dccSNélio Laranjeiro 	}
120899c12dccSNélio Laranjeiro 	return len;
120999c12dccSNélio Laranjeiro }
121099c12dccSNélio Laranjeiro 
121199c12dccSNélio Laranjeiro /**
121267fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
121367fa62bcSAdrien Mazarguil  *
121467fa62bcSAdrien Mazarguil  * @param[in] rxq
121567fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
12166218063bSNélio Laranjeiro  * @param[in] cqe
12176218063bSNélio Laranjeiro  *   Pointer to CQE.
121867fa62bcSAdrien Mazarguil  *
121967fa62bcSAdrien Mazarguil  * @return
122067fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
122167fa62bcSAdrien Mazarguil  */
122267fa62bcSAdrien Mazarguil static inline uint32_t
12236218063bSNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe)
122467fa62bcSAdrien Mazarguil {
122567fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
12266218063bSNélio Laranjeiro 	uint8_t l3_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L3_HDR_TYPE_MASK;
12276218063bSNélio Laranjeiro 	uint8_t l4_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L4_HDR_TYPE_MASK;
12286218063bSNélio Laranjeiro 	uint8_t info = cqe->rsvd0[0];
122967fa62bcSAdrien Mazarguil 
12306218063bSNélio Laranjeiro 	if ((l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV4) ||
12316218063bSNélio Laranjeiro 	    (l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV6))
123267fa62bcSAdrien Mazarguil 		ol_flags |=
12336218063bSNélio Laranjeiro 			(!(cqe->hds_ip_ext & MLX5_CQE_L3_OK) *
1234d0087d76SYaacov Hazan 			 PKT_RX_IP_CKSUM_BAD);
12356218063bSNélio Laranjeiro 	if ((l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP) ||
12366218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_EMP_ACK) ||
12376218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_ACK) ||
12386218063bSNélio Laranjeiro 	    (l4_hdr == MLX5_CQE_L4_HDR_TYPE_UDP))
1239d0087d76SYaacov Hazan 		ol_flags |=
12406218063bSNélio Laranjeiro 			(!(cqe->hds_ip_ext & MLX5_CQE_L4_OK) *
124167fa62bcSAdrien Mazarguil 			 PKT_RX_L4_CKSUM_BAD);
124267fa62bcSAdrien Mazarguil 	/*
124367fa62bcSAdrien Mazarguil 	 * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place
124467fa62bcSAdrien Mazarguil 	 * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional
124567fa62bcSAdrien Mazarguil 	 * (its value is 0).
124667fa62bcSAdrien Mazarguil 	 */
12476218063bSNélio Laranjeiro 	if ((info & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
124867fa62bcSAdrien Mazarguil 		ol_flags |=
12496218063bSNélio Laranjeiro 			TRANSPOSE(~cqe->l4_hdr_type_etc,
125067fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK,
125167fa62bcSAdrien Mazarguil 				  PKT_RX_IP_CKSUM_BAD) |
12526218063bSNélio Laranjeiro 			TRANSPOSE(~cqe->l4_hdr_type_etc,
125367fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK,
125467fa62bcSAdrien Mazarguil 				  PKT_RX_L4_CKSUM_BAD);
125567fa62bcSAdrien Mazarguil 	return ol_flags;
125667fa62bcSAdrien Mazarguil }
125767fa62bcSAdrien Mazarguil 
125867fa62bcSAdrien Mazarguil /**
12592e22920bSAdrien Mazarguil  * DPDK callback for RX.
12602e22920bSAdrien Mazarguil  *
12612e22920bSAdrien Mazarguil  * @param dpdk_rxq
12622e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
12632e22920bSAdrien Mazarguil  * @param[out] pkts
12642e22920bSAdrien Mazarguil  *   Array to store received packets.
12652e22920bSAdrien Mazarguil  * @param pkts_n
12662e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
12672e22920bSAdrien Mazarguil  *
12682e22920bSAdrien Mazarguil  * @return
12692e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
12702e22920bSAdrien Mazarguil  */
12712e22920bSAdrien Mazarguil uint16_t
12722e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
12732e22920bSAdrien Mazarguil {
12746218063bSNélio Laranjeiro 	struct rxq *rxq = dpdk_rxq;
127599c12dccSNélio Laranjeiro 	const unsigned int cqe_cnt = rxq->cqe_n - 1;
1276*b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
12779964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
12789964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
12799964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
12806218063bSNélio Laranjeiro 	volatile struct mlx5_cqe64 *cqe =
128199c12dccSNélio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64;
12829964b965SNélio Laranjeiro 	unsigned int i = 0;
12839964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
12849964b965SNélio Laranjeiro 	int len;
12852e22920bSAdrien Mazarguil 
12869964b965SNélio Laranjeiro 	while (pkts_n) {
12879964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
12889964b965SNélio Laranjeiro 		volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx];
12899964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
12909964b965SNélio Laranjeiro 
12919964b965SNélio Laranjeiro 		if (pkt)
12929964b965SNélio Laranjeiro 			NEXT(seg) = rep;
12939964b965SNélio Laranjeiro 		seg = rep;
12949964b965SNélio Laranjeiro 		rte_prefetch0(seg);
12956218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
12969964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1297fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
12982e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
129915a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
130015a756b6SSagi Grimberg 			if (!pkt) {
130115a756b6SSagi Grimberg 				/*
130215a756b6SSagi Grimberg 				 * no buffers before we even started,
130315a756b6SSagi Grimberg 				 * bail out silently.
130415a756b6SSagi Grimberg 				 */
130515a756b6SSagi Grimberg 				break;
130615a756b6SSagi Grimberg 			}
1307a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1308a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
13099964b965SNélio Laranjeiro 				seg = NEXT(pkt);
13109964b965SNélio Laranjeiro 				rte_mbuf_refcnt_set(pkt, 0);
13119964b965SNélio Laranjeiro 				__rte_mbuf_raw_free(pkt);
13129964b965SNélio Laranjeiro 				pkt = seg;
13139964b965SNélio Laranjeiro 			}
13146218063bSNélio Laranjeiro 			break;
13152e22920bSAdrien Mazarguil 		}
13169964b965SNélio Laranjeiro 		if (!pkt) {
13179964b965SNélio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64;
131899c12dccSNélio Laranjeiro 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt);
13199964b965SNélio Laranjeiro 			if (len == 0) {
13206218063bSNélio Laranjeiro 				rte_mbuf_refcnt_set(rep, 0);
13216218063bSNélio Laranjeiro 				__rte_mbuf_raw_free(rep);
13226218063bSNélio Laranjeiro 				break;
13236218063bSNélio Laranjeiro 			}
132499c12dccSNélio Laranjeiro 			if (unlikely(len == -1)) {
132599c12dccSNélio Laranjeiro 				/* RX error, packet is likely too large. */
132699c12dccSNélio Laranjeiro 				rte_mbuf_refcnt_set(rep, 0);
132799c12dccSNélio Laranjeiro 				__rte_mbuf_raw_free(rep);
132899c12dccSNélio Laranjeiro 				++rxq->stats.idropped;
132999c12dccSNélio Laranjeiro 				goto skip;
133099c12dccSNélio Laranjeiro 			}
13319964b965SNélio Laranjeiro 			pkt = seg;
13329964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
13339964b965SNélio Laranjeiro 			/* Update packet information. */
13340ac64846SMaxime Leroy 			pkt->packet_type = 0;
13350ac64846SMaxime Leroy 			pkt->ol_flags = 0;
13366218063bSNélio Laranjeiro 			if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip |
13376218063bSNélio Laranjeiro 			    rxq->crc_present) {
13386218063bSNélio Laranjeiro 				if (rxq->csum) {
13399964b965SNélio Laranjeiro 					pkt->packet_type =
13409964b965SNélio Laranjeiro 						rxq_cq_to_pkt_type(cqe);
13419964b965SNélio Laranjeiro 					pkt->ol_flags =
13429964b965SNélio Laranjeiro 						rxq_cq_to_ol_flags(rxq, cqe);
13436218063bSNélio Laranjeiro 				}
13449964b965SNélio Laranjeiro 				if (cqe->l4_hdr_type_etc &
13459964b965SNélio Laranjeiro 				    MLX5_CQE_VLAN_STRIPPED) {
13466218063bSNélio Laranjeiro 					pkt->ol_flags |= PKT_RX_VLAN_PKT |
1347b37b528dSOlivier Matz 						PKT_RX_VLAN_STRIPPED;
13486218063bSNélio Laranjeiro 					pkt->vlan_tci = ntohs(cqe->vlan_info);
1349f3db9489SYaacov Hazan 				}
13506218063bSNélio Laranjeiro 				if (rxq->crc_present)
13516218063bSNélio Laranjeiro 					len -= ETHER_CRC_LEN;
1352081f7eaeSNelio Laranjeiro 			}
13536218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
13549964b965SNélio Laranjeiro 		}
13559964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
13569964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
13579964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
13589964b965SNélio Laranjeiro 		NB_SEGS(rep) = NB_SEGS(seg);
13599964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
13609964b965SNélio Laranjeiro 		NEXT(rep) = NULL;
13619964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
13629964b965SNélio Laranjeiro 		/*
13639964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
13649964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
13659964b965SNélio Laranjeiro 		 * changes.
13669964b965SNélio Laranjeiro 		 */
13679964b965SNélio Laranjeiro 		wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t));
13689964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
13699964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
13709964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
13719964b965SNélio Laranjeiro 			++rq_ci;
13729964b965SNélio Laranjeiro 			continue;
13739964b965SNélio Laranjeiro 		}
13749964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
137587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
137687011737SAdrien Mazarguil 		/* Increment bytes counter. */
13779964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
137887011737SAdrien Mazarguil #endif
13796218063bSNélio Laranjeiro 		/* Return packet. */
13806218063bSNélio Laranjeiro 		*(pkts++) = pkt;
13819964b965SNélio Laranjeiro 		pkt = NULL;
13829964b965SNélio Laranjeiro 		--pkts_n;
13839964b965SNélio Laranjeiro 		++i;
138499c12dccSNélio Laranjeiro skip:
13859964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
13869964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
13876218063bSNélio Laranjeiro 		++rq_ci;
13889964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
13892e22920bSAdrien Mazarguil 	}
13909964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
13912e22920bSAdrien Mazarguil 		return 0;
13926218063bSNélio Laranjeiro 	/* Update the consumer index. */
13939964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
13946218063bSNélio Laranjeiro 	rte_wmb();
13956218063bSNélio Laranjeiro 	*rxq->cq_db = htonl(rxq->cq_ci);
13966218063bSNélio Laranjeiro 	rte_wmb();
13976218063bSNélio Laranjeiro 	*rxq->rq_db = htonl(rxq->rq_ci);
139887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
139987011737SAdrien Mazarguil 	/* Increment packets counter. */
14009964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
140187011737SAdrien Mazarguil #endif
14029964b965SNélio Laranjeiro 	return i;
14032e22920bSAdrien Mazarguil }
14042e22920bSAdrien Mazarguil 
14052e22920bSAdrien Mazarguil /**
14062e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
14072e22920bSAdrien Mazarguil  *
14082e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14092e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14102e22920bSAdrien Mazarguil  *
14112e22920bSAdrien Mazarguil  * @param dpdk_txq
14122e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
14132e22920bSAdrien Mazarguil  * @param[in] pkts
14142e22920bSAdrien Mazarguil  *   Packets to transmit.
14152e22920bSAdrien Mazarguil  * @param pkts_n
14162e22920bSAdrien Mazarguil  *   Number of packets in array.
14172e22920bSAdrien Mazarguil  *
14182e22920bSAdrien Mazarguil  * @return
14192e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
14202e22920bSAdrien Mazarguil  */
14212e22920bSAdrien Mazarguil uint16_t
14222e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
14232e22920bSAdrien Mazarguil {
14242e22920bSAdrien Mazarguil 	(void)dpdk_txq;
14252e22920bSAdrien Mazarguil 	(void)pkts;
14262e22920bSAdrien Mazarguil 	(void)pkts_n;
14272e22920bSAdrien Mazarguil 	return 0;
14282e22920bSAdrien Mazarguil }
14292e22920bSAdrien Mazarguil 
14302e22920bSAdrien Mazarguil /**
14312e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
14322e22920bSAdrien Mazarguil  *
14332e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14342e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14352e22920bSAdrien Mazarguil  *
14362e22920bSAdrien Mazarguil  * @param dpdk_rxq
14372e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
14382e22920bSAdrien Mazarguil  * @param[out] pkts
14392e22920bSAdrien Mazarguil  *   Array to store received packets.
14402e22920bSAdrien Mazarguil  * @param pkts_n
14412e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
14422e22920bSAdrien Mazarguil  *
14432e22920bSAdrien Mazarguil  * @return
14442e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
14452e22920bSAdrien Mazarguil  */
14462e22920bSAdrien Mazarguil uint16_t
14472e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
14482e22920bSAdrien Mazarguil {
14492e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
14502e22920bSAdrien Mazarguil 	(void)pkts;
14512e22920bSAdrien Mazarguil 	(void)pkts_n;
14522e22920bSAdrien Mazarguil 	return 0;
14532e22920bSAdrien Mazarguil }
1454