xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision a859e8a904bd0798e456d8afd7f60b8020a8cefc)
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
422e22920bSAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic"
432e22920bSAdrien Mazarguil #endif
442e22920bSAdrien Mazarguil #include <infiniband/verbs.h>
452e22920bSAdrien Mazarguil #ifdef PEDANTIC
462e22920bSAdrien Mazarguil #pragma GCC diagnostic error "-pedantic"
472e22920bSAdrien Mazarguil #endif
482e22920bSAdrien Mazarguil 
492e22920bSAdrien Mazarguil /* DPDK headers don't like -pedantic. */
502e22920bSAdrien Mazarguil #ifdef PEDANTIC
512e22920bSAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic"
522e22920bSAdrien Mazarguil #endif
532e22920bSAdrien Mazarguil #include <rte_mbuf.h>
542e22920bSAdrien Mazarguil #include <rte_mempool.h>
552e22920bSAdrien Mazarguil #include <rte_prefetch.h>
562e22920bSAdrien Mazarguil #include <rte_common.h>
572e22920bSAdrien Mazarguil #include <rte_branch_prediction.h>
582e22920bSAdrien Mazarguil #ifdef PEDANTIC
592e22920bSAdrien Mazarguil #pragma GCC diagnostic error "-pedantic"
602e22920bSAdrien Mazarguil #endif
612e22920bSAdrien Mazarguil 
622e22920bSAdrien Mazarguil #include "mlx5.h"
632e22920bSAdrien Mazarguil #include "mlx5_utils.h"
642e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
65f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
662e22920bSAdrien Mazarguil #include "mlx5_defs.h"
672e22920bSAdrien Mazarguil 
682e22920bSAdrien Mazarguil /**
692e22920bSAdrien Mazarguil  * Manage TX completions.
702e22920bSAdrien Mazarguil  *
712e22920bSAdrien Mazarguil  * When sending a burst, mlx5_tx_burst() posts several WRs.
722e22920bSAdrien Mazarguil  * To improve performance, a completion event is only required once every
732e22920bSAdrien Mazarguil  * MLX5_PMD_TX_PER_COMP_REQ sends. Doing so discards completion information
742e22920bSAdrien Mazarguil  * for other WRs, but this information would not be used anyway.
752e22920bSAdrien Mazarguil  *
762e22920bSAdrien Mazarguil  * @param txq
772e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
782e22920bSAdrien Mazarguil  *
792e22920bSAdrien Mazarguil  * @return
802e22920bSAdrien Mazarguil  *   0 on success, -1 on failure.
812e22920bSAdrien Mazarguil  */
822e22920bSAdrien Mazarguil static int
832e22920bSAdrien Mazarguil txq_complete(struct txq *txq)
842e22920bSAdrien Mazarguil {
852e22920bSAdrien Mazarguil 	unsigned int elts_comp = txq->elts_comp;
862e22920bSAdrien Mazarguil 	unsigned int elts_tail = txq->elts_tail;
87*a859e8a9SNelio Laranjeiro 	unsigned int elts_free = txq->elts_tail;
882e22920bSAdrien Mazarguil 	const unsigned int elts_n = txq->elts_n;
892e22920bSAdrien Mazarguil 	int wcs_n;
902e22920bSAdrien Mazarguil 
912e22920bSAdrien Mazarguil 	if (unlikely(elts_comp == 0))
922e22920bSAdrien Mazarguil 		return 0;
932e22920bSAdrien Mazarguil #ifdef DEBUG_SEND
942e22920bSAdrien Mazarguil 	DEBUG("%p: processing %u work requests completions",
952e22920bSAdrien Mazarguil 	      (void *)txq, elts_comp);
962e22920bSAdrien Mazarguil #endif
97e1682023SNelio Laranjeiro 	wcs_n = txq->poll_cnt(txq->cq, elts_comp);
982e22920bSAdrien Mazarguil 	if (unlikely(wcs_n == 0))
992e22920bSAdrien Mazarguil 		return 0;
1002e22920bSAdrien Mazarguil 	if (unlikely(wcs_n < 0)) {
1012e22920bSAdrien Mazarguil 		DEBUG("%p: ibv_poll_cq() failed (wcs_n=%d)",
1022e22920bSAdrien Mazarguil 		      (void *)txq, wcs_n);
1032e22920bSAdrien Mazarguil 		return -1;
1042e22920bSAdrien Mazarguil 	}
1052e22920bSAdrien Mazarguil 	elts_comp -= wcs_n;
1062e22920bSAdrien Mazarguil 	assert(elts_comp <= txq->elts_comp);
1072e22920bSAdrien Mazarguil 	/*
1082e22920bSAdrien Mazarguil 	 * Assume WC status is successful as nothing can be done about it
1092e22920bSAdrien Mazarguil 	 * anyway.
1102e22920bSAdrien Mazarguil 	 */
1112e22920bSAdrien Mazarguil 	elts_tail += wcs_n * txq->elts_comp_cd_init;
1122e22920bSAdrien Mazarguil 	if (elts_tail >= elts_n)
1132e22920bSAdrien Mazarguil 		elts_tail -= elts_n;
114*a859e8a9SNelio Laranjeiro 
115*a859e8a9SNelio Laranjeiro 	while (elts_free != elts_tail) {
116*a859e8a9SNelio Laranjeiro 		struct txq_elt *elt = &(*txq->elts)[elts_free];
117*a859e8a9SNelio Laranjeiro 		unsigned int elts_free_next =
118*a859e8a9SNelio Laranjeiro 			(((elts_free + 1) == elts_n) ? 0 : elts_free + 1);
119*a859e8a9SNelio Laranjeiro 		struct rte_mbuf *tmp = elt->buf;
120*a859e8a9SNelio Laranjeiro 		struct txq_elt *elt_next = &(*txq->elts)[elts_free_next];
121*a859e8a9SNelio Laranjeiro 
122*a859e8a9SNelio Laranjeiro 		RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
123*a859e8a9SNelio Laranjeiro 		/* Faster than rte_pktmbuf_free(). */
124*a859e8a9SNelio Laranjeiro 		do {
125*a859e8a9SNelio Laranjeiro 			struct rte_mbuf *next = NEXT(tmp);
126*a859e8a9SNelio Laranjeiro 
127*a859e8a9SNelio Laranjeiro 			rte_pktmbuf_free_seg(tmp);
128*a859e8a9SNelio Laranjeiro 			tmp = next;
129*a859e8a9SNelio Laranjeiro 		} while (tmp != NULL);
130*a859e8a9SNelio Laranjeiro 		elts_free = elts_free_next;
131*a859e8a9SNelio Laranjeiro 	}
132*a859e8a9SNelio Laranjeiro 
1332e22920bSAdrien Mazarguil 	txq->elts_tail = elts_tail;
1342e22920bSAdrien Mazarguil 	txq->elts_comp = elts_comp;
1352e22920bSAdrien Mazarguil 	return 0;
1362e22920bSAdrien Mazarguil }
1372e22920bSAdrien Mazarguil 
1382e22920bSAdrien Mazarguil /**
1398340392eSAdrien Mazarguil  * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
1408340392eSAdrien Mazarguil  * the cloned mbuf is allocated is returned instead.
1418340392eSAdrien Mazarguil  *
1428340392eSAdrien Mazarguil  * @param buf
1438340392eSAdrien Mazarguil  *   Pointer to mbuf.
1448340392eSAdrien Mazarguil  *
1458340392eSAdrien Mazarguil  * @return
1468340392eSAdrien Mazarguil  *   Memory pool where data is located for given mbuf.
1478340392eSAdrien Mazarguil  */
1488340392eSAdrien Mazarguil static struct rte_mempool *
1498340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf)
1508340392eSAdrien Mazarguil {
1518340392eSAdrien Mazarguil 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
1528340392eSAdrien Mazarguil 		return rte_mbuf_from_indirect(buf)->pool;
1538340392eSAdrien Mazarguil 	return buf->pool;
1548340392eSAdrien Mazarguil }
1558340392eSAdrien Mazarguil 
1568340392eSAdrien Mazarguil /**
1572e22920bSAdrien Mazarguil  * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[].
1582e22920bSAdrien Mazarguil  * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
1592e22920bSAdrien Mazarguil  * remove an entry first.
1602e22920bSAdrien Mazarguil  *
1612e22920bSAdrien Mazarguil  * @param txq
1622e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
1632e22920bSAdrien Mazarguil  * @param[in] mp
1642e22920bSAdrien Mazarguil  *   Memory Pool for which a Memory Region lkey must be returned.
1652e22920bSAdrien Mazarguil  *
1662e22920bSAdrien Mazarguil  * @return
1672e22920bSAdrien Mazarguil  *   mr->lkey on success, (uint32_t)-1 on failure.
1682e22920bSAdrien Mazarguil  */
1692e22920bSAdrien Mazarguil static uint32_t
1700a3b350dSOlga Shern txq_mp2mr(struct txq *txq, const struct rte_mempool *mp)
1712e22920bSAdrien Mazarguil {
1722e22920bSAdrien Mazarguil 	unsigned int i;
1732e22920bSAdrien Mazarguil 	struct ibv_mr *mr;
1742e22920bSAdrien Mazarguil 
1752e22920bSAdrien Mazarguil 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
1762e22920bSAdrien Mazarguil 		if (unlikely(txq->mp2mr[i].mp == NULL)) {
1772e22920bSAdrien Mazarguil 			/* Unknown MP, add a new MR for it. */
1782e22920bSAdrien Mazarguil 			break;
1792e22920bSAdrien Mazarguil 		}
1802e22920bSAdrien Mazarguil 		if (txq->mp2mr[i].mp == mp) {
1812e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].lkey != (uint32_t)-1);
1822e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].mr->lkey == txq->mp2mr[i].lkey);
1832e22920bSAdrien Mazarguil 			return txq->mp2mr[i].lkey;
1842e22920bSAdrien Mazarguil 		}
1852e22920bSAdrien Mazarguil 	}
1862e22920bSAdrien Mazarguil 	/* Add a new entry, register MR first. */
1870a3b350dSOlga Shern 	DEBUG("%p: discovered new memory pool \"%s\" (%p)",
1880a3b350dSOlga Shern 	      (void *)txq, mp->name, (const void *)mp);
1892e22920bSAdrien Mazarguil 	mr = ibv_reg_mr(txq->priv->pd,
1902e22920bSAdrien Mazarguil 			(void *)mp->elt_va_start,
1912e22920bSAdrien Mazarguil 			(mp->elt_va_end - mp->elt_va_start),
1922e22920bSAdrien Mazarguil 			(IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE));
1932e22920bSAdrien Mazarguil 	if (unlikely(mr == NULL)) {
1942e22920bSAdrien Mazarguil 		DEBUG("%p: unable to configure MR, ibv_reg_mr() failed.",
1952e22920bSAdrien Mazarguil 		      (void *)txq);
1962e22920bSAdrien Mazarguil 		return (uint32_t)-1;
1972e22920bSAdrien Mazarguil 	}
1982e22920bSAdrien Mazarguil 	if (unlikely(i == RTE_DIM(txq->mp2mr))) {
1992e22920bSAdrien Mazarguil 		/* Table is full, remove oldest entry. */
2002e22920bSAdrien Mazarguil 		DEBUG("%p: MR <-> MP table full, dropping oldest entry.",
2012e22920bSAdrien Mazarguil 		      (void *)txq);
2022e22920bSAdrien Mazarguil 		--i;
203ecbfdbadSOlga Shern 		claim_zero(ibv_dereg_mr(txq->mp2mr[0].mr));
2042e22920bSAdrien Mazarguil 		memmove(&txq->mp2mr[0], &txq->mp2mr[1],
2052e22920bSAdrien Mazarguil 			(sizeof(txq->mp2mr) - sizeof(txq->mp2mr[0])));
2062e22920bSAdrien Mazarguil 	}
2072e22920bSAdrien Mazarguil 	/* Store the new entry. */
2082e22920bSAdrien Mazarguil 	txq->mp2mr[i].mp = mp;
2092e22920bSAdrien Mazarguil 	txq->mp2mr[i].mr = mr;
2102e22920bSAdrien Mazarguil 	txq->mp2mr[i].lkey = mr->lkey;
2110a3b350dSOlga Shern 	DEBUG("%p: new MR lkey for MP \"%s\" (%p): 0x%08" PRIu32,
2120a3b350dSOlga Shern 	      (void *)txq, mp->name, (const void *)mp, txq->mp2mr[i].lkey);
2132e22920bSAdrien Mazarguil 	return txq->mp2mr[i].lkey;
2142e22920bSAdrien Mazarguil }
2152e22920bSAdrien Mazarguil 
2160a3b350dSOlga Shern struct txq_mp2mr_mbuf_check_data {
2170a3b350dSOlga Shern 	const struct rte_mempool *mp;
2180a3b350dSOlga Shern 	int ret;
2190a3b350dSOlga Shern };
2200a3b350dSOlga Shern 
2210a3b350dSOlga Shern /**
2220a3b350dSOlga Shern  * Callback function for rte_mempool_obj_iter() to check whether a given
2230a3b350dSOlga Shern  * mempool object looks like a mbuf.
2240a3b350dSOlga Shern  *
2250a3b350dSOlga Shern  * @param[in, out] arg
2260a3b350dSOlga Shern  *   Context data (struct txq_mp2mr_mbuf_check_data). Contains mempool pointer
2270a3b350dSOlga Shern  *   and return value.
2280a3b350dSOlga Shern  * @param[in] start
2290a3b350dSOlga Shern  *   Object start address.
2300a3b350dSOlga Shern  * @param[in] end
2310a3b350dSOlga Shern  *   Object end address.
2320a3b350dSOlga Shern  * @param index
2330a3b350dSOlga Shern  *   Unused.
2340a3b350dSOlga Shern  *
2350a3b350dSOlga Shern  * @return
2360a3b350dSOlga Shern  *   Nonzero value when object is not a mbuf.
2370a3b350dSOlga Shern  */
2380a3b350dSOlga Shern static void
2390a3b350dSOlga Shern txq_mp2mr_mbuf_check(void *arg, void *start, void *end,
2400a3b350dSOlga Shern 		     uint32_t index __rte_unused)
2410a3b350dSOlga Shern {
2420a3b350dSOlga Shern 	struct txq_mp2mr_mbuf_check_data *data = arg;
2430a3b350dSOlga Shern 	struct rte_mbuf *buf =
2440a3b350dSOlga Shern 		(void *)((uintptr_t)start + data->mp->header_size);
2450a3b350dSOlga Shern 
2460a3b350dSOlga Shern 	(void)index;
2470a3b350dSOlga Shern 	/* Check whether mbuf structure fits element size and whether mempool
2480a3b350dSOlga Shern 	 * pointer is valid. */
2490a3b350dSOlga Shern 	if (((uintptr_t)end >= (uintptr_t)(buf + 1)) &&
2500a3b350dSOlga Shern 	    (buf->pool == data->mp))
2510a3b350dSOlga Shern 		data->ret = 0;
2520a3b350dSOlga Shern 	else
2530a3b350dSOlga Shern 		data->ret = -1;
2540a3b350dSOlga Shern }
2550a3b350dSOlga Shern 
2560a3b350dSOlga Shern /**
2570a3b350dSOlga Shern  * Iterator function for rte_mempool_walk() to register existing mempools and
2580a3b350dSOlga Shern  * fill the MP to MR cache of a TX queue.
2590a3b350dSOlga Shern  *
2600a3b350dSOlga Shern  * @param[in] mp
2610a3b350dSOlga Shern  *   Memory Pool to register.
2620a3b350dSOlga Shern  * @param *arg
2630a3b350dSOlga Shern  *   Pointer to TX queue structure.
2640a3b350dSOlga Shern  */
2650a3b350dSOlga Shern void
2660a3b350dSOlga Shern txq_mp2mr_iter(const struct rte_mempool *mp, void *arg)
2670a3b350dSOlga Shern {
2680a3b350dSOlga Shern 	struct txq *txq = arg;
2690a3b350dSOlga Shern 	struct txq_mp2mr_mbuf_check_data data = {
2700a3b350dSOlga Shern 		.mp = mp,
2710a3b350dSOlga Shern 		.ret = -1,
2720a3b350dSOlga Shern 	};
2730a3b350dSOlga Shern 
2740a3b350dSOlga Shern 	/* Discard empty mempools. */
2750a3b350dSOlga Shern 	if (mp->size == 0)
2760a3b350dSOlga Shern 		return;
2770a3b350dSOlga Shern 	/* Register mempool only if the first element looks like a mbuf. */
2780a3b350dSOlga Shern 	rte_mempool_obj_iter((void *)mp->elt_va_start,
2790a3b350dSOlga Shern 			     1,
2800a3b350dSOlga Shern 			     mp->header_size + mp->elt_size + mp->trailer_size,
2810a3b350dSOlga Shern 			     1,
2820a3b350dSOlga Shern 			     mp->elt_pa,
2830a3b350dSOlga Shern 			     mp->pg_num,
2840a3b350dSOlga Shern 			     mp->pg_shift,
2850a3b350dSOlga Shern 			     txq_mp2mr_mbuf_check,
2860a3b350dSOlga Shern 			     &data);
2870a3b350dSOlga Shern 	if (data.ret)
2880a3b350dSOlga Shern 		return;
2890a3b350dSOlga Shern 	txq_mp2mr(txq, mp);
2900a3b350dSOlga Shern }
2910a3b350dSOlga Shern 
2923ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1
2933ee84446SAdrien Mazarguil 
2943ee84446SAdrien Mazarguil /**
2953ee84446SAdrien Mazarguil  * Copy scattered mbuf contents to a single linear buffer.
2963ee84446SAdrien Mazarguil  *
2973ee84446SAdrien Mazarguil  * @param[out] linear
2983ee84446SAdrien Mazarguil  *   Linear output buffer.
2993ee84446SAdrien Mazarguil  * @param[in] buf
3003ee84446SAdrien Mazarguil  *   Scattered input buffer.
3013ee84446SAdrien Mazarguil  *
3023ee84446SAdrien Mazarguil  * @return
3033ee84446SAdrien Mazarguil  *   Number of bytes copied to the output buffer or 0 if not large enough.
3043ee84446SAdrien Mazarguil  */
3053ee84446SAdrien Mazarguil static unsigned int
3063ee84446SAdrien Mazarguil linearize_mbuf(linear_t *linear, struct rte_mbuf *buf)
3073ee84446SAdrien Mazarguil {
3083ee84446SAdrien Mazarguil 	unsigned int size = 0;
3093ee84446SAdrien Mazarguil 	unsigned int offset;
3103ee84446SAdrien Mazarguil 
3113ee84446SAdrien Mazarguil 	do {
3123ee84446SAdrien Mazarguil 		unsigned int len = DATA_LEN(buf);
3133ee84446SAdrien Mazarguil 
3143ee84446SAdrien Mazarguil 		offset = size;
3153ee84446SAdrien Mazarguil 		size += len;
3163ee84446SAdrien Mazarguil 		if (unlikely(size > sizeof(*linear)))
3173ee84446SAdrien Mazarguil 			return 0;
3183ee84446SAdrien Mazarguil 		memcpy(&(*linear)[offset],
3193ee84446SAdrien Mazarguil 		       rte_pktmbuf_mtod(buf, uint8_t *),
3203ee84446SAdrien Mazarguil 		       len);
3213ee84446SAdrien Mazarguil 		buf = NEXT(buf);
3223ee84446SAdrien Mazarguil 	} while (buf != NULL);
3233ee84446SAdrien Mazarguil 	return size;
3243ee84446SAdrien Mazarguil }
3253ee84446SAdrien Mazarguil 
3263ee84446SAdrien Mazarguil /**
3273ee84446SAdrien Mazarguil  * Handle scattered buffers for mlx5_tx_burst().
3283ee84446SAdrien Mazarguil  *
3293ee84446SAdrien Mazarguil  * @param txq
3303ee84446SAdrien Mazarguil  *   TX queue structure.
3313ee84446SAdrien Mazarguil  * @param segs
3323ee84446SAdrien Mazarguil  *   Number of segments in buf.
3333ee84446SAdrien Mazarguil  * @param elt
3343ee84446SAdrien Mazarguil  *   TX queue element to fill.
3353ee84446SAdrien Mazarguil  * @param[in] buf
3363ee84446SAdrien Mazarguil  *   Buffer to process.
3373ee84446SAdrien Mazarguil  * @param elts_head
3383ee84446SAdrien Mazarguil  *   Index of the linear buffer to use if necessary (normally txq->elts_head).
3393ee84446SAdrien Mazarguil  * @param[out] sges
3403ee84446SAdrien Mazarguil  *   Array filled with SGEs on success.
3413ee84446SAdrien Mazarguil  *
3423ee84446SAdrien Mazarguil  * @return
3433ee84446SAdrien Mazarguil  *   A structure containing the processed packet size in bytes and the
3443ee84446SAdrien Mazarguil  *   number of SGEs. Both fields are set to (unsigned int)-1 in case of
3453ee84446SAdrien Mazarguil  *   failure.
3463ee84446SAdrien Mazarguil  */
3473ee84446SAdrien Mazarguil static struct tx_burst_sg_ret {
3483ee84446SAdrien Mazarguil 	unsigned int length;
3493ee84446SAdrien Mazarguil 	unsigned int num;
3503ee84446SAdrien Mazarguil }
3513ee84446SAdrien Mazarguil tx_burst_sg(struct txq *txq, unsigned int segs, struct txq_elt *elt,
3523ee84446SAdrien Mazarguil 	    struct rte_mbuf *buf, unsigned int elts_head,
3533ee84446SAdrien Mazarguil 	    struct ibv_sge (*sges)[MLX5_PMD_SGE_WR_N])
3543ee84446SAdrien Mazarguil {
3553ee84446SAdrien Mazarguil 	unsigned int sent_size = 0;
3563ee84446SAdrien Mazarguil 	unsigned int j;
3573ee84446SAdrien Mazarguil 	int linearize = 0;
3583ee84446SAdrien Mazarguil 
3593ee84446SAdrien Mazarguil 	/* When there are too many segments, extra segments are
3603ee84446SAdrien Mazarguil 	 * linearized in the last SGE. */
3613ee84446SAdrien Mazarguil 	if (unlikely(segs > RTE_DIM(*sges))) {
3623ee84446SAdrien Mazarguil 		segs = (RTE_DIM(*sges) - 1);
3633ee84446SAdrien Mazarguil 		linearize = 1;
3643ee84446SAdrien Mazarguil 	}
3653ee84446SAdrien Mazarguil 	/* Update element. */
3663ee84446SAdrien Mazarguil 	elt->buf = buf;
3673ee84446SAdrien Mazarguil 	/* Register segments as SGEs. */
3683ee84446SAdrien Mazarguil 	for (j = 0; (j != segs); ++j) {
3693ee84446SAdrien Mazarguil 		struct ibv_sge *sge = &(*sges)[j];
3703ee84446SAdrien Mazarguil 		uint32_t lkey;
3713ee84446SAdrien Mazarguil 
3723ee84446SAdrien Mazarguil 		/* Retrieve Memory Region key for this memory pool. */
3738340392eSAdrien Mazarguil 		lkey = txq_mp2mr(txq, txq_mb2mp(buf));
3743ee84446SAdrien Mazarguil 		if (unlikely(lkey == (uint32_t)-1)) {
3753ee84446SAdrien Mazarguil 			/* MR does not exist. */
3763ee84446SAdrien Mazarguil 			DEBUG("%p: unable to get MP <-> MR association",
3773ee84446SAdrien Mazarguil 			      (void *)txq);
3783ee84446SAdrien Mazarguil 			/* Clean up TX element. */
3793ee84446SAdrien Mazarguil 			elt->buf = NULL;
3803ee84446SAdrien Mazarguil 			goto stop;
3813ee84446SAdrien Mazarguil 		}
3823ee84446SAdrien Mazarguil 		/* Update SGE. */
3833ee84446SAdrien Mazarguil 		sge->addr = rte_pktmbuf_mtod(buf, uintptr_t);
3843ee84446SAdrien Mazarguil 		if (txq->priv->vf)
3853ee84446SAdrien Mazarguil 			rte_prefetch0((volatile void *)
3863ee84446SAdrien Mazarguil 				      (uintptr_t)sge->addr);
3873ee84446SAdrien Mazarguil 		sge->length = DATA_LEN(buf);
3883ee84446SAdrien Mazarguil 		sge->lkey = lkey;
3893ee84446SAdrien Mazarguil 		sent_size += sge->length;
3903ee84446SAdrien Mazarguil 		buf = NEXT(buf);
3913ee84446SAdrien Mazarguil 	}
3923ee84446SAdrien Mazarguil 	/* If buf is not NULL here and is not going to be linearized,
3933ee84446SAdrien Mazarguil 	 * nb_segs is not valid. */
3943ee84446SAdrien Mazarguil 	assert(j == segs);
3953ee84446SAdrien Mazarguil 	assert((buf == NULL) || (linearize));
3963ee84446SAdrien Mazarguil 	/* Linearize extra segments. */
3973ee84446SAdrien Mazarguil 	if (linearize) {
3983ee84446SAdrien Mazarguil 		struct ibv_sge *sge = &(*sges)[segs];
3993ee84446SAdrien Mazarguil 		linear_t *linear = &(*txq->elts_linear)[elts_head];
4003ee84446SAdrien Mazarguil 		unsigned int size = linearize_mbuf(linear, buf);
4013ee84446SAdrien Mazarguil 
4023ee84446SAdrien Mazarguil 		assert(segs == (RTE_DIM(*sges) - 1));
4033ee84446SAdrien Mazarguil 		if (size == 0) {
4043ee84446SAdrien Mazarguil 			/* Invalid packet. */
4053ee84446SAdrien Mazarguil 			DEBUG("%p: packet too large to be linearized.",
4063ee84446SAdrien Mazarguil 			      (void *)txq);
4073ee84446SAdrien Mazarguil 			/* Clean up TX element. */
4083ee84446SAdrien Mazarguil 			elt->buf = NULL;
4093ee84446SAdrien Mazarguil 			goto stop;
4103ee84446SAdrien Mazarguil 		}
4113ee84446SAdrien Mazarguil 		/* If MLX5_PMD_SGE_WR_N is 1, free mbuf immediately. */
4123ee84446SAdrien Mazarguil 		if (RTE_DIM(*sges) == 1) {
4133ee84446SAdrien Mazarguil 			do {
4143ee84446SAdrien Mazarguil 				struct rte_mbuf *next = NEXT(buf);
4153ee84446SAdrien Mazarguil 
4163ee84446SAdrien Mazarguil 				rte_pktmbuf_free_seg(buf);
4173ee84446SAdrien Mazarguil 				buf = next;
4183ee84446SAdrien Mazarguil 			} while (buf != NULL);
4193ee84446SAdrien Mazarguil 			elt->buf = NULL;
4203ee84446SAdrien Mazarguil 		}
4213ee84446SAdrien Mazarguil 		/* Update SGE. */
4223ee84446SAdrien Mazarguil 		sge->addr = (uintptr_t)&(*linear)[0];
4233ee84446SAdrien Mazarguil 		sge->length = size;
4243ee84446SAdrien Mazarguil 		sge->lkey = txq->mr_linear->lkey;
4253ee84446SAdrien Mazarguil 		sent_size += size;
42634d06263SAdrien Mazarguil 		/* Include last segment. */
42734d06263SAdrien Mazarguil 		segs++;
4283ee84446SAdrien Mazarguil 	}
4293ee84446SAdrien Mazarguil 	return (struct tx_burst_sg_ret){
4303ee84446SAdrien Mazarguil 		.length = sent_size,
4313ee84446SAdrien Mazarguil 		.num = segs,
4323ee84446SAdrien Mazarguil 	};
4333ee84446SAdrien Mazarguil stop:
4343ee84446SAdrien Mazarguil 	return (struct tx_burst_sg_ret){
4353ee84446SAdrien Mazarguil 		.length = -1,
4363ee84446SAdrien Mazarguil 		.num = -1,
4373ee84446SAdrien Mazarguil 	};
4383ee84446SAdrien Mazarguil }
4393ee84446SAdrien Mazarguil 
4403ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */
4413ee84446SAdrien Mazarguil 
4422e22920bSAdrien Mazarguil /**
4432e22920bSAdrien Mazarguil  * DPDK callback for TX.
4442e22920bSAdrien Mazarguil  *
4452e22920bSAdrien Mazarguil  * @param dpdk_txq
4462e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
4472e22920bSAdrien Mazarguil  * @param[in] pkts
4482e22920bSAdrien Mazarguil  *   Packets to transmit.
4492e22920bSAdrien Mazarguil  * @param pkts_n
4502e22920bSAdrien Mazarguil  *   Number of packets in array.
4512e22920bSAdrien Mazarguil  *
4522e22920bSAdrien Mazarguil  * @return
4532e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
4542e22920bSAdrien Mazarguil  */
4552e22920bSAdrien Mazarguil uint16_t
4562e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
4572e22920bSAdrien Mazarguil {
4582e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
4592e22920bSAdrien Mazarguil 	unsigned int elts_head = txq->elts_head;
4602e22920bSAdrien Mazarguil 	const unsigned int elts_n = txq->elts_n;
4612e22920bSAdrien Mazarguil 	unsigned int elts_comp_cd = txq->elts_comp_cd;
4622e22920bSAdrien Mazarguil 	unsigned int elts_comp = 0;
4632e22920bSAdrien Mazarguil 	unsigned int i;
4642e22920bSAdrien Mazarguil 	unsigned int max;
4652e22920bSAdrien Mazarguil 	int err;
4665e1d11ecSNelio Laranjeiro 	struct rte_mbuf *buf = pkts[0];
4672e22920bSAdrien Mazarguil 
4682e22920bSAdrien Mazarguil 	assert(elts_comp_cd != 0);
4695e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
4705e1d11ecSNelio Laranjeiro 	rte_prefetch0(buf);
4712e22920bSAdrien Mazarguil 	txq_complete(txq);
4724f52bbfbSNelio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
4732e22920bSAdrien Mazarguil 	if (max > elts_n)
4742e22920bSAdrien Mazarguil 		max -= elts_n;
4752e22920bSAdrien Mazarguil 	assert(max >= 1);
4762e22920bSAdrien Mazarguil 	assert(max <= elts_n);
4772e22920bSAdrien Mazarguil 	/* Always leave one free entry in the ring. */
4782e22920bSAdrien Mazarguil 	--max;
4792e22920bSAdrien Mazarguil 	if (max == 0)
4802e22920bSAdrien Mazarguil 		return 0;
4812e22920bSAdrien Mazarguil 	if (max > pkts_n)
4822e22920bSAdrien Mazarguil 		max = pkts_n;
4832e22920bSAdrien Mazarguil 	for (i = 0; (i != max); ++i) {
4845e1d11ecSNelio Laranjeiro 		struct rte_mbuf *buf_next = pkts[i + 1];
4852e22920bSAdrien Mazarguil 		unsigned int elts_head_next =
4862e22920bSAdrien Mazarguil 			(((elts_head + 1) == elts_n) ? 0 : elts_head + 1);
4872e22920bSAdrien Mazarguil 		struct txq_elt *elt = &(*txq->elts)[elts_head];
4882e22920bSAdrien Mazarguil 		unsigned int segs = NB_SEGS(buf);
48987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
49087011737SAdrien Mazarguil 		unsigned int sent_size = 0;
49187011737SAdrien Mazarguil #endif
4922e22920bSAdrien Mazarguil 		uint32_t send_flags = 0;
4932e22920bSAdrien Mazarguil 
4945e1d11ecSNelio Laranjeiro 		if (i + 1 < max)
4955e1d11ecSNelio Laranjeiro 			rte_prefetch0(buf_next);
4962e22920bSAdrien Mazarguil 		/* Request TX completion. */
4972e22920bSAdrien Mazarguil 		if (unlikely(--elts_comp_cd == 0)) {
4982e22920bSAdrien Mazarguil 			elts_comp_cd = txq->elts_comp_cd_init;
4992e22920bSAdrien Mazarguil 			++elts_comp;
5002e22920bSAdrien Mazarguil 			send_flags |= IBV_EXP_QP_BURST_SIGNALED;
5012e22920bSAdrien Mazarguil 		}
50267fa62bcSAdrien Mazarguil 		/* Should we enable HW CKSUM offload */
50367fa62bcSAdrien Mazarguil 		if (buf->ol_flags &
50467fa62bcSAdrien Mazarguil 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
50567fa62bcSAdrien Mazarguil 			send_flags |= IBV_EXP_QP_BURST_IP_CSUM;
50667fa62bcSAdrien Mazarguil 			/* HW does not support checksum offloads at arbitrary
50767fa62bcSAdrien Mazarguil 			 * offsets but automatically recognizes the packet
50867fa62bcSAdrien Mazarguil 			 * type. For inner L3/L4 checksums, only VXLAN (UDP)
50967fa62bcSAdrien Mazarguil 			 * tunnels are currently supported. */
51067fa62bcSAdrien Mazarguil 			if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type))
51167fa62bcSAdrien Mazarguil 				send_flags |= IBV_EXP_QP_BURST_TUNNEL;
51267fa62bcSAdrien Mazarguil 		}
5132e22920bSAdrien Mazarguil 		if (likely(segs == 1)) {
5142e22920bSAdrien Mazarguil 			uintptr_t addr;
5152e22920bSAdrien Mazarguil 			uint32_t length;
5162e22920bSAdrien Mazarguil 			uint32_t lkey;
5175e1d11ecSNelio Laranjeiro 			uintptr_t buf_next_addr;
5182e22920bSAdrien Mazarguil 
5192e22920bSAdrien Mazarguil 			/* Retrieve buffer information. */
5202e22920bSAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
5212e22920bSAdrien Mazarguil 			length = DATA_LEN(buf);
5222e22920bSAdrien Mazarguil 			/* Update element. */
5232e22920bSAdrien Mazarguil 			elt->buf = buf;
5242e22920bSAdrien Mazarguil 			if (txq->priv->vf)
5252e22920bSAdrien Mazarguil 				rte_prefetch0((volatile void *)
5262e22920bSAdrien Mazarguil 					      (uintptr_t)addr);
5275e1d11ecSNelio Laranjeiro 			/* Prefetch next buffer data. */
5285e1d11ecSNelio Laranjeiro 			if (i + 1 < max) {
5295e1d11ecSNelio Laranjeiro 				buf_next_addr =
5305e1d11ecSNelio Laranjeiro 					rte_pktmbuf_mtod(buf_next, uintptr_t);
5315e1d11ecSNelio Laranjeiro 				rte_prefetch0((volatile void *)
5325e1d11ecSNelio Laranjeiro 					      (uintptr_t)buf_next_addr);
5335e1d11ecSNelio Laranjeiro 			}
5342e22920bSAdrien Mazarguil 			/* Put packet into send queue. */
5352e22920bSAdrien Mazarguil #if MLX5_PMD_MAX_INLINE > 0
5362e22920bSAdrien Mazarguil 			if (length <= txq->max_inline)
537e1682023SNelio Laranjeiro 				err = txq->send_pending_inline
5382e22920bSAdrien Mazarguil 					(txq->qp,
5392e22920bSAdrien Mazarguil 					 (void *)addr,
5402e22920bSAdrien Mazarguil 					 length,
5412e22920bSAdrien Mazarguil 					 send_flags);
5422e22920bSAdrien Mazarguil 			else
5432e22920bSAdrien Mazarguil #endif
544d970e992SNelio Laranjeiro 			{
545d970e992SNelio Laranjeiro 				/* Retrieve Memory Region key for this
546d970e992SNelio Laranjeiro 				 * memory pool. */
547d970e992SNelio Laranjeiro 				lkey = txq_mp2mr(txq, txq_mb2mp(buf));
548d970e992SNelio Laranjeiro 				if (unlikely(lkey == (uint32_t)-1)) {
549d970e992SNelio Laranjeiro 					/* MR does not exist. */
550d970e992SNelio Laranjeiro 					DEBUG("%p: unable to get MP <-> MR"
551d970e992SNelio Laranjeiro 					      " association", (void *)txq);
552d970e992SNelio Laranjeiro 					/* Clean up TX element. */
553d970e992SNelio Laranjeiro 					elt->buf = NULL;
554d970e992SNelio Laranjeiro 					goto stop;
555d970e992SNelio Laranjeiro 				}
556e1682023SNelio Laranjeiro 				err = txq->send_pending
5572e22920bSAdrien Mazarguil 					(txq->qp,
5582e22920bSAdrien Mazarguil 					 addr,
5592e22920bSAdrien Mazarguil 					 length,
5602e22920bSAdrien Mazarguil 					 lkey,
5612e22920bSAdrien Mazarguil 					 send_flags);
562d970e992SNelio Laranjeiro 			}
5632e22920bSAdrien Mazarguil 			if (unlikely(err))
5642e22920bSAdrien Mazarguil 				goto stop;
56587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
56687011737SAdrien Mazarguil 			sent_size += length;
56787011737SAdrien Mazarguil #endif
5682e22920bSAdrien Mazarguil 		} else {
5693ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1
5703ee84446SAdrien Mazarguil 			struct ibv_sge sges[MLX5_PMD_SGE_WR_N];
5713ee84446SAdrien Mazarguil 			struct tx_burst_sg_ret ret;
5723ee84446SAdrien Mazarguil 
5733ee84446SAdrien Mazarguil 			ret = tx_burst_sg(txq, segs, elt, buf, elts_head,
5743ee84446SAdrien Mazarguil 					  &sges);
5753ee84446SAdrien Mazarguil 			if (ret.length == (unsigned int)-1)
5763ee84446SAdrien Mazarguil 				goto stop;
5773ee84446SAdrien Mazarguil 			/* Put SG list into send queue. */
578e1682023SNelio Laranjeiro 			err = txq->send_pending_sg_list
5793ee84446SAdrien Mazarguil 				(txq->qp,
5803ee84446SAdrien Mazarguil 				 sges,
5813ee84446SAdrien Mazarguil 				 ret.num,
5823ee84446SAdrien Mazarguil 				 send_flags);
5833ee84446SAdrien Mazarguil 			if (unlikely(err))
5843ee84446SAdrien Mazarguil 				goto stop;
58587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
58687011737SAdrien Mazarguil 			sent_size += ret.length;
58787011737SAdrien Mazarguil #endif
5883ee84446SAdrien Mazarguil #else /* MLX5_PMD_SGE_WR_N > 1 */
5892e22920bSAdrien Mazarguil 			DEBUG("%p: TX scattered buffers support not"
5902e22920bSAdrien Mazarguil 			      " compiled in", (void *)txq);
5912e22920bSAdrien Mazarguil 			goto stop;
5923ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */
5932e22920bSAdrien Mazarguil 		}
5942e22920bSAdrien Mazarguil 		elts_head = elts_head_next;
5955e1d11ecSNelio Laranjeiro 		buf = buf_next;
59687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
59787011737SAdrien Mazarguil 		/* Increment sent bytes counter. */
59887011737SAdrien Mazarguil 		txq->stats.obytes += sent_size;
59987011737SAdrien Mazarguil #endif
6002e22920bSAdrien Mazarguil 	}
6012e22920bSAdrien Mazarguil stop:
6022e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
6032e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
6042e22920bSAdrien Mazarguil 		return 0;
60587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
60687011737SAdrien Mazarguil 	/* Increment sent packets counter. */
60787011737SAdrien Mazarguil 	txq->stats.opackets += i;
60887011737SAdrien Mazarguil #endif
6092e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
610e1682023SNelio Laranjeiro 	err = txq->send_flush(txq->qp);
6112e22920bSAdrien Mazarguil 	if (unlikely(err)) {
6122e22920bSAdrien Mazarguil 		/* A nonzero value is not supposed to be returned.
6132e22920bSAdrien Mazarguil 		 * Nothing can be done about it. */
6142e22920bSAdrien Mazarguil 		DEBUG("%p: send_flush() failed with error %d",
6152e22920bSAdrien Mazarguil 		      (void *)txq, err);
6162e22920bSAdrien Mazarguil 	}
6172e22920bSAdrien Mazarguil 	txq->elts_head = elts_head;
6182e22920bSAdrien Mazarguil 	txq->elts_comp += elts_comp;
6192e22920bSAdrien Mazarguil 	txq->elts_comp_cd = elts_comp_cd;
6202e22920bSAdrien Mazarguil 	return i;
6212e22920bSAdrien Mazarguil }
6222e22920bSAdrien Mazarguil 
6232e22920bSAdrien Mazarguil /**
62467fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
62567fa62bcSAdrien Mazarguil  *
62667fa62bcSAdrien Mazarguil  * @param flags
62767fa62bcSAdrien Mazarguil  *   RX completion flags returned by poll_length_flags().
62867fa62bcSAdrien Mazarguil  *
62967fa62bcSAdrien Mazarguil  * @return
63067fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
63167fa62bcSAdrien Mazarguil  */
63267fa62bcSAdrien Mazarguil static inline uint32_t
63367fa62bcSAdrien Mazarguil rxq_cq_to_pkt_type(uint32_t flags)
63467fa62bcSAdrien Mazarguil {
63567fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
63667fa62bcSAdrien Mazarguil 
63767fa62bcSAdrien Mazarguil 	if (flags & IBV_EXP_CQ_RX_TUNNEL_PACKET)
63867fa62bcSAdrien Mazarguil 		pkt_type =
63967fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
64067fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV4_PACKET,
64167fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
64267fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
64367fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV6_PACKET,
64467fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6) |
64567fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
64667fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV4_PACKET,
64767fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV4) |
64867fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
64967fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV6_PACKET,
65067fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV6);
65167fa62bcSAdrien Mazarguil 	else
65267fa62bcSAdrien Mazarguil 		pkt_type =
65367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
65467fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV4_PACKET,
65567fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
65667fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
65767fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV6_PACKET,
65867fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6);
65967fa62bcSAdrien Mazarguil 	return pkt_type;
66067fa62bcSAdrien Mazarguil }
66167fa62bcSAdrien Mazarguil 
66267fa62bcSAdrien Mazarguil /**
66367fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
66467fa62bcSAdrien Mazarguil  *
66567fa62bcSAdrien Mazarguil  * @param[in] rxq
66667fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
66767fa62bcSAdrien Mazarguil  * @param flags
66867fa62bcSAdrien Mazarguil  *   RX completion flags returned by poll_length_flags().
66967fa62bcSAdrien Mazarguil  *
67067fa62bcSAdrien Mazarguil  * @return
67167fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
67267fa62bcSAdrien Mazarguil  */
67367fa62bcSAdrien Mazarguil static inline uint32_t
67467fa62bcSAdrien Mazarguil rxq_cq_to_ol_flags(const struct rxq *rxq, uint32_t flags)
67567fa62bcSAdrien Mazarguil {
67667fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
67767fa62bcSAdrien Mazarguil 
67867fa62bcSAdrien Mazarguil 	if (rxq->csum)
67967fa62bcSAdrien Mazarguil 		ol_flags |=
68067fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
68167fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IP_CSUM_OK,
68267fa62bcSAdrien Mazarguil 				  PKT_RX_IP_CKSUM_BAD) |
68367fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
68467fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_TCP_UDP_CSUM_OK,
68567fa62bcSAdrien Mazarguil 				  PKT_RX_L4_CKSUM_BAD);
68667fa62bcSAdrien Mazarguil 	/*
68767fa62bcSAdrien Mazarguil 	 * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place
68867fa62bcSAdrien Mazarguil 	 * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional
68967fa62bcSAdrien Mazarguil 	 * (its value is 0).
69067fa62bcSAdrien Mazarguil 	 */
69167fa62bcSAdrien Mazarguil 	if ((flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
69267fa62bcSAdrien Mazarguil 		ol_flags |=
69367fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
69467fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK,
69567fa62bcSAdrien Mazarguil 				  PKT_RX_IP_CKSUM_BAD) |
69667fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
69767fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK,
69867fa62bcSAdrien Mazarguil 				  PKT_RX_L4_CKSUM_BAD);
69967fa62bcSAdrien Mazarguil 	return ol_flags;
70067fa62bcSAdrien Mazarguil }
70167fa62bcSAdrien Mazarguil 
70267fa62bcSAdrien Mazarguil /**
7033ee84446SAdrien Mazarguil  * DPDK callback for RX with scattered packets support.
7043ee84446SAdrien Mazarguil  *
7053ee84446SAdrien Mazarguil  * @param dpdk_rxq
7063ee84446SAdrien Mazarguil  *   Generic pointer to RX queue structure.
7073ee84446SAdrien Mazarguil  * @param[out] pkts
7083ee84446SAdrien Mazarguil  *   Array to store received packets.
7093ee84446SAdrien Mazarguil  * @param pkts_n
7103ee84446SAdrien Mazarguil  *   Maximum number of packets in array.
7113ee84446SAdrien Mazarguil  *
7123ee84446SAdrien Mazarguil  * @return
7133ee84446SAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
7143ee84446SAdrien Mazarguil  */
7153ee84446SAdrien Mazarguil uint16_t
7163ee84446SAdrien Mazarguil mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
7173ee84446SAdrien Mazarguil {
7183ee84446SAdrien Mazarguil 	struct rxq *rxq = (struct rxq *)dpdk_rxq;
7193ee84446SAdrien Mazarguil 	struct rxq_elt_sp (*elts)[rxq->elts_n] = rxq->elts.sp;
7203ee84446SAdrien Mazarguil 	const unsigned int elts_n = rxq->elts_n;
7213ee84446SAdrien Mazarguil 	unsigned int elts_head = rxq->elts_head;
7223ee84446SAdrien Mazarguil 	unsigned int i;
7233ee84446SAdrien Mazarguil 	unsigned int pkts_ret = 0;
7243ee84446SAdrien Mazarguil 	int ret;
7253ee84446SAdrien Mazarguil 
7263ee84446SAdrien Mazarguil 	if (unlikely(!rxq->sp))
7273ee84446SAdrien Mazarguil 		return mlx5_rx_burst(dpdk_rxq, pkts, pkts_n);
7283ee84446SAdrien Mazarguil 	if (unlikely(elts == NULL)) /* See RTE_DEV_CMD_SET_MTU. */
7293ee84446SAdrien Mazarguil 		return 0;
7303ee84446SAdrien Mazarguil 	for (i = 0; (i != pkts_n); ++i) {
7313ee84446SAdrien Mazarguil 		struct rxq_elt_sp *elt = &(*elts)[elts_head];
7323ee84446SAdrien Mazarguil 		unsigned int len;
7333ee84446SAdrien Mazarguil 		unsigned int pkt_buf_len;
7343ee84446SAdrien Mazarguil 		struct rte_mbuf *pkt_buf = NULL; /* Buffer returned in pkts. */
7353ee84446SAdrien Mazarguil 		struct rte_mbuf **pkt_buf_next = &pkt_buf;
7363ee84446SAdrien Mazarguil 		unsigned int seg_headroom = RTE_PKTMBUF_HEADROOM;
7373ee84446SAdrien Mazarguil 		unsigned int j = 0;
7383ee84446SAdrien Mazarguil 		uint32_t flags;
739f3db9489SYaacov Hazan 		uint16_t vlan_tci;
7403ee84446SAdrien Mazarguil 
7413ee84446SAdrien Mazarguil 		/* Sanity checks. */
7423ee84446SAdrien Mazarguil 		assert(elts_head < rxq->elts_n);
7433ee84446SAdrien Mazarguil 		assert(rxq->elts_head < rxq->elts_n);
744e1682023SNelio Laranjeiro 		ret = rxq->poll(rxq->cq, NULL, NULL, &flags, &vlan_tci);
7453ee84446SAdrien Mazarguil 		if (unlikely(ret < 0)) {
7463ee84446SAdrien Mazarguil 			struct ibv_wc wc;
7473ee84446SAdrien Mazarguil 			int wcs_n;
7483ee84446SAdrien Mazarguil 
7493ee84446SAdrien Mazarguil 			DEBUG("rxq=%p, poll_length() failed (ret=%d)",
7503ee84446SAdrien Mazarguil 			      (void *)rxq, ret);
7513ee84446SAdrien Mazarguil 			/* ibv_poll_cq() must be used in case of failure. */
7523ee84446SAdrien Mazarguil 			wcs_n = ibv_poll_cq(rxq->cq, 1, &wc);
7533ee84446SAdrien Mazarguil 			if (unlikely(wcs_n == 0))
7543ee84446SAdrien Mazarguil 				break;
7553ee84446SAdrien Mazarguil 			if (unlikely(wcs_n < 0)) {
7563ee84446SAdrien Mazarguil 				DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)",
7573ee84446SAdrien Mazarguil 				      (void *)rxq, wcs_n);
7583ee84446SAdrien Mazarguil 				break;
7593ee84446SAdrien Mazarguil 			}
7603ee84446SAdrien Mazarguil 			assert(wcs_n == 1);
7613ee84446SAdrien Mazarguil 			if (unlikely(wc.status != IBV_WC_SUCCESS)) {
7623ee84446SAdrien Mazarguil 				/* Whatever, just repost the offending WR. */
7633ee84446SAdrien Mazarguil 				DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work"
7643ee84446SAdrien Mazarguil 				      " completion status (%d): %s",
7653ee84446SAdrien Mazarguil 				      (void *)rxq, wc.wr_id, wc.status,
7663ee84446SAdrien Mazarguil 				      ibv_wc_status_str(wc.status));
76787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
76887011737SAdrien Mazarguil 				/* Increment dropped packets counter. */
76987011737SAdrien Mazarguil 				++rxq->stats.idropped;
77087011737SAdrien Mazarguil #endif
7713ee84446SAdrien Mazarguil 				goto repost;
7723ee84446SAdrien Mazarguil 			}
7733ee84446SAdrien Mazarguil 			ret = wc.byte_len;
7743ee84446SAdrien Mazarguil 		}
7753ee84446SAdrien Mazarguil 		if (ret == 0)
7763ee84446SAdrien Mazarguil 			break;
7773ee84446SAdrien Mazarguil 		len = ret;
7783ee84446SAdrien Mazarguil 		pkt_buf_len = len;
7793ee84446SAdrien Mazarguil 		/*
7803ee84446SAdrien Mazarguil 		 * Replace spent segments with new ones, concatenate and
7813ee84446SAdrien Mazarguil 		 * return them as pkt_buf.
7823ee84446SAdrien Mazarguil 		 */
7833ee84446SAdrien Mazarguil 		while (1) {
7843ee84446SAdrien Mazarguil 			struct ibv_sge *sge = &elt->sges[j];
7853ee84446SAdrien Mazarguil 			struct rte_mbuf *seg = elt->bufs[j];
7863ee84446SAdrien Mazarguil 			struct rte_mbuf *rep;
7873ee84446SAdrien Mazarguil 			unsigned int seg_tailroom;
7883ee84446SAdrien Mazarguil 
789aa7f63abSAdrien Mazarguil 			assert(seg != NULL);
7903ee84446SAdrien Mazarguil 			/*
7913ee84446SAdrien Mazarguil 			 * Fetch initial bytes of packet descriptor into a
7923ee84446SAdrien Mazarguil 			 * cacheline while allocating rep.
7933ee84446SAdrien Mazarguil 			 */
7943ee84446SAdrien Mazarguil 			rte_prefetch0(seg);
7953ee84446SAdrien Mazarguil 			rep = __rte_mbuf_raw_alloc(rxq->mp);
7963ee84446SAdrien Mazarguil 			if (unlikely(rep == NULL)) {
7973ee84446SAdrien Mazarguil 				/*
7983ee84446SAdrien Mazarguil 				 * Unable to allocate a replacement mbuf,
7993ee84446SAdrien Mazarguil 				 * repost WR.
8003ee84446SAdrien Mazarguil 				 */
801aa7f63abSAdrien Mazarguil 				DEBUG("rxq=%p: can't allocate a new mbuf",
802aa7f63abSAdrien Mazarguil 				      (void *)rxq);
8033ee84446SAdrien Mazarguil 				if (pkt_buf != NULL) {
8043ee84446SAdrien Mazarguil 					*pkt_buf_next = NULL;
8053ee84446SAdrien Mazarguil 					rte_pktmbuf_free(pkt_buf);
8063ee84446SAdrien Mazarguil 				}
8073ee84446SAdrien Mazarguil 				/* Increment out of memory counters. */
80887011737SAdrien Mazarguil 				++rxq->stats.rx_nombuf;
8093ee84446SAdrien Mazarguil 				++rxq->priv->dev->data->rx_mbuf_alloc_failed;
8103ee84446SAdrien Mazarguil 				goto repost;
8113ee84446SAdrien Mazarguil 			}
8123ee84446SAdrien Mazarguil #ifndef NDEBUG
8133ee84446SAdrien Mazarguil 			/* Poison user-modifiable fields in rep. */
8143ee84446SAdrien Mazarguil 			NEXT(rep) = (void *)((uintptr_t)-1);
8153ee84446SAdrien Mazarguil 			SET_DATA_OFF(rep, 0xdead);
8163ee84446SAdrien Mazarguil 			DATA_LEN(rep) = 0xd00d;
8173ee84446SAdrien Mazarguil 			PKT_LEN(rep) = 0xdeadd00d;
8183ee84446SAdrien Mazarguil 			NB_SEGS(rep) = 0x2a;
8193ee84446SAdrien Mazarguil 			PORT(rep) = 0x2a;
8203ee84446SAdrien Mazarguil 			rep->ol_flags = -1;
8213ee84446SAdrien Mazarguil #endif
8223ee84446SAdrien Mazarguil 			assert(rep->buf_len == seg->buf_len);
8233ee84446SAdrien Mazarguil 			assert(rep->buf_len == rxq->mb_len);
8243ee84446SAdrien Mazarguil 			/* Reconfigure sge to use rep instead of seg. */
8253ee84446SAdrien Mazarguil 			assert(sge->lkey == rxq->mr->lkey);
8263ee84446SAdrien Mazarguil 			sge->addr = ((uintptr_t)rep->buf_addr + seg_headroom);
8273ee84446SAdrien Mazarguil 			elt->bufs[j] = rep;
8283ee84446SAdrien Mazarguil 			++j;
8293ee84446SAdrien Mazarguil 			/* Update pkt_buf if it's the first segment, or link
8303ee84446SAdrien Mazarguil 			 * seg to the previous one and update pkt_buf_next. */
8313ee84446SAdrien Mazarguil 			*pkt_buf_next = seg;
8323ee84446SAdrien Mazarguil 			pkt_buf_next = &NEXT(seg);
8333ee84446SAdrien Mazarguil 			/* Update seg information. */
8343ee84446SAdrien Mazarguil 			seg_tailroom = (seg->buf_len - seg_headroom);
8353ee84446SAdrien Mazarguil 			assert(sge->length == seg_tailroom);
8363ee84446SAdrien Mazarguil 			SET_DATA_OFF(seg, seg_headroom);
8373ee84446SAdrien Mazarguil 			if (likely(len <= seg_tailroom)) {
8383ee84446SAdrien Mazarguil 				/* Last segment. */
8393ee84446SAdrien Mazarguil 				DATA_LEN(seg) = len;
8403ee84446SAdrien Mazarguil 				PKT_LEN(seg) = len;
8413ee84446SAdrien Mazarguil 				/* Sanity check. */
8423ee84446SAdrien Mazarguil 				assert(rte_pktmbuf_headroom(seg) ==
8433ee84446SAdrien Mazarguil 				       seg_headroom);
8443ee84446SAdrien Mazarguil 				assert(rte_pktmbuf_tailroom(seg) ==
8453ee84446SAdrien Mazarguil 				       (seg_tailroom - len));
8463ee84446SAdrien Mazarguil 				break;
8473ee84446SAdrien Mazarguil 			}
8483ee84446SAdrien Mazarguil 			DATA_LEN(seg) = seg_tailroom;
8493ee84446SAdrien Mazarguil 			PKT_LEN(seg) = seg_tailroom;
8503ee84446SAdrien Mazarguil 			/* Sanity check. */
8513ee84446SAdrien Mazarguil 			assert(rte_pktmbuf_headroom(seg) == seg_headroom);
8523ee84446SAdrien Mazarguil 			assert(rte_pktmbuf_tailroom(seg) == 0);
8533ee84446SAdrien Mazarguil 			/* Fix len and clear headroom for next segments. */
8543ee84446SAdrien Mazarguil 			len -= seg_tailroom;
8553ee84446SAdrien Mazarguil 			seg_headroom = 0;
8563ee84446SAdrien Mazarguil 		}
8573ee84446SAdrien Mazarguil 		/* Update head and tail segments. */
8583ee84446SAdrien Mazarguil 		*pkt_buf_next = NULL;
8593ee84446SAdrien Mazarguil 		assert(pkt_buf != NULL);
8603ee84446SAdrien Mazarguil 		assert(j != 0);
8613ee84446SAdrien Mazarguil 		NB_SEGS(pkt_buf) = j;
8623ee84446SAdrien Mazarguil 		PORT(pkt_buf) = rxq->port_id;
8633ee84446SAdrien Mazarguil 		PKT_LEN(pkt_buf) = pkt_buf_len;
864081f7eaeSNelio Laranjeiro 		if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip) {
86567fa62bcSAdrien Mazarguil 			pkt_buf->packet_type = rxq_cq_to_pkt_type(flags);
86667fa62bcSAdrien Mazarguil 			pkt_buf->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
867f3db9489SYaacov Hazan #ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
868f3db9489SYaacov Hazan 			if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
869f3db9489SYaacov Hazan 				pkt_buf->ol_flags |= PKT_RX_VLAN_PKT;
870f3db9489SYaacov Hazan 				pkt_buf->vlan_tci = vlan_tci;
871f3db9489SYaacov Hazan 			}
872f3db9489SYaacov Hazan #endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
873081f7eaeSNelio Laranjeiro 		}
8743ee84446SAdrien Mazarguil 
8753ee84446SAdrien Mazarguil 		/* Return packet. */
8763ee84446SAdrien Mazarguil 		*(pkts++) = pkt_buf;
8773ee84446SAdrien Mazarguil 		++pkts_ret;
87887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
87987011737SAdrien Mazarguil 		/* Increment bytes counter. */
88087011737SAdrien Mazarguil 		rxq->stats.ibytes += pkt_buf_len;
88187011737SAdrien Mazarguil #endif
8823ee84446SAdrien Mazarguil repost:
883e1682023SNelio Laranjeiro 		ret = rxq->recv(rxq->wq, elt->sges, RTE_DIM(elt->sges));
88461bdf1e0SAdrien Mazarguil 		if (unlikely(ret)) {
88561bdf1e0SAdrien Mazarguil 			/* Inability to repost WRs is fatal. */
88661bdf1e0SAdrien Mazarguil 			DEBUG("%p: recv_sg_list(): failed (ret=%d)",
88761bdf1e0SAdrien Mazarguil 			      (void *)rxq->priv,
88861bdf1e0SAdrien Mazarguil 			      ret);
88961bdf1e0SAdrien Mazarguil 			abort();
89061bdf1e0SAdrien Mazarguil 		}
8913ee84446SAdrien Mazarguil 		if (++elts_head >= elts_n)
8923ee84446SAdrien Mazarguil 			elts_head = 0;
8933ee84446SAdrien Mazarguil 		continue;
8943ee84446SAdrien Mazarguil 	}
8953ee84446SAdrien Mazarguil 	if (unlikely(i == 0))
8963ee84446SAdrien Mazarguil 		return 0;
8973ee84446SAdrien Mazarguil 	rxq->elts_head = elts_head;
89887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
89987011737SAdrien Mazarguil 	/* Increment packets counter. */
90087011737SAdrien Mazarguil 	rxq->stats.ipackets += pkts_ret;
90187011737SAdrien Mazarguil #endif
9023ee84446SAdrien Mazarguil 	return pkts_ret;
9033ee84446SAdrien Mazarguil }
9043ee84446SAdrien Mazarguil 
9053ee84446SAdrien Mazarguil /**
9062e22920bSAdrien Mazarguil  * DPDK callback for RX.
9072e22920bSAdrien Mazarguil  *
9083ee84446SAdrien Mazarguil  * The following function is the same as mlx5_rx_burst_sp(), except it doesn't
9093ee84446SAdrien Mazarguil  * manage scattered packets. Improves performance when MRU is lower than the
9103ee84446SAdrien Mazarguil  * size of the first segment.
9113ee84446SAdrien Mazarguil  *
9122e22920bSAdrien Mazarguil  * @param dpdk_rxq
9132e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
9142e22920bSAdrien Mazarguil  * @param[out] pkts
9152e22920bSAdrien Mazarguil  *   Array to store received packets.
9162e22920bSAdrien Mazarguil  * @param pkts_n
9172e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
9182e22920bSAdrien Mazarguil  *
9192e22920bSAdrien Mazarguil  * @return
9202e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
9212e22920bSAdrien Mazarguil  */
9222e22920bSAdrien Mazarguil uint16_t
9232e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
9242e22920bSAdrien Mazarguil {
9252e22920bSAdrien Mazarguil 	struct rxq *rxq = (struct rxq *)dpdk_rxq;
9262e22920bSAdrien Mazarguil 	struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts.no_sp;
9272e22920bSAdrien Mazarguil 	const unsigned int elts_n = rxq->elts_n;
9282e22920bSAdrien Mazarguil 	unsigned int elts_head = rxq->elts_head;
9292e22920bSAdrien Mazarguil 	struct ibv_sge sges[pkts_n];
9302e22920bSAdrien Mazarguil 	unsigned int i;
9312e22920bSAdrien Mazarguil 	unsigned int pkts_ret = 0;
9322e22920bSAdrien Mazarguil 	int ret;
9332e22920bSAdrien Mazarguil 
9343ee84446SAdrien Mazarguil 	if (unlikely(rxq->sp))
9353ee84446SAdrien Mazarguil 		return mlx5_rx_burst_sp(dpdk_rxq, pkts, pkts_n);
9362e22920bSAdrien Mazarguil 	for (i = 0; (i != pkts_n); ++i) {
9372e22920bSAdrien Mazarguil 		struct rxq_elt *elt = &(*elts)[elts_head];
9382e22920bSAdrien Mazarguil 		unsigned int len;
939aa7f63abSAdrien Mazarguil 		struct rte_mbuf *seg = elt->buf;
9402e22920bSAdrien Mazarguil 		struct rte_mbuf *rep;
9412e22920bSAdrien Mazarguil 		uint32_t flags;
942f3db9489SYaacov Hazan 		uint16_t vlan_tci;
9432e22920bSAdrien Mazarguil 
9442e22920bSAdrien Mazarguil 		/* Sanity checks. */
945aa7f63abSAdrien Mazarguil 		assert(seg != NULL);
9462e22920bSAdrien Mazarguil 		assert(elts_head < rxq->elts_n);
9472e22920bSAdrien Mazarguil 		assert(rxq->elts_head < rxq->elts_n);
9482e22920bSAdrien Mazarguil 		/*
9492e22920bSAdrien Mazarguil 		 * Fetch initial bytes of packet descriptor into a
9502e22920bSAdrien Mazarguil 		 * cacheline while allocating rep.
9512e22920bSAdrien Mazarguil 		 */
9522e22920bSAdrien Mazarguil 		rte_prefetch0(seg);
9532e22920bSAdrien Mazarguil 		rte_prefetch0(&seg->cacheline1);
954e1682023SNelio Laranjeiro 		ret = rxq->poll(rxq->cq, NULL, NULL, &flags, &vlan_tci);
9552e22920bSAdrien Mazarguil 		if (unlikely(ret < 0)) {
9562e22920bSAdrien Mazarguil 			struct ibv_wc wc;
9572e22920bSAdrien Mazarguil 			int wcs_n;
9582e22920bSAdrien Mazarguil 
9592e22920bSAdrien Mazarguil 			DEBUG("rxq=%p, poll_length() failed (ret=%d)",
9602e22920bSAdrien Mazarguil 			      (void *)rxq, ret);
9612e22920bSAdrien Mazarguil 			/* ibv_poll_cq() must be used in case of failure. */
9622e22920bSAdrien Mazarguil 			wcs_n = ibv_poll_cq(rxq->cq, 1, &wc);
9632e22920bSAdrien Mazarguil 			if (unlikely(wcs_n == 0))
9642e22920bSAdrien Mazarguil 				break;
9652e22920bSAdrien Mazarguil 			if (unlikely(wcs_n < 0)) {
9662e22920bSAdrien Mazarguil 				DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)",
9672e22920bSAdrien Mazarguil 				      (void *)rxq, wcs_n);
9682e22920bSAdrien Mazarguil 				break;
9692e22920bSAdrien Mazarguil 			}
9702e22920bSAdrien Mazarguil 			assert(wcs_n == 1);
9712e22920bSAdrien Mazarguil 			if (unlikely(wc.status != IBV_WC_SUCCESS)) {
9722e22920bSAdrien Mazarguil 				/* Whatever, just repost the offending WR. */
9732e22920bSAdrien Mazarguil 				DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work"
9742e22920bSAdrien Mazarguil 				      " completion status (%d): %s",
9752e22920bSAdrien Mazarguil 				      (void *)rxq, wc.wr_id, wc.status,
9762e22920bSAdrien Mazarguil 				      ibv_wc_status_str(wc.status));
97787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
97887011737SAdrien Mazarguil 				/* Increment dropped packets counter. */
97987011737SAdrien Mazarguil 				++rxq->stats.idropped;
98087011737SAdrien Mazarguil #endif
9812e22920bSAdrien Mazarguil 				/* Add SGE to array for repost. */
9822e22920bSAdrien Mazarguil 				sges[i] = elt->sge;
9832e22920bSAdrien Mazarguil 				goto repost;
9842e22920bSAdrien Mazarguil 			}
9852e22920bSAdrien Mazarguil 			ret = wc.byte_len;
9862e22920bSAdrien Mazarguil 		}
9872e22920bSAdrien Mazarguil 		if (ret == 0)
9882e22920bSAdrien Mazarguil 			break;
9892e22920bSAdrien Mazarguil 		len = ret;
9902e22920bSAdrien Mazarguil 		rep = __rte_mbuf_raw_alloc(rxq->mp);
9912e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
9922e22920bSAdrien Mazarguil 			/*
9932e22920bSAdrien Mazarguil 			 * Unable to allocate a replacement mbuf,
9942e22920bSAdrien Mazarguil 			 * repost WR.
9952e22920bSAdrien Mazarguil 			 */
996aa7f63abSAdrien Mazarguil 			DEBUG("rxq=%p: can't allocate a new mbuf",
997aa7f63abSAdrien Mazarguil 			      (void *)rxq);
9982e22920bSAdrien Mazarguil 			/* Increment out of memory counters. */
99987011737SAdrien Mazarguil 			++rxq->stats.rx_nombuf;
10002e22920bSAdrien Mazarguil 			++rxq->priv->dev->data->rx_mbuf_alloc_failed;
10012e22920bSAdrien Mazarguil 			goto repost;
10022e22920bSAdrien Mazarguil 		}
10032e22920bSAdrien Mazarguil 
10042e22920bSAdrien Mazarguil 		/* Reconfigure sge to use rep instead of seg. */
10052e22920bSAdrien Mazarguil 		elt->sge.addr = (uintptr_t)rep->buf_addr + RTE_PKTMBUF_HEADROOM;
10062e22920bSAdrien Mazarguil 		assert(elt->sge.lkey == rxq->mr->lkey);
1007aa7f63abSAdrien Mazarguil 		elt->buf = rep;
10082e22920bSAdrien Mazarguil 
10092e22920bSAdrien Mazarguil 		/* Add SGE to array for repost. */
10102e22920bSAdrien Mazarguil 		sges[i] = elt->sge;
10112e22920bSAdrien Mazarguil 
10122e22920bSAdrien Mazarguil 		/* Update seg information. */
10132e22920bSAdrien Mazarguil 		SET_DATA_OFF(seg, RTE_PKTMBUF_HEADROOM);
10142e22920bSAdrien Mazarguil 		NB_SEGS(seg) = 1;
10152e22920bSAdrien Mazarguil 		PORT(seg) = rxq->port_id;
10162e22920bSAdrien Mazarguil 		NEXT(seg) = NULL;
10172e22920bSAdrien Mazarguil 		PKT_LEN(seg) = len;
10182e22920bSAdrien Mazarguil 		DATA_LEN(seg) = len;
1019081f7eaeSNelio Laranjeiro 		if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip) {
102067fa62bcSAdrien Mazarguil 			seg->packet_type = rxq_cq_to_pkt_type(flags);
102167fa62bcSAdrien Mazarguil 			seg->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
1022f3db9489SYaacov Hazan #ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
1023f3db9489SYaacov Hazan 			if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
1024f3db9489SYaacov Hazan 				seg->ol_flags |= PKT_RX_VLAN_PKT;
1025f3db9489SYaacov Hazan 				seg->vlan_tci = vlan_tci;
1026f3db9489SYaacov Hazan 			}
1027f3db9489SYaacov Hazan #endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
1028081f7eaeSNelio Laranjeiro 		}
10292e22920bSAdrien Mazarguil 		/* Return packet. */
10302e22920bSAdrien Mazarguil 		*(pkts++) = seg;
10312e22920bSAdrien Mazarguil 		++pkts_ret;
103287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
103387011737SAdrien Mazarguil 		/* Increment bytes counter. */
103487011737SAdrien Mazarguil 		rxq->stats.ibytes += len;
103587011737SAdrien Mazarguil #endif
10362e22920bSAdrien Mazarguil repost:
10372e22920bSAdrien Mazarguil 		if (++elts_head >= elts_n)
10382e22920bSAdrien Mazarguil 			elts_head = 0;
10392e22920bSAdrien Mazarguil 		continue;
10402e22920bSAdrien Mazarguil 	}
10412e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
10422e22920bSAdrien Mazarguil 		return 0;
10432e22920bSAdrien Mazarguil 	/* Repost WRs. */
10442e22920bSAdrien Mazarguil #ifdef DEBUG_RECV
10452e22920bSAdrien Mazarguil 	DEBUG("%p: reposting %u WRs", (void *)rxq, i);
10462e22920bSAdrien Mazarguil #endif
1047e1682023SNelio Laranjeiro 	ret = rxq->recv(rxq->wq, sges, i);
10482e22920bSAdrien Mazarguil 	if (unlikely(ret)) {
10492e22920bSAdrien Mazarguil 		/* Inability to repost WRs is fatal. */
10502e22920bSAdrien Mazarguil 		DEBUG("%p: recv_burst(): failed (ret=%d)",
10512e22920bSAdrien Mazarguil 		      (void *)rxq->priv,
10522e22920bSAdrien Mazarguil 		      ret);
10532e22920bSAdrien Mazarguil 		abort();
10542e22920bSAdrien Mazarguil 	}
10552e22920bSAdrien Mazarguil 	rxq->elts_head = elts_head;
105687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
105787011737SAdrien Mazarguil 	/* Increment packets counter. */
105887011737SAdrien Mazarguil 	rxq->stats.ipackets += pkts_ret;
105987011737SAdrien Mazarguil #endif
10602e22920bSAdrien Mazarguil 	return pkts_ret;
10612e22920bSAdrien Mazarguil }
10622e22920bSAdrien Mazarguil 
10632e22920bSAdrien Mazarguil /**
10642e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
10652e22920bSAdrien Mazarguil  *
10662e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
10672e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
10682e22920bSAdrien Mazarguil  *
10692e22920bSAdrien Mazarguil  * @param dpdk_txq
10702e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
10712e22920bSAdrien Mazarguil  * @param[in] pkts
10722e22920bSAdrien Mazarguil  *   Packets to transmit.
10732e22920bSAdrien Mazarguil  * @param pkts_n
10742e22920bSAdrien Mazarguil  *   Number of packets in array.
10752e22920bSAdrien Mazarguil  *
10762e22920bSAdrien Mazarguil  * @return
10772e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
10782e22920bSAdrien Mazarguil  */
10792e22920bSAdrien Mazarguil uint16_t
10802e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
10812e22920bSAdrien Mazarguil {
10822e22920bSAdrien Mazarguil 	(void)dpdk_txq;
10832e22920bSAdrien Mazarguil 	(void)pkts;
10842e22920bSAdrien Mazarguil 	(void)pkts_n;
10852e22920bSAdrien Mazarguil 	return 0;
10862e22920bSAdrien Mazarguil }
10872e22920bSAdrien Mazarguil 
10882e22920bSAdrien Mazarguil /**
10892e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
10902e22920bSAdrien Mazarguil  *
10912e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
10922e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
10932e22920bSAdrien Mazarguil  *
10942e22920bSAdrien Mazarguil  * @param dpdk_rxq
10952e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
10962e22920bSAdrien Mazarguil  * @param[out] pkts
10972e22920bSAdrien Mazarguil  *   Array to store received packets.
10982e22920bSAdrien Mazarguil  * @param pkts_n
10992e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
11002e22920bSAdrien Mazarguil  *
11012e22920bSAdrien Mazarguil  * @return
11022e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
11032e22920bSAdrien Mazarguil  */
11042e22920bSAdrien Mazarguil uint16_t
11052e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
11062e22920bSAdrien Mazarguil {
11072e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
11082e22920bSAdrien Mazarguil 	(void)pkts;
11092e22920bSAdrien Mazarguil 	(void)pkts_n;
11102e22920bSAdrien Mazarguil 	return 0;
11112e22920bSAdrien Mazarguil }
1112