xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision d1d914ebbc2514f334a3ed24057e63c8bb76363d)
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>
580dc02ccaSAdrien Mazarguil #include <rte_memory.h>
592e22920bSAdrien Mazarguil #ifdef PEDANTIC
602e22920bSAdrien Mazarguil #pragma GCC diagnostic error "-pedantic"
612e22920bSAdrien Mazarguil #endif
622e22920bSAdrien Mazarguil 
632e22920bSAdrien Mazarguil #include "mlx5.h"
642e22920bSAdrien Mazarguil #include "mlx5_utils.h"
652e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
66f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
672e22920bSAdrien Mazarguil #include "mlx5_defs.h"
682e22920bSAdrien Mazarguil 
692e22920bSAdrien Mazarguil /**
702e22920bSAdrien Mazarguil  * Manage TX completions.
712e22920bSAdrien Mazarguil  *
722e22920bSAdrien Mazarguil  * When sending a burst, mlx5_tx_burst() posts several WRs.
732e22920bSAdrien Mazarguil  * To improve performance, a completion event is only required once every
742e22920bSAdrien Mazarguil  * MLX5_PMD_TX_PER_COMP_REQ sends. Doing so discards completion information
752e22920bSAdrien Mazarguil  * for other WRs, but this information would not be used anyway.
762e22920bSAdrien Mazarguil  *
772e22920bSAdrien Mazarguil  * @param txq
782e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
792e22920bSAdrien Mazarguil  *
802e22920bSAdrien Mazarguil  * @return
812e22920bSAdrien Mazarguil  *   0 on success, -1 on failure.
822e22920bSAdrien Mazarguil  */
832e22920bSAdrien Mazarguil static int
842e22920bSAdrien Mazarguil txq_complete(struct txq *txq)
852e22920bSAdrien Mazarguil {
862e22920bSAdrien Mazarguil 	unsigned int elts_comp = txq->elts_comp;
872e22920bSAdrien Mazarguil 	unsigned int elts_tail = txq->elts_tail;
88a859e8a9SNelio Laranjeiro 	unsigned int elts_free = txq->elts_tail;
892e22920bSAdrien Mazarguil 	const unsigned int elts_n = txq->elts_n;
902e22920bSAdrien Mazarguil 	int wcs_n;
912e22920bSAdrien Mazarguil 
922e22920bSAdrien Mazarguil 	if (unlikely(elts_comp == 0))
932e22920bSAdrien Mazarguil 		return 0;
942e22920bSAdrien Mazarguil #ifdef DEBUG_SEND
952e22920bSAdrien Mazarguil 	DEBUG("%p: processing %u work requests completions",
962e22920bSAdrien Mazarguil 	      (void *)txq, elts_comp);
972e22920bSAdrien Mazarguil #endif
98e1682023SNelio Laranjeiro 	wcs_n = txq->poll_cnt(txq->cq, elts_comp);
992e22920bSAdrien Mazarguil 	if (unlikely(wcs_n == 0))
1002e22920bSAdrien Mazarguil 		return 0;
1012e22920bSAdrien Mazarguil 	if (unlikely(wcs_n < 0)) {
1022e22920bSAdrien Mazarguil 		DEBUG("%p: ibv_poll_cq() failed (wcs_n=%d)",
1032e22920bSAdrien Mazarguil 		      (void *)txq, wcs_n);
1042e22920bSAdrien Mazarguil 		return -1;
1052e22920bSAdrien Mazarguil 	}
1062e22920bSAdrien Mazarguil 	elts_comp -= wcs_n;
1072e22920bSAdrien Mazarguil 	assert(elts_comp <= txq->elts_comp);
1082e22920bSAdrien Mazarguil 	/*
1092e22920bSAdrien Mazarguil 	 * Assume WC status is successful as nothing can be done about it
1102e22920bSAdrien Mazarguil 	 * anyway.
1112e22920bSAdrien Mazarguil 	 */
1122e22920bSAdrien Mazarguil 	elts_tail += wcs_n * txq->elts_comp_cd_init;
1132e22920bSAdrien Mazarguil 	if (elts_tail >= elts_n)
1142e22920bSAdrien Mazarguil 		elts_tail -= elts_n;
115a859e8a9SNelio Laranjeiro 
116a859e8a9SNelio Laranjeiro 	while (elts_free != elts_tail) {
117a859e8a9SNelio Laranjeiro 		struct txq_elt *elt = &(*txq->elts)[elts_free];
118a859e8a9SNelio Laranjeiro 		unsigned int elts_free_next =
119a859e8a9SNelio Laranjeiro 			(((elts_free + 1) == elts_n) ? 0 : elts_free + 1);
120a859e8a9SNelio Laranjeiro 		struct rte_mbuf *tmp = elt->buf;
121a859e8a9SNelio Laranjeiro 		struct txq_elt *elt_next = &(*txq->elts)[elts_free_next];
122a859e8a9SNelio Laranjeiro 
123b185e63fSAdrien Mazarguil #ifndef NDEBUG
124b185e63fSAdrien Mazarguil 		/* Poisoning. */
125b185e63fSAdrien Mazarguil 		memset(elt, 0x66, sizeof(*elt));
126b185e63fSAdrien Mazarguil #endif
127a859e8a9SNelio Laranjeiro 		RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
128a859e8a9SNelio Laranjeiro 		/* Faster than rte_pktmbuf_free(). */
129a859e8a9SNelio Laranjeiro 		do {
130a859e8a9SNelio Laranjeiro 			struct rte_mbuf *next = NEXT(tmp);
131a859e8a9SNelio Laranjeiro 
132a859e8a9SNelio Laranjeiro 			rte_pktmbuf_free_seg(tmp);
133a859e8a9SNelio Laranjeiro 			tmp = next;
134a859e8a9SNelio Laranjeiro 		} while (tmp != NULL);
135a859e8a9SNelio Laranjeiro 		elts_free = elts_free_next;
136a859e8a9SNelio Laranjeiro 	}
137a859e8a9SNelio Laranjeiro 
1382e22920bSAdrien Mazarguil 	txq->elts_tail = elts_tail;
1392e22920bSAdrien Mazarguil 	txq->elts_comp = elts_comp;
1402e22920bSAdrien Mazarguil 	return 0;
1412e22920bSAdrien Mazarguil }
1422e22920bSAdrien Mazarguil 
143*d1d914ebSOlivier Matz struct mlx5_check_mempool_data {
144*d1d914ebSOlivier Matz 	int ret;
145*d1d914ebSOlivier Matz 	char *start;
146*d1d914ebSOlivier Matz 	char *end;
147*d1d914ebSOlivier Matz };
148*d1d914ebSOlivier Matz 
149*d1d914ebSOlivier Matz /* Called by mlx5_check_mempool() when iterating the memory chunks. */
150*d1d914ebSOlivier Matz static void mlx5_check_mempool_cb(struct rte_mempool *mp,
151*d1d914ebSOlivier Matz 	void *opaque, struct rte_mempool_memhdr *memhdr,
152*d1d914ebSOlivier Matz 	unsigned mem_idx)
153*d1d914ebSOlivier Matz {
154*d1d914ebSOlivier Matz 	struct mlx5_check_mempool_data *data = opaque;
155*d1d914ebSOlivier Matz 
156*d1d914ebSOlivier Matz 	(void)mp;
157*d1d914ebSOlivier Matz 	(void)mem_idx;
158*d1d914ebSOlivier Matz 
159*d1d914ebSOlivier Matz 	/* It already failed, skip the next chunks. */
160*d1d914ebSOlivier Matz 	if (data->ret != 0)
161*d1d914ebSOlivier Matz 		return;
162*d1d914ebSOlivier Matz 	/* It is the first chunk. */
163*d1d914ebSOlivier Matz 	if (data->start == NULL && data->end == NULL) {
164*d1d914ebSOlivier Matz 		data->start = memhdr->addr;
165*d1d914ebSOlivier Matz 		data->end = data->start + memhdr->len;
166*d1d914ebSOlivier Matz 		return;
167*d1d914ebSOlivier Matz 	}
168*d1d914ebSOlivier Matz 	if (data->end == memhdr->addr) {
169*d1d914ebSOlivier Matz 		data->end += memhdr->len;
170*d1d914ebSOlivier Matz 		return;
171*d1d914ebSOlivier Matz 	}
172*d1d914ebSOlivier Matz 	if (data->start == (char *)memhdr->addr + memhdr->len) {
173*d1d914ebSOlivier Matz 		data->start -= memhdr->len;
174*d1d914ebSOlivier Matz 		return;
175*d1d914ebSOlivier Matz 	}
176*d1d914ebSOlivier Matz 	/* Error, mempool is not virtually contigous. */
177*d1d914ebSOlivier Matz 	data->ret = -1;
178*d1d914ebSOlivier Matz }
179*d1d914ebSOlivier Matz 
180*d1d914ebSOlivier Matz /**
181*d1d914ebSOlivier Matz  * Check if a mempool can be used: it must be virtually contiguous.
182*d1d914ebSOlivier Matz  *
183*d1d914ebSOlivier Matz  * @param[in] mp
184*d1d914ebSOlivier Matz  *   Pointer to memory pool.
185*d1d914ebSOlivier Matz  * @param[out] start
186*d1d914ebSOlivier Matz  *   Pointer to the start address of the mempool virtual memory area
187*d1d914ebSOlivier Matz  * @param[out] end
188*d1d914ebSOlivier Matz  *   Pointer to the end address of the mempool virtual memory area
189*d1d914ebSOlivier Matz  *
190*d1d914ebSOlivier Matz  * @return
191*d1d914ebSOlivier Matz  *   0 on success (mempool is virtually contiguous), -1 on error.
192*d1d914ebSOlivier Matz  */
193*d1d914ebSOlivier Matz static int mlx5_check_mempool(struct rte_mempool *mp, uintptr_t *start,
194*d1d914ebSOlivier Matz 	uintptr_t *end)
195*d1d914ebSOlivier Matz {
196*d1d914ebSOlivier Matz 	struct mlx5_check_mempool_data data;
197*d1d914ebSOlivier Matz 
198*d1d914ebSOlivier Matz 	memset(&data, 0, sizeof(data));
199*d1d914ebSOlivier Matz 	rte_mempool_mem_iter(mp, mlx5_check_mempool_cb, &data);
200*d1d914ebSOlivier Matz 	*start = (uintptr_t)data.start;
201*d1d914ebSOlivier Matz 	*end = (uintptr_t)data.end;
202*d1d914ebSOlivier Matz 
203*d1d914ebSOlivier Matz 	return data.ret;
204*d1d914ebSOlivier Matz }
205*d1d914ebSOlivier Matz 
2060dc02ccaSAdrien Mazarguil /* For best performance, this function should not be inlined. */
207*d1d914ebSOlivier Matz struct ibv_mr *mlx5_mp2mr(struct ibv_pd *, struct rte_mempool *)
2080dc02ccaSAdrien Mazarguil 	__attribute__((noinline));
2090dc02ccaSAdrien Mazarguil 
2100dc02ccaSAdrien Mazarguil /**
2110dc02ccaSAdrien Mazarguil  * Register mempool as a memory region.
2120dc02ccaSAdrien Mazarguil  *
2130dc02ccaSAdrien Mazarguil  * @param pd
2140dc02ccaSAdrien Mazarguil  *   Pointer to protection domain.
2150dc02ccaSAdrien Mazarguil  * @param mp
2160dc02ccaSAdrien Mazarguil  *   Pointer to memory pool.
2170dc02ccaSAdrien Mazarguil  *
2180dc02ccaSAdrien Mazarguil  * @return
2190dc02ccaSAdrien Mazarguil  *   Memory region pointer, NULL in case of error.
2200dc02ccaSAdrien Mazarguil  */
2210dc02ccaSAdrien Mazarguil struct ibv_mr *
222*d1d914ebSOlivier Matz mlx5_mp2mr(struct ibv_pd *pd, struct rte_mempool *mp)
2230dc02ccaSAdrien Mazarguil {
2240dc02ccaSAdrien Mazarguil 	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
225*d1d914ebSOlivier Matz 	uintptr_t start;
226*d1d914ebSOlivier Matz 	uintptr_t end;
2270dc02ccaSAdrien Mazarguil 	unsigned int i;
2280dc02ccaSAdrien Mazarguil 
229*d1d914ebSOlivier Matz 	if (mlx5_check_mempool(mp, &start, &end) != 0) {
230*d1d914ebSOlivier Matz 		ERROR("mempool %p: not virtually contiguous",
231*d1d914ebSOlivier Matz 			(void *)mp);
232*d1d914ebSOlivier Matz 		return NULL;
233*d1d914ebSOlivier Matz 	}
234*d1d914ebSOlivier Matz 
2350dc02ccaSAdrien Mazarguil 	DEBUG("mempool %p area start=%p end=%p size=%zu",
236*d1d914ebSOlivier Matz 	      (void *)mp, (void *)start, (void *)end,
2370dc02ccaSAdrien Mazarguil 	      (size_t)(end - start));
2380dc02ccaSAdrien Mazarguil 	/* Round start and end to page boundary if found in memory segments. */
2390dc02ccaSAdrien Mazarguil 	for (i = 0; (i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL); ++i) {
2400dc02ccaSAdrien Mazarguil 		uintptr_t addr = (uintptr_t)ms[i].addr;
2410dc02ccaSAdrien Mazarguil 		size_t len = ms[i].len;
2420dc02ccaSAdrien Mazarguil 		unsigned int align = ms[i].hugepage_sz;
2430dc02ccaSAdrien Mazarguil 
2440dc02ccaSAdrien Mazarguil 		if ((start > addr) && (start < addr + len))
2450dc02ccaSAdrien Mazarguil 			start = RTE_ALIGN_FLOOR(start, align);
2460dc02ccaSAdrien Mazarguil 		if ((end > addr) && (end < addr + len))
2470dc02ccaSAdrien Mazarguil 			end = RTE_ALIGN_CEIL(end, align);
2480dc02ccaSAdrien Mazarguil 	}
2490dc02ccaSAdrien Mazarguil 	DEBUG("mempool %p using start=%p end=%p size=%zu for MR",
250*d1d914ebSOlivier Matz 	      (void *)mp, (void *)start, (void *)end,
2510dc02ccaSAdrien Mazarguil 	      (size_t)(end - start));
2520dc02ccaSAdrien Mazarguil 	return ibv_reg_mr(pd,
2530dc02ccaSAdrien Mazarguil 			  (void *)start,
2540dc02ccaSAdrien Mazarguil 			  end - start,
2550dc02ccaSAdrien Mazarguil 			  IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
2560dc02ccaSAdrien Mazarguil }
2570dc02ccaSAdrien Mazarguil 
2582e22920bSAdrien Mazarguil /**
2598340392eSAdrien Mazarguil  * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which
2608340392eSAdrien Mazarguil  * the cloned mbuf is allocated is returned instead.
2618340392eSAdrien Mazarguil  *
2628340392eSAdrien Mazarguil  * @param buf
2638340392eSAdrien Mazarguil  *   Pointer to mbuf.
2648340392eSAdrien Mazarguil  *
2658340392eSAdrien Mazarguil  * @return
2668340392eSAdrien Mazarguil  *   Memory pool where data is located for given mbuf.
2678340392eSAdrien Mazarguil  */
2688340392eSAdrien Mazarguil static struct rte_mempool *
2698340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf)
2708340392eSAdrien Mazarguil {
2718340392eSAdrien Mazarguil 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
2728340392eSAdrien Mazarguil 		return rte_mbuf_from_indirect(buf)->pool;
2738340392eSAdrien Mazarguil 	return buf->pool;
2748340392eSAdrien Mazarguil }
2758340392eSAdrien Mazarguil 
2768340392eSAdrien Mazarguil /**
2772e22920bSAdrien Mazarguil  * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[].
2782e22920bSAdrien Mazarguil  * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full,
2792e22920bSAdrien Mazarguil  * remove an entry first.
2802e22920bSAdrien Mazarguil  *
2812e22920bSAdrien Mazarguil  * @param txq
2822e22920bSAdrien Mazarguil  *   Pointer to TX queue structure.
2832e22920bSAdrien Mazarguil  * @param[in] mp
2842e22920bSAdrien Mazarguil  *   Memory Pool for which a Memory Region lkey must be returned.
2852e22920bSAdrien Mazarguil  *
2862e22920bSAdrien Mazarguil  * @return
2872e22920bSAdrien Mazarguil  *   mr->lkey on success, (uint32_t)-1 on failure.
2882e22920bSAdrien Mazarguil  */
2892e22920bSAdrien Mazarguil static uint32_t
290*d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp)
2912e22920bSAdrien Mazarguil {
2922e22920bSAdrien Mazarguil 	unsigned int i;
2932e22920bSAdrien Mazarguil 	struct ibv_mr *mr;
2942e22920bSAdrien Mazarguil 
2952e22920bSAdrien Mazarguil 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
2962e22920bSAdrien Mazarguil 		if (unlikely(txq->mp2mr[i].mp == NULL)) {
2972e22920bSAdrien Mazarguil 			/* Unknown MP, add a new MR for it. */
2982e22920bSAdrien Mazarguil 			break;
2992e22920bSAdrien Mazarguil 		}
3002e22920bSAdrien Mazarguil 		if (txq->mp2mr[i].mp == mp) {
3012e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].lkey != (uint32_t)-1);
3022e22920bSAdrien Mazarguil 			assert(txq->mp2mr[i].mr->lkey == txq->mp2mr[i].lkey);
3032e22920bSAdrien Mazarguil 			return txq->mp2mr[i].lkey;
3042e22920bSAdrien Mazarguil 		}
3052e22920bSAdrien Mazarguil 	}
3062e22920bSAdrien Mazarguil 	/* Add a new entry, register MR first. */
3070a3b350dSOlga Shern 	DEBUG("%p: discovered new memory pool \"%s\" (%p)",
308*d1d914ebSOlivier Matz 	      (void *)txq, mp->name, (void *)mp);
3090dc02ccaSAdrien Mazarguil 	mr = mlx5_mp2mr(txq->priv->pd, mp);
3102e22920bSAdrien Mazarguil 	if (unlikely(mr == NULL)) {
3112e22920bSAdrien Mazarguil 		DEBUG("%p: unable to configure MR, ibv_reg_mr() failed.",
3122e22920bSAdrien Mazarguil 		      (void *)txq);
3132e22920bSAdrien Mazarguil 		return (uint32_t)-1;
3142e22920bSAdrien Mazarguil 	}
3152e22920bSAdrien Mazarguil 	if (unlikely(i == RTE_DIM(txq->mp2mr))) {
3162e22920bSAdrien Mazarguil 		/* Table is full, remove oldest entry. */
3172e22920bSAdrien Mazarguil 		DEBUG("%p: MR <-> MP table full, dropping oldest entry.",
3182e22920bSAdrien Mazarguil 		      (void *)txq);
3192e22920bSAdrien Mazarguil 		--i;
320ecbfdbadSOlga Shern 		claim_zero(ibv_dereg_mr(txq->mp2mr[0].mr));
3212e22920bSAdrien Mazarguil 		memmove(&txq->mp2mr[0], &txq->mp2mr[1],
3222e22920bSAdrien Mazarguil 			(sizeof(txq->mp2mr) - sizeof(txq->mp2mr[0])));
3232e22920bSAdrien Mazarguil 	}
3242e22920bSAdrien Mazarguil 	/* Store the new entry. */
3252e22920bSAdrien Mazarguil 	txq->mp2mr[i].mp = mp;
3262e22920bSAdrien Mazarguil 	txq->mp2mr[i].mr = mr;
3272e22920bSAdrien Mazarguil 	txq->mp2mr[i].lkey = mr->lkey;
3280a3b350dSOlga Shern 	DEBUG("%p: new MR lkey for MP \"%s\" (%p): 0x%08" PRIu32,
329*d1d914ebSOlivier Matz 	      (void *)txq, mp->name, (void *)mp, txq->mp2mr[i].lkey);
3302e22920bSAdrien Mazarguil 	return txq->mp2mr[i].lkey;
3312e22920bSAdrien Mazarguil }
3322e22920bSAdrien Mazarguil 
3330a3b350dSOlga Shern struct txq_mp2mr_mbuf_check_data {
3340a3b350dSOlga Shern 	int ret;
3350a3b350dSOlga Shern };
3360a3b350dSOlga Shern 
3370a3b350dSOlga Shern /**
3380a3b350dSOlga Shern  * Callback function for rte_mempool_obj_iter() to check whether a given
3390a3b350dSOlga Shern  * mempool object looks like a mbuf.
3400a3b350dSOlga Shern  *
341d86046f0SOlivier Matz  * @param[in] mp
342d86046f0SOlivier Matz  *   The mempool pointer
343d86046f0SOlivier Matz  * @param[in] arg
344d86046f0SOlivier Matz  *   Context data (struct txq_mp2mr_mbuf_check_data). Contains the
345d86046f0SOlivier Matz  *   return value.
346d86046f0SOlivier Matz  * @param[in] obj
347d86046f0SOlivier Matz  *   Object address.
3480a3b350dSOlga Shern  * @param index
349d86046f0SOlivier Matz  *   Object index, unused.
3500a3b350dSOlga Shern  */
3510a3b350dSOlga Shern static void
352d86046f0SOlivier Matz txq_mp2mr_mbuf_check(struct rte_mempool *mp, void *arg, void *obj,
3530a3b350dSOlga Shern 	uint32_t index __rte_unused)
3540a3b350dSOlga Shern {
3550a3b350dSOlga Shern 	struct txq_mp2mr_mbuf_check_data *data = arg;
356d86046f0SOlivier Matz 	struct rte_mbuf *buf = obj;
3570a3b350dSOlga Shern 
3580a3b350dSOlga Shern 	/* Check whether mbuf structure fits element size and whether mempool
3590a3b350dSOlga Shern 	 * pointer is valid. */
360d86046f0SOlivier Matz 	if (sizeof(*buf) > mp->elt_size || buf->pool != mp)
3610a3b350dSOlga Shern 		data->ret = -1;
3620a3b350dSOlga Shern }
3630a3b350dSOlga Shern 
3640a3b350dSOlga Shern /**
3650a3b350dSOlga Shern  * Iterator function for rte_mempool_walk() to register existing mempools and
3660a3b350dSOlga Shern  * fill the MP to MR cache of a TX queue.
3670a3b350dSOlga Shern  *
3680a3b350dSOlga Shern  * @param[in] mp
3690a3b350dSOlga Shern  *   Memory Pool to register.
3700a3b350dSOlga Shern  * @param *arg
3710a3b350dSOlga Shern  *   Pointer to TX queue structure.
3720a3b350dSOlga Shern  */
3730a3b350dSOlga Shern void
374c2c66588SOlivier Matz txq_mp2mr_iter(struct rte_mempool *mp, void *arg)
3750a3b350dSOlga Shern {
3760a3b350dSOlga Shern 	struct txq *txq = arg;
3770a3b350dSOlga Shern 	struct txq_mp2mr_mbuf_check_data data = {
378d86046f0SOlivier Matz 		.ret = 0,
3790a3b350dSOlga Shern 	};
3800a3b350dSOlga Shern 
3810a3b350dSOlga Shern 	/* Register mempool only if the first element looks like a mbuf. */
382d86046f0SOlivier Matz 	if (rte_mempool_obj_iter(mp, txq_mp2mr_mbuf_check, &data) == 0 ||
383d86046f0SOlivier Matz 			data.ret == -1)
3840a3b350dSOlga Shern 		return;
3850a3b350dSOlga Shern 	txq_mp2mr(txq, mp);
3860a3b350dSOlga Shern }
3870a3b350dSOlga Shern 
388e192ef80SYaacov Hazan /**
389e192ef80SYaacov Hazan  * Insert VLAN using mbuf headroom space.
390e192ef80SYaacov Hazan  *
391e192ef80SYaacov Hazan  * @param buf
392e192ef80SYaacov Hazan  *   Buffer for VLAN insertion.
393e192ef80SYaacov Hazan  *
394e192ef80SYaacov Hazan  * @return
395e192ef80SYaacov Hazan  *   0 on success, errno value on failure.
396e192ef80SYaacov Hazan  */
397e192ef80SYaacov Hazan static inline int
398e192ef80SYaacov Hazan insert_vlan_sw(struct rte_mbuf *buf)
399e192ef80SYaacov Hazan {
400e192ef80SYaacov Hazan 	uintptr_t addr;
401e192ef80SYaacov Hazan 	uint32_t vlan;
402e192ef80SYaacov Hazan 	uint16_t head_room_len = rte_pktmbuf_headroom(buf);
403e192ef80SYaacov Hazan 
404e192ef80SYaacov Hazan 	if (head_room_len < 4)
405e192ef80SYaacov Hazan 		return EINVAL;
406e192ef80SYaacov Hazan 
407e192ef80SYaacov Hazan 	addr = rte_pktmbuf_mtod(buf, uintptr_t);
408e192ef80SYaacov Hazan 	vlan = htonl(0x81000000 | buf->vlan_tci);
409e192ef80SYaacov Hazan 	memmove((void *)(addr - 4), (void *)addr, 12);
410e192ef80SYaacov Hazan 	memcpy((void *)(addr + 8), &vlan, sizeof(vlan));
411e192ef80SYaacov Hazan 
412e192ef80SYaacov Hazan 	SET_DATA_OFF(buf, head_room_len - 4);
413e192ef80SYaacov Hazan 	DATA_LEN(buf) += 4;
414e192ef80SYaacov Hazan 
415e192ef80SYaacov Hazan 	return 0;
416e192ef80SYaacov Hazan }
417e192ef80SYaacov Hazan 
4183ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1
4193ee84446SAdrien Mazarguil 
4203ee84446SAdrien Mazarguil /**
4213ee84446SAdrien Mazarguil  * Copy scattered mbuf contents to a single linear buffer.
4223ee84446SAdrien Mazarguil  *
4233ee84446SAdrien Mazarguil  * @param[out] linear
4243ee84446SAdrien Mazarguil  *   Linear output buffer.
4253ee84446SAdrien Mazarguil  * @param[in] buf
4263ee84446SAdrien Mazarguil  *   Scattered input buffer.
4273ee84446SAdrien Mazarguil  *
4283ee84446SAdrien Mazarguil  * @return
4293ee84446SAdrien Mazarguil  *   Number of bytes copied to the output buffer or 0 if not large enough.
4303ee84446SAdrien Mazarguil  */
4313ee84446SAdrien Mazarguil static unsigned int
4323ee84446SAdrien Mazarguil linearize_mbuf(linear_t *linear, struct rte_mbuf *buf)
4333ee84446SAdrien Mazarguil {
4343ee84446SAdrien Mazarguil 	unsigned int size = 0;
4353ee84446SAdrien Mazarguil 	unsigned int offset;
4363ee84446SAdrien Mazarguil 
4373ee84446SAdrien Mazarguil 	do {
4383ee84446SAdrien Mazarguil 		unsigned int len = DATA_LEN(buf);
4393ee84446SAdrien Mazarguil 
4403ee84446SAdrien Mazarguil 		offset = size;
4413ee84446SAdrien Mazarguil 		size += len;
4423ee84446SAdrien Mazarguil 		if (unlikely(size > sizeof(*linear)))
4433ee84446SAdrien Mazarguil 			return 0;
4443ee84446SAdrien Mazarguil 		memcpy(&(*linear)[offset],
4453ee84446SAdrien Mazarguil 		       rte_pktmbuf_mtod(buf, uint8_t *),
4463ee84446SAdrien Mazarguil 		       len);
4473ee84446SAdrien Mazarguil 		buf = NEXT(buf);
4483ee84446SAdrien Mazarguil 	} while (buf != NULL);
4493ee84446SAdrien Mazarguil 	return size;
4503ee84446SAdrien Mazarguil }
4513ee84446SAdrien Mazarguil 
4523ee84446SAdrien Mazarguil /**
4533ee84446SAdrien Mazarguil  * Handle scattered buffers for mlx5_tx_burst().
4543ee84446SAdrien Mazarguil  *
4553ee84446SAdrien Mazarguil  * @param txq
4563ee84446SAdrien Mazarguil  *   TX queue structure.
4573ee84446SAdrien Mazarguil  * @param segs
4583ee84446SAdrien Mazarguil  *   Number of segments in buf.
4593ee84446SAdrien Mazarguil  * @param elt
4603ee84446SAdrien Mazarguil  *   TX queue element to fill.
4613ee84446SAdrien Mazarguil  * @param[in] buf
4623ee84446SAdrien Mazarguil  *   Buffer to process.
4633ee84446SAdrien Mazarguil  * @param elts_head
4643ee84446SAdrien Mazarguil  *   Index of the linear buffer to use if necessary (normally txq->elts_head).
4653ee84446SAdrien Mazarguil  * @param[out] sges
4663ee84446SAdrien Mazarguil  *   Array filled with SGEs on success.
4673ee84446SAdrien Mazarguil  *
4683ee84446SAdrien Mazarguil  * @return
4693ee84446SAdrien Mazarguil  *   A structure containing the processed packet size in bytes and the
4703ee84446SAdrien Mazarguil  *   number of SGEs. Both fields are set to (unsigned int)-1 in case of
4713ee84446SAdrien Mazarguil  *   failure.
4723ee84446SAdrien Mazarguil  */
4733ee84446SAdrien Mazarguil static struct tx_burst_sg_ret {
4743ee84446SAdrien Mazarguil 	unsigned int length;
4753ee84446SAdrien Mazarguil 	unsigned int num;
4763ee84446SAdrien Mazarguil }
4773ee84446SAdrien Mazarguil tx_burst_sg(struct txq *txq, unsigned int segs, struct txq_elt *elt,
4783ee84446SAdrien Mazarguil 	    struct rte_mbuf *buf, unsigned int elts_head,
4793ee84446SAdrien Mazarguil 	    struct ibv_sge (*sges)[MLX5_PMD_SGE_WR_N])
4803ee84446SAdrien Mazarguil {
4813ee84446SAdrien Mazarguil 	unsigned int sent_size = 0;
4823ee84446SAdrien Mazarguil 	unsigned int j;
4833ee84446SAdrien Mazarguil 	int linearize = 0;
4843ee84446SAdrien Mazarguil 
4853ee84446SAdrien Mazarguil 	/* When there are too many segments, extra segments are
4863ee84446SAdrien Mazarguil 	 * linearized in the last SGE. */
4873ee84446SAdrien Mazarguil 	if (unlikely(segs > RTE_DIM(*sges))) {
4883ee84446SAdrien Mazarguil 		segs = (RTE_DIM(*sges) - 1);
4893ee84446SAdrien Mazarguil 		linearize = 1;
4903ee84446SAdrien Mazarguil 	}
4913ee84446SAdrien Mazarguil 	/* Update element. */
4923ee84446SAdrien Mazarguil 	elt->buf = buf;
4933ee84446SAdrien Mazarguil 	/* Register segments as SGEs. */
4943ee84446SAdrien Mazarguil 	for (j = 0; (j != segs); ++j) {
4953ee84446SAdrien Mazarguil 		struct ibv_sge *sge = &(*sges)[j];
4963ee84446SAdrien Mazarguil 		uint32_t lkey;
4973ee84446SAdrien Mazarguil 
4983ee84446SAdrien Mazarguil 		/* Retrieve Memory Region key for this memory pool. */
4998340392eSAdrien Mazarguil 		lkey = txq_mp2mr(txq, txq_mb2mp(buf));
5003ee84446SAdrien Mazarguil 		if (unlikely(lkey == (uint32_t)-1)) {
5013ee84446SAdrien Mazarguil 			/* MR does not exist. */
5023ee84446SAdrien Mazarguil 			DEBUG("%p: unable to get MP <-> MR association",
5033ee84446SAdrien Mazarguil 			      (void *)txq);
5043ee84446SAdrien Mazarguil 			/* Clean up TX element. */
5053ee84446SAdrien Mazarguil 			elt->buf = NULL;
5063ee84446SAdrien Mazarguil 			goto stop;
5073ee84446SAdrien Mazarguil 		}
5083ee84446SAdrien Mazarguil 		/* Update SGE. */
5093ee84446SAdrien Mazarguil 		sge->addr = rte_pktmbuf_mtod(buf, uintptr_t);
5103ee84446SAdrien Mazarguil 		if (txq->priv->vf)
5113ee84446SAdrien Mazarguil 			rte_prefetch0((volatile void *)
5123ee84446SAdrien Mazarguil 				      (uintptr_t)sge->addr);
5133ee84446SAdrien Mazarguil 		sge->length = DATA_LEN(buf);
5143ee84446SAdrien Mazarguil 		sge->lkey = lkey;
5153ee84446SAdrien Mazarguil 		sent_size += sge->length;
5163ee84446SAdrien Mazarguil 		buf = NEXT(buf);
5173ee84446SAdrien Mazarguil 	}
5183ee84446SAdrien Mazarguil 	/* If buf is not NULL here and is not going to be linearized,
5193ee84446SAdrien Mazarguil 	 * nb_segs is not valid. */
5203ee84446SAdrien Mazarguil 	assert(j == segs);
5213ee84446SAdrien Mazarguil 	assert((buf == NULL) || (linearize));
5223ee84446SAdrien Mazarguil 	/* Linearize extra segments. */
5233ee84446SAdrien Mazarguil 	if (linearize) {
5243ee84446SAdrien Mazarguil 		struct ibv_sge *sge = &(*sges)[segs];
5253ee84446SAdrien Mazarguil 		linear_t *linear = &(*txq->elts_linear)[elts_head];
5263ee84446SAdrien Mazarguil 		unsigned int size = linearize_mbuf(linear, buf);
5273ee84446SAdrien Mazarguil 
5283ee84446SAdrien Mazarguil 		assert(segs == (RTE_DIM(*sges) - 1));
5293ee84446SAdrien Mazarguil 		if (size == 0) {
5303ee84446SAdrien Mazarguil 			/* Invalid packet. */
5313ee84446SAdrien Mazarguil 			DEBUG("%p: packet too large to be linearized.",
5323ee84446SAdrien Mazarguil 			      (void *)txq);
5333ee84446SAdrien Mazarguil 			/* Clean up TX element. */
5343ee84446SAdrien Mazarguil 			elt->buf = NULL;
5353ee84446SAdrien Mazarguil 			goto stop;
5363ee84446SAdrien Mazarguil 		}
5373ee84446SAdrien Mazarguil 		/* If MLX5_PMD_SGE_WR_N is 1, free mbuf immediately. */
5383ee84446SAdrien Mazarguil 		if (RTE_DIM(*sges) == 1) {
5393ee84446SAdrien Mazarguil 			do {
5403ee84446SAdrien Mazarguil 				struct rte_mbuf *next = NEXT(buf);
5413ee84446SAdrien Mazarguil 
5423ee84446SAdrien Mazarguil 				rte_pktmbuf_free_seg(buf);
5433ee84446SAdrien Mazarguil 				buf = next;
5443ee84446SAdrien Mazarguil 			} while (buf != NULL);
5453ee84446SAdrien Mazarguil 			elt->buf = NULL;
5463ee84446SAdrien Mazarguil 		}
5473ee84446SAdrien Mazarguil 		/* Update SGE. */
5483ee84446SAdrien Mazarguil 		sge->addr = (uintptr_t)&(*linear)[0];
5493ee84446SAdrien Mazarguil 		sge->length = size;
5503ee84446SAdrien Mazarguil 		sge->lkey = txq->mr_linear->lkey;
5513ee84446SAdrien Mazarguil 		sent_size += size;
55234d06263SAdrien Mazarguil 		/* Include last segment. */
55334d06263SAdrien Mazarguil 		segs++;
5543ee84446SAdrien Mazarguil 	}
5553ee84446SAdrien Mazarguil 	return (struct tx_burst_sg_ret){
5563ee84446SAdrien Mazarguil 		.length = sent_size,
5573ee84446SAdrien Mazarguil 		.num = segs,
5583ee84446SAdrien Mazarguil 	};
5593ee84446SAdrien Mazarguil stop:
5603ee84446SAdrien Mazarguil 	return (struct tx_burst_sg_ret){
5613ee84446SAdrien Mazarguil 		.length = -1,
5623ee84446SAdrien Mazarguil 		.num = -1,
5633ee84446SAdrien Mazarguil 	};
5643ee84446SAdrien Mazarguil }
5653ee84446SAdrien Mazarguil 
5663ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */
5673ee84446SAdrien Mazarguil 
5682e22920bSAdrien Mazarguil /**
5692e22920bSAdrien Mazarguil  * DPDK callback for TX.
5702e22920bSAdrien Mazarguil  *
5712e22920bSAdrien Mazarguil  * @param dpdk_txq
5722e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
5732e22920bSAdrien Mazarguil  * @param[in] pkts
5742e22920bSAdrien Mazarguil  *   Packets to transmit.
5752e22920bSAdrien Mazarguil  * @param pkts_n
5762e22920bSAdrien Mazarguil  *   Number of packets in array.
5772e22920bSAdrien Mazarguil  *
5782e22920bSAdrien Mazarguil  * @return
5792e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
5802e22920bSAdrien Mazarguil  */
5812e22920bSAdrien Mazarguil uint16_t
5822e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
5832e22920bSAdrien Mazarguil {
5842e22920bSAdrien Mazarguil 	struct txq *txq = (struct txq *)dpdk_txq;
5852e22920bSAdrien Mazarguil 	unsigned int elts_head = txq->elts_head;
5862e22920bSAdrien Mazarguil 	const unsigned int elts_n = txq->elts_n;
5872e22920bSAdrien Mazarguil 	unsigned int elts_comp_cd = txq->elts_comp_cd;
5882e22920bSAdrien Mazarguil 	unsigned int elts_comp = 0;
5892e22920bSAdrien Mazarguil 	unsigned int i;
5902e22920bSAdrien Mazarguil 	unsigned int max;
5912e22920bSAdrien Mazarguil 	int err;
5925e1d11ecSNelio Laranjeiro 	struct rte_mbuf *buf = pkts[0];
5932e22920bSAdrien Mazarguil 
5942e22920bSAdrien Mazarguil 	assert(elts_comp_cd != 0);
5955e1d11ecSNelio Laranjeiro 	/* Prefetch first packet cacheline. */
5965e1d11ecSNelio Laranjeiro 	rte_prefetch0(buf);
5972e22920bSAdrien Mazarguil 	txq_complete(txq);
5984f52bbfbSNelio Laranjeiro 	max = (elts_n - (elts_head - txq->elts_tail));
5992e22920bSAdrien Mazarguil 	if (max > elts_n)
6002e22920bSAdrien Mazarguil 		max -= elts_n;
6012e22920bSAdrien Mazarguil 	assert(max >= 1);
6022e22920bSAdrien Mazarguil 	assert(max <= elts_n);
6032e22920bSAdrien Mazarguil 	/* Always leave one free entry in the ring. */
6042e22920bSAdrien Mazarguil 	--max;
6052e22920bSAdrien Mazarguil 	if (max == 0)
6062e22920bSAdrien Mazarguil 		return 0;
6072e22920bSAdrien Mazarguil 	if (max > pkts_n)
6082e22920bSAdrien Mazarguil 		max = pkts_n;
6092e22920bSAdrien Mazarguil 	for (i = 0; (i != max); ++i) {
6105e1d11ecSNelio Laranjeiro 		struct rte_mbuf *buf_next = pkts[i + 1];
6112e22920bSAdrien Mazarguil 		unsigned int elts_head_next =
6122e22920bSAdrien Mazarguil 			(((elts_head + 1) == elts_n) ? 0 : elts_head + 1);
6132e22920bSAdrien Mazarguil 		struct txq_elt *elt = &(*txq->elts)[elts_head];
6142e22920bSAdrien Mazarguil 		unsigned int segs = NB_SEGS(buf);
61587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
61687011737SAdrien Mazarguil 		unsigned int sent_size = 0;
61787011737SAdrien Mazarguil #endif
6182e22920bSAdrien Mazarguil 		uint32_t send_flags = 0;
619e192ef80SYaacov Hazan #ifdef HAVE_VERBS_VLAN_INSERTION
620e192ef80SYaacov Hazan 		int insert_vlan = 0;
621e192ef80SYaacov Hazan #endif /* HAVE_VERBS_VLAN_INSERTION */
6222e22920bSAdrien Mazarguil 
6235e1d11ecSNelio Laranjeiro 		if (i + 1 < max)
6245e1d11ecSNelio Laranjeiro 			rte_prefetch0(buf_next);
6252e22920bSAdrien Mazarguil 		/* Request TX completion. */
6262e22920bSAdrien Mazarguil 		if (unlikely(--elts_comp_cd == 0)) {
6272e22920bSAdrien Mazarguil 			elts_comp_cd = txq->elts_comp_cd_init;
6282e22920bSAdrien Mazarguil 			++elts_comp;
6292e22920bSAdrien Mazarguil 			send_flags |= IBV_EXP_QP_BURST_SIGNALED;
6302e22920bSAdrien Mazarguil 		}
63167fa62bcSAdrien Mazarguil 		/* Should we enable HW CKSUM offload */
63267fa62bcSAdrien Mazarguil 		if (buf->ol_flags &
63367fa62bcSAdrien Mazarguil 		    (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) {
63467fa62bcSAdrien Mazarguil 			send_flags |= IBV_EXP_QP_BURST_IP_CSUM;
63567fa62bcSAdrien Mazarguil 			/* HW does not support checksum offloads at arbitrary
63667fa62bcSAdrien Mazarguil 			 * offsets but automatically recognizes the packet
63767fa62bcSAdrien Mazarguil 			 * type. For inner L3/L4 checksums, only VXLAN (UDP)
63867fa62bcSAdrien Mazarguil 			 * tunnels are currently supported. */
63967fa62bcSAdrien Mazarguil 			if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type))
64067fa62bcSAdrien Mazarguil 				send_flags |= IBV_EXP_QP_BURST_TUNNEL;
64167fa62bcSAdrien Mazarguil 		}
642e192ef80SYaacov Hazan 		if (buf->ol_flags & PKT_TX_VLAN_PKT) {
643e192ef80SYaacov Hazan #ifdef HAVE_VERBS_VLAN_INSERTION
644e192ef80SYaacov Hazan 			if (!txq->priv->mps)
645e192ef80SYaacov Hazan 				insert_vlan = 1;
646e192ef80SYaacov Hazan 			else
647e192ef80SYaacov Hazan #endif /* HAVE_VERBS_VLAN_INSERTION */
648e192ef80SYaacov Hazan 			{
649e192ef80SYaacov Hazan 				err = insert_vlan_sw(buf);
650e192ef80SYaacov Hazan 				if (unlikely(err))
651e192ef80SYaacov Hazan 					goto stop;
652e192ef80SYaacov Hazan 			}
653e192ef80SYaacov Hazan 		}
6542e22920bSAdrien Mazarguil 		if (likely(segs == 1)) {
6552e22920bSAdrien Mazarguil 			uintptr_t addr;
6562e22920bSAdrien Mazarguil 			uint32_t length;
6572e22920bSAdrien Mazarguil 			uint32_t lkey;
6585e1d11ecSNelio Laranjeiro 			uintptr_t buf_next_addr;
6592e22920bSAdrien Mazarguil 
6602e22920bSAdrien Mazarguil 			/* Retrieve buffer information. */
6612e22920bSAdrien Mazarguil 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
6622e22920bSAdrien Mazarguil 			length = DATA_LEN(buf);
6632e22920bSAdrien Mazarguil 			/* Update element. */
6642e22920bSAdrien Mazarguil 			elt->buf = buf;
6652e22920bSAdrien Mazarguil 			if (txq->priv->vf)
6662e22920bSAdrien Mazarguil 				rte_prefetch0((volatile void *)
6672e22920bSAdrien Mazarguil 					      (uintptr_t)addr);
6685e1d11ecSNelio Laranjeiro 			/* Prefetch next buffer data. */
6695e1d11ecSNelio Laranjeiro 			if (i + 1 < max) {
6705e1d11ecSNelio Laranjeiro 				buf_next_addr =
6715e1d11ecSNelio Laranjeiro 					rte_pktmbuf_mtod(buf_next, uintptr_t);
6725e1d11ecSNelio Laranjeiro 				rte_prefetch0((volatile void *)
6735e1d11ecSNelio Laranjeiro 					      (uintptr_t)buf_next_addr);
6745e1d11ecSNelio Laranjeiro 			}
6752e22920bSAdrien Mazarguil 			/* Put packet into send queue. */
6762e22920bSAdrien Mazarguil #if MLX5_PMD_MAX_INLINE > 0
677e192ef80SYaacov Hazan 			if (length <= txq->max_inline) {
678e192ef80SYaacov Hazan #ifdef HAVE_VERBS_VLAN_INSERTION
679e192ef80SYaacov Hazan 				if (insert_vlan)
680e192ef80SYaacov Hazan 					err = txq->send_pending_inline_vlan
681e192ef80SYaacov Hazan 						(txq->qp,
682e192ef80SYaacov Hazan 						 (void *)addr,
683e192ef80SYaacov Hazan 						 length,
684e192ef80SYaacov Hazan 						 send_flags,
685e192ef80SYaacov Hazan 						 &buf->vlan_tci);
686e192ef80SYaacov Hazan 				else
687e192ef80SYaacov Hazan #endif /* HAVE_VERBS_VLAN_INSERTION */
688e1682023SNelio Laranjeiro 					err = txq->send_pending_inline
6892e22920bSAdrien Mazarguil 						(txq->qp,
6902e22920bSAdrien Mazarguil 						 (void *)addr,
6912e22920bSAdrien Mazarguil 						 length,
6922e22920bSAdrien Mazarguil 						 send_flags);
693e192ef80SYaacov Hazan 			} else
6942e22920bSAdrien Mazarguil #endif
695d970e992SNelio Laranjeiro 			{
696d970e992SNelio Laranjeiro 				/* Retrieve Memory Region key for this
697d970e992SNelio Laranjeiro 				 * memory pool. */
698d970e992SNelio Laranjeiro 				lkey = txq_mp2mr(txq, txq_mb2mp(buf));
699d970e992SNelio Laranjeiro 				if (unlikely(lkey == (uint32_t)-1)) {
700d970e992SNelio Laranjeiro 					/* MR does not exist. */
701d970e992SNelio Laranjeiro 					DEBUG("%p: unable to get MP <-> MR"
702d970e992SNelio Laranjeiro 					      " association", (void *)txq);
703d970e992SNelio Laranjeiro 					/* Clean up TX element. */
704d970e992SNelio Laranjeiro 					elt->buf = NULL;
705d970e992SNelio Laranjeiro 					goto stop;
706d970e992SNelio Laranjeiro 				}
707e192ef80SYaacov Hazan #ifdef HAVE_VERBS_VLAN_INSERTION
708e192ef80SYaacov Hazan 				if (insert_vlan)
709e192ef80SYaacov Hazan 					err = txq->send_pending_vlan
710e192ef80SYaacov Hazan 						(txq->qp,
711e192ef80SYaacov Hazan 						 addr,
712e192ef80SYaacov Hazan 						 length,
713e192ef80SYaacov Hazan 						 lkey,
714e192ef80SYaacov Hazan 						 send_flags,
715e192ef80SYaacov Hazan 						 &buf->vlan_tci);
716e192ef80SYaacov Hazan 				else
717e192ef80SYaacov Hazan #endif /* HAVE_VERBS_VLAN_INSERTION */
718e1682023SNelio Laranjeiro 					err = txq->send_pending
7192e22920bSAdrien Mazarguil 						(txq->qp,
7202e22920bSAdrien Mazarguil 						 addr,
7212e22920bSAdrien Mazarguil 						 length,
7222e22920bSAdrien Mazarguil 						 lkey,
7232e22920bSAdrien Mazarguil 						 send_flags);
724d970e992SNelio Laranjeiro 			}
7252e22920bSAdrien Mazarguil 			if (unlikely(err))
7262e22920bSAdrien Mazarguil 				goto stop;
72787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
72887011737SAdrien Mazarguil 			sent_size += length;
72987011737SAdrien Mazarguil #endif
7302e22920bSAdrien Mazarguil 		} else {
7313ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1
7323ee84446SAdrien Mazarguil 			struct ibv_sge sges[MLX5_PMD_SGE_WR_N];
7333ee84446SAdrien Mazarguil 			struct tx_burst_sg_ret ret;
7343ee84446SAdrien Mazarguil 
7353ee84446SAdrien Mazarguil 			ret = tx_burst_sg(txq, segs, elt, buf, elts_head,
7363ee84446SAdrien Mazarguil 					  &sges);
7373ee84446SAdrien Mazarguil 			if (ret.length == (unsigned int)-1)
7383ee84446SAdrien Mazarguil 				goto stop;
7393ee84446SAdrien Mazarguil 			/* Put SG list into send queue. */
740e192ef80SYaacov Hazan #ifdef HAVE_VERBS_VLAN_INSERTION
741e192ef80SYaacov Hazan 			if (insert_vlan)
742e192ef80SYaacov Hazan 				err = txq->send_pending_sg_list_vlan
743e192ef80SYaacov Hazan 					(txq->qp,
744e192ef80SYaacov Hazan 					 sges,
745e192ef80SYaacov Hazan 					 ret.num,
746e192ef80SYaacov Hazan 					 send_flags,
747e192ef80SYaacov Hazan 					 &buf->vlan_tci);
748e192ef80SYaacov Hazan 			else
749e192ef80SYaacov Hazan #endif /* HAVE_VERBS_VLAN_INSERTION */
750e1682023SNelio Laranjeiro 				err = txq->send_pending_sg_list
7513ee84446SAdrien Mazarguil 					(txq->qp,
7523ee84446SAdrien Mazarguil 					 sges,
7533ee84446SAdrien Mazarguil 					 ret.num,
7543ee84446SAdrien Mazarguil 					 send_flags);
7553ee84446SAdrien Mazarguil 			if (unlikely(err))
7563ee84446SAdrien Mazarguil 				goto stop;
75787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
75887011737SAdrien Mazarguil 			sent_size += ret.length;
75987011737SAdrien Mazarguil #endif
7603ee84446SAdrien Mazarguil #else /* MLX5_PMD_SGE_WR_N > 1 */
7612e22920bSAdrien Mazarguil 			DEBUG("%p: TX scattered buffers support not"
7622e22920bSAdrien Mazarguil 			      " compiled in", (void *)txq);
7632e22920bSAdrien Mazarguil 			goto stop;
7643ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */
7652e22920bSAdrien Mazarguil 		}
7662e22920bSAdrien Mazarguil 		elts_head = elts_head_next;
7675e1d11ecSNelio Laranjeiro 		buf = buf_next;
76887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
76987011737SAdrien Mazarguil 		/* Increment sent bytes counter. */
77087011737SAdrien Mazarguil 		txq->stats.obytes += sent_size;
77187011737SAdrien Mazarguil #endif
7722e22920bSAdrien Mazarguil 	}
7732e22920bSAdrien Mazarguil stop:
7742e22920bSAdrien Mazarguil 	/* Take a shortcut if nothing must be sent. */
7752e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
7762e22920bSAdrien Mazarguil 		return 0;
77787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
77887011737SAdrien Mazarguil 	/* Increment sent packets counter. */
77987011737SAdrien Mazarguil 	txq->stats.opackets += i;
78087011737SAdrien Mazarguil #endif
7812e22920bSAdrien Mazarguil 	/* Ring QP doorbell. */
782e1682023SNelio Laranjeiro 	err = txq->send_flush(txq->qp);
7832e22920bSAdrien Mazarguil 	if (unlikely(err)) {
7842e22920bSAdrien Mazarguil 		/* A nonzero value is not supposed to be returned.
7852e22920bSAdrien Mazarguil 		 * Nothing can be done about it. */
7862e22920bSAdrien Mazarguil 		DEBUG("%p: send_flush() failed with error %d",
7872e22920bSAdrien Mazarguil 		      (void *)txq, err);
7882e22920bSAdrien Mazarguil 	}
7892e22920bSAdrien Mazarguil 	txq->elts_head = elts_head;
7902e22920bSAdrien Mazarguil 	txq->elts_comp += elts_comp;
7912e22920bSAdrien Mazarguil 	txq->elts_comp_cd = elts_comp_cd;
7922e22920bSAdrien Mazarguil 	return i;
7932e22920bSAdrien Mazarguil }
7942e22920bSAdrien Mazarguil 
7952e22920bSAdrien Mazarguil /**
79667fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
79767fa62bcSAdrien Mazarguil  *
79867fa62bcSAdrien Mazarguil  * @param flags
79967fa62bcSAdrien Mazarguil  *   RX completion flags returned by poll_length_flags().
80067fa62bcSAdrien Mazarguil  *
80178a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
80278a38edfSJianfeng Tan  *
80367fa62bcSAdrien Mazarguil  * @return
80467fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
80567fa62bcSAdrien Mazarguil  */
80667fa62bcSAdrien Mazarguil static inline uint32_t
80767fa62bcSAdrien Mazarguil rxq_cq_to_pkt_type(uint32_t flags)
80867fa62bcSAdrien Mazarguil {
80967fa62bcSAdrien Mazarguil 	uint32_t pkt_type;
81067fa62bcSAdrien Mazarguil 
81167fa62bcSAdrien Mazarguil 	if (flags & IBV_EXP_CQ_RX_TUNNEL_PACKET)
81267fa62bcSAdrien Mazarguil 		pkt_type =
81367fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
81467fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV4_PACKET,
81567fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
81667fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
81767fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IPV6_PACKET,
81867fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6) |
81967fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
82067fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV4_PACKET,
82167fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV4) |
82267fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
82367fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV6_PACKET,
82467fa62bcSAdrien Mazarguil 				  RTE_PTYPE_INNER_L3_IPV6);
82567fa62bcSAdrien Mazarguil 	else
82667fa62bcSAdrien Mazarguil 		pkt_type =
82767fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
82867fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV4_PACKET,
82967fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV4) |
83067fa62bcSAdrien Mazarguil 			TRANSPOSE(flags,
83167fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_IPV6_PACKET,
83267fa62bcSAdrien Mazarguil 				  RTE_PTYPE_L3_IPV6);
83367fa62bcSAdrien Mazarguil 	return pkt_type;
83467fa62bcSAdrien Mazarguil }
83567fa62bcSAdrien Mazarguil 
83667fa62bcSAdrien Mazarguil /**
83767fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
83867fa62bcSAdrien Mazarguil  *
83967fa62bcSAdrien Mazarguil  * @param[in] rxq
84067fa62bcSAdrien Mazarguil  *   Pointer to RX queue structure.
84167fa62bcSAdrien Mazarguil  * @param flags
84267fa62bcSAdrien Mazarguil  *   RX completion flags returned by poll_length_flags().
84367fa62bcSAdrien Mazarguil  *
84467fa62bcSAdrien Mazarguil  * @return
84567fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
84667fa62bcSAdrien Mazarguil  */
84767fa62bcSAdrien Mazarguil static inline uint32_t
84867fa62bcSAdrien Mazarguil rxq_cq_to_ol_flags(const struct rxq *rxq, uint32_t flags)
84967fa62bcSAdrien Mazarguil {
85067fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
85167fa62bcSAdrien Mazarguil 
852d0087d76SYaacov Hazan 	if (rxq->csum) {
853d0087d76SYaacov Hazan 		/* Set IP checksum flag only for IPv4/IPv6 packets. */
854d0087d76SYaacov Hazan 		if (flags &
855d0087d76SYaacov Hazan 		    (IBV_EXP_CQ_RX_IPV4_PACKET | IBV_EXP_CQ_RX_IPV6_PACKET))
85667fa62bcSAdrien Mazarguil 			ol_flags |=
85767fa62bcSAdrien Mazarguil 				TRANSPOSE(~flags,
85867fa62bcSAdrien Mazarguil 					IBV_EXP_CQ_RX_IP_CSUM_OK,
859d0087d76SYaacov Hazan 					PKT_RX_IP_CKSUM_BAD);
860d0087d76SYaacov Hazan #ifdef HAVE_EXP_CQ_RX_TCP_PACKET
861d0087d76SYaacov Hazan 		/* Set L4 checksum flag only for TCP/UDP packets. */
862d0087d76SYaacov Hazan 		if (flags &
863d0087d76SYaacov Hazan 		    (IBV_EXP_CQ_RX_TCP_PACKET | IBV_EXP_CQ_RX_UDP_PACKET))
864d0087d76SYaacov Hazan #endif /* HAVE_EXP_CQ_RX_TCP_PACKET */
865d0087d76SYaacov Hazan 			ol_flags |=
86667fa62bcSAdrien Mazarguil 				TRANSPOSE(~flags,
86767fa62bcSAdrien Mazarguil 					IBV_EXP_CQ_RX_TCP_UDP_CSUM_OK,
86867fa62bcSAdrien Mazarguil 					PKT_RX_L4_CKSUM_BAD);
869d0087d76SYaacov Hazan 	}
87067fa62bcSAdrien Mazarguil 	/*
87167fa62bcSAdrien Mazarguil 	 * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place
87267fa62bcSAdrien Mazarguil 	 * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional
87367fa62bcSAdrien Mazarguil 	 * (its value is 0).
87467fa62bcSAdrien Mazarguil 	 */
87567fa62bcSAdrien Mazarguil 	if ((flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun))
87667fa62bcSAdrien Mazarguil 		ol_flags |=
87767fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
87867fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK,
87967fa62bcSAdrien Mazarguil 				  PKT_RX_IP_CKSUM_BAD) |
88067fa62bcSAdrien Mazarguil 			TRANSPOSE(~flags,
88167fa62bcSAdrien Mazarguil 				  IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK,
88267fa62bcSAdrien Mazarguil 				  PKT_RX_L4_CKSUM_BAD);
88367fa62bcSAdrien Mazarguil 	return ol_flags;
88467fa62bcSAdrien Mazarguil }
88567fa62bcSAdrien Mazarguil 
88667fa62bcSAdrien Mazarguil /**
8873ee84446SAdrien Mazarguil  * DPDK callback for RX with scattered packets support.
8883ee84446SAdrien Mazarguil  *
8893ee84446SAdrien Mazarguil  * @param dpdk_rxq
8903ee84446SAdrien Mazarguil  *   Generic pointer to RX queue structure.
8913ee84446SAdrien Mazarguil  * @param[out] pkts
8923ee84446SAdrien Mazarguil  *   Array to store received packets.
8933ee84446SAdrien Mazarguil  * @param pkts_n
8943ee84446SAdrien Mazarguil  *   Maximum number of packets in array.
8953ee84446SAdrien Mazarguil  *
8963ee84446SAdrien Mazarguil  * @return
8973ee84446SAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
8983ee84446SAdrien Mazarguil  */
8993ee84446SAdrien Mazarguil uint16_t
9003ee84446SAdrien Mazarguil mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
9013ee84446SAdrien Mazarguil {
9023ee84446SAdrien Mazarguil 	struct rxq *rxq = (struct rxq *)dpdk_rxq;
9033ee84446SAdrien Mazarguil 	struct rxq_elt_sp (*elts)[rxq->elts_n] = rxq->elts.sp;
9043ee84446SAdrien Mazarguil 	const unsigned int elts_n = rxq->elts_n;
9053ee84446SAdrien Mazarguil 	unsigned int elts_head = rxq->elts_head;
9063ee84446SAdrien Mazarguil 	unsigned int i;
9073ee84446SAdrien Mazarguil 	unsigned int pkts_ret = 0;
9083ee84446SAdrien Mazarguil 	int ret;
9093ee84446SAdrien Mazarguil 
9103ee84446SAdrien Mazarguil 	if (unlikely(!rxq->sp))
9113ee84446SAdrien Mazarguil 		return mlx5_rx_burst(dpdk_rxq, pkts, pkts_n);
9123ee84446SAdrien Mazarguil 	if (unlikely(elts == NULL)) /* See RTE_DEV_CMD_SET_MTU. */
9133ee84446SAdrien Mazarguil 		return 0;
9143ee84446SAdrien Mazarguil 	for (i = 0; (i != pkts_n); ++i) {
9153ee84446SAdrien Mazarguil 		struct rxq_elt_sp *elt = &(*elts)[elts_head];
9163ee84446SAdrien Mazarguil 		unsigned int len;
9173ee84446SAdrien Mazarguil 		unsigned int pkt_buf_len;
9183ee84446SAdrien Mazarguil 		struct rte_mbuf *pkt_buf = NULL; /* Buffer returned in pkts. */
9193ee84446SAdrien Mazarguil 		struct rte_mbuf **pkt_buf_next = &pkt_buf;
9203ee84446SAdrien Mazarguil 		unsigned int seg_headroom = RTE_PKTMBUF_HEADROOM;
9213ee84446SAdrien Mazarguil 		unsigned int j = 0;
9223ee84446SAdrien Mazarguil 		uint32_t flags;
923f3db9489SYaacov Hazan 		uint16_t vlan_tci;
9243ee84446SAdrien Mazarguil 
9253ee84446SAdrien Mazarguil 		/* Sanity checks. */
9263ee84446SAdrien Mazarguil 		assert(elts_head < rxq->elts_n);
9273ee84446SAdrien Mazarguil 		assert(rxq->elts_head < rxq->elts_n);
928e1682023SNelio Laranjeiro 		ret = rxq->poll(rxq->cq, NULL, NULL, &flags, &vlan_tci);
9293ee84446SAdrien Mazarguil 		if (unlikely(ret < 0)) {
9303ee84446SAdrien Mazarguil 			struct ibv_wc wc;
9313ee84446SAdrien Mazarguil 			int wcs_n;
9323ee84446SAdrien Mazarguil 
9333ee84446SAdrien Mazarguil 			DEBUG("rxq=%p, poll_length() failed (ret=%d)",
9343ee84446SAdrien Mazarguil 			      (void *)rxq, ret);
9353ee84446SAdrien Mazarguil 			/* ibv_poll_cq() must be used in case of failure. */
9363ee84446SAdrien Mazarguil 			wcs_n = ibv_poll_cq(rxq->cq, 1, &wc);
9373ee84446SAdrien Mazarguil 			if (unlikely(wcs_n == 0))
9383ee84446SAdrien Mazarguil 				break;
9393ee84446SAdrien Mazarguil 			if (unlikely(wcs_n < 0)) {
9403ee84446SAdrien Mazarguil 				DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)",
9413ee84446SAdrien Mazarguil 				      (void *)rxq, wcs_n);
9423ee84446SAdrien Mazarguil 				break;
9433ee84446SAdrien Mazarguil 			}
9443ee84446SAdrien Mazarguil 			assert(wcs_n == 1);
9453ee84446SAdrien Mazarguil 			if (unlikely(wc.status != IBV_WC_SUCCESS)) {
9463ee84446SAdrien Mazarguil 				/* Whatever, just repost the offending WR. */
9473ee84446SAdrien Mazarguil 				DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work"
9483ee84446SAdrien Mazarguil 				      " completion status (%d): %s",
9493ee84446SAdrien Mazarguil 				      (void *)rxq, wc.wr_id, wc.status,
9503ee84446SAdrien Mazarguil 				      ibv_wc_status_str(wc.status));
95187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
95287011737SAdrien Mazarguil 				/* Increment dropped packets counter. */
95387011737SAdrien Mazarguil 				++rxq->stats.idropped;
95487011737SAdrien Mazarguil #endif
9553ee84446SAdrien Mazarguil 				goto repost;
9563ee84446SAdrien Mazarguil 			}
9573ee84446SAdrien Mazarguil 			ret = wc.byte_len;
9583ee84446SAdrien Mazarguil 		}
9593ee84446SAdrien Mazarguil 		if (ret == 0)
9603ee84446SAdrien Mazarguil 			break;
9614d326709SOlga Shern 		assert(ret >= (rxq->crc_present << 2));
9624d326709SOlga Shern 		len = ret - (rxq->crc_present << 2);
9633ee84446SAdrien Mazarguil 		pkt_buf_len = len;
9643ee84446SAdrien Mazarguil 		/*
9653ee84446SAdrien Mazarguil 		 * Replace spent segments with new ones, concatenate and
9663ee84446SAdrien Mazarguil 		 * return them as pkt_buf.
9673ee84446SAdrien Mazarguil 		 */
9683ee84446SAdrien Mazarguil 		while (1) {
9693ee84446SAdrien Mazarguil 			struct ibv_sge *sge = &elt->sges[j];
9703ee84446SAdrien Mazarguil 			struct rte_mbuf *seg = elt->bufs[j];
9713ee84446SAdrien Mazarguil 			struct rte_mbuf *rep;
9723ee84446SAdrien Mazarguil 			unsigned int seg_tailroom;
9733ee84446SAdrien Mazarguil 
974aa7f63abSAdrien Mazarguil 			assert(seg != NULL);
9753ee84446SAdrien Mazarguil 			/*
9763ee84446SAdrien Mazarguil 			 * Fetch initial bytes of packet descriptor into a
9773ee84446SAdrien Mazarguil 			 * cacheline while allocating rep.
9783ee84446SAdrien Mazarguil 			 */
9793ee84446SAdrien Mazarguil 			rte_prefetch0(seg);
980fbfd9955SOlivier Matz 			rep = rte_mbuf_raw_alloc(rxq->mp);
9813ee84446SAdrien Mazarguil 			if (unlikely(rep == NULL)) {
9823ee84446SAdrien Mazarguil 				/*
9833ee84446SAdrien Mazarguil 				 * Unable to allocate a replacement mbuf,
9843ee84446SAdrien Mazarguil 				 * repost WR.
9853ee84446SAdrien Mazarguil 				 */
986aa7f63abSAdrien Mazarguil 				DEBUG("rxq=%p: can't allocate a new mbuf",
987aa7f63abSAdrien Mazarguil 				      (void *)rxq);
9883ee84446SAdrien Mazarguil 				if (pkt_buf != NULL) {
9893ee84446SAdrien Mazarguil 					*pkt_buf_next = NULL;
9903ee84446SAdrien Mazarguil 					rte_pktmbuf_free(pkt_buf);
9913ee84446SAdrien Mazarguil 				}
9923ee84446SAdrien Mazarguil 				/* Increment out of memory counters. */
99387011737SAdrien Mazarguil 				++rxq->stats.rx_nombuf;
9943ee84446SAdrien Mazarguil 				++rxq->priv->dev->data->rx_mbuf_alloc_failed;
9953ee84446SAdrien Mazarguil 				goto repost;
9963ee84446SAdrien Mazarguil 			}
9973ee84446SAdrien Mazarguil #ifndef NDEBUG
9983ee84446SAdrien Mazarguil 			/* Poison user-modifiable fields in rep. */
9993ee84446SAdrien Mazarguil 			NEXT(rep) = (void *)((uintptr_t)-1);
10003ee84446SAdrien Mazarguil 			SET_DATA_OFF(rep, 0xdead);
10013ee84446SAdrien Mazarguil 			DATA_LEN(rep) = 0xd00d;
10023ee84446SAdrien Mazarguil 			PKT_LEN(rep) = 0xdeadd00d;
10033ee84446SAdrien Mazarguil 			NB_SEGS(rep) = 0x2a;
10043ee84446SAdrien Mazarguil 			PORT(rep) = 0x2a;
10053ee84446SAdrien Mazarguil 			rep->ol_flags = -1;
10063ee84446SAdrien Mazarguil #endif
10073ee84446SAdrien Mazarguil 			assert(rep->buf_len == seg->buf_len);
10083ee84446SAdrien Mazarguil 			assert(rep->buf_len == rxq->mb_len);
10093ee84446SAdrien Mazarguil 			/* Reconfigure sge to use rep instead of seg. */
10103ee84446SAdrien Mazarguil 			assert(sge->lkey == rxq->mr->lkey);
10113ee84446SAdrien Mazarguil 			sge->addr = ((uintptr_t)rep->buf_addr + seg_headroom);
10123ee84446SAdrien Mazarguil 			elt->bufs[j] = rep;
10133ee84446SAdrien Mazarguil 			++j;
10143ee84446SAdrien Mazarguil 			/* Update pkt_buf if it's the first segment, or link
10153ee84446SAdrien Mazarguil 			 * seg to the previous one and update pkt_buf_next. */
10163ee84446SAdrien Mazarguil 			*pkt_buf_next = seg;
10173ee84446SAdrien Mazarguil 			pkt_buf_next = &NEXT(seg);
10183ee84446SAdrien Mazarguil 			/* Update seg information. */
10193ee84446SAdrien Mazarguil 			seg_tailroom = (seg->buf_len - seg_headroom);
10203ee84446SAdrien Mazarguil 			assert(sge->length == seg_tailroom);
10213ee84446SAdrien Mazarguil 			SET_DATA_OFF(seg, seg_headroom);
10223ee84446SAdrien Mazarguil 			if (likely(len <= seg_tailroom)) {
10233ee84446SAdrien Mazarguil 				/* Last segment. */
10243ee84446SAdrien Mazarguil 				DATA_LEN(seg) = len;
10253ee84446SAdrien Mazarguil 				PKT_LEN(seg) = len;
10263ee84446SAdrien Mazarguil 				/* Sanity check. */
10273ee84446SAdrien Mazarguil 				assert(rte_pktmbuf_headroom(seg) ==
10283ee84446SAdrien Mazarguil 				       seg_headroom);
10293ee84446SAdrien Mazarguil 				assert(rte_pktmbuf_tailroom(seg) ==
10303ee84446SAdrien Mazarguil 				       (seg_tailroom - len));
10313ee84446SAdrien Mazarguil 				break;
10323ee84446SAdrien Mazarguil 			}
10333ee84446SAdrien Mazarguil 			DATA_LEN(seg) = seg_tailroom;
10343ee84446SAdrien Mazarguil 			PKT_LEN(seg) = seg_tailroom;
10353ee84446SAdrien Mazarguil 			/* Sanity check. */
10363ee84446SAdrien Mazarguil 			assert(rte_pktmbuf_headroom(seg) == seg_headroom);
10373ee84446SAdrien Mazarguil 			assert(rte_pktmbuf_tailroom(seg) == 0);
10383ee84446SAdrien Mazarguil 			/* Fix len and clear headroom for next segments. */
10393ee84446SAdrien Mazarguil 			len -= seg_tailroom;
10403ee84446SAdrien Mazarguil 			seg_headroom = 0;
10413ee84446SAdrien Mazarguil 		}
10423ee84446SAdrien Mazarguil 		/* Update head and tail segments. */
10433ee84446SAdrien Mazarguil 		*pkt_buf_next = NULL;
10443ee84446SAdrien Mazarguil 		assert(pkt_buf != NULL);
10453ee84446SAdrien Mazarguil 		assert(j != 0);
10463ee84446SAdrien Mazarguil 		NB_SEGS(pkt_buf) = j;
10473ee84446SAdrien Mazarguil 		PORT(pkt_buf) = rxq->port_id;
10483ee84446SAdrien Mazarguil 		PKT_LEN(pkt_buf) = pkt_buf_len;
1049081f7eaeSNelio Laranjeiro 		if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip) {
105067fa62bcSAdrien Mazarguil 			pkt_buf->packet_type = rxq_cq_to_pkt_type(flags);
105167fa62bcSAdrien Mazarguil 			pkt_buf->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
1052f3db9489SYaacov Hazan #ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
1053f3db9489SYaacov Hazan 			if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
1054f3db9489SYaacov Hazan 				pkt_buf->ol_flags |= PKT_RX_VLAN_PKT;
1055f3db9489SYaacov Hazan 				pkt_buf->vlan_tci = vlan_tci;
1056f3db9489SYaacov Hazan 			}
1057f3db9489SYaacov Hazan #endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
1058081f7eaeSNelio Laranjeiro 		}
10593ee84446SAdrien Mazarguil 
10603ee84446SAdrien Mazarguil 		/* Return packet. */
10613ee84446SAdrien Mazarguil 		*(pkts++) = pkt_buf;
10623ee84446SAdrien Mazarguil 		++pkts_ret;
106387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
106487011737SAdrien Mazarguil 		/* Increment bytes counter. */
106587011737SAdrien Mazarguil 		rxq->stats.ibytes += pkt_buf_len;
106687011737SAdrien Mazarguil #endif
10673ee84446SAdrien Mazarguil repost:
1068e1682023SNelio Laranjeiro 		ret = rxq->recv(rxq->wq, elt->sges, RTE_DIM(elt->sges));
106961bdf1e0SAdrien Mazarguil 		if (unlikely(ret)) {
107061bdf1e0SAdrien Mazarguil 			/* Inability to repost WRs is fatal. */
107161bdf1e0SAdrien Mazarguil 			DEBUG("%p: recv_sg_list(): failed (ret=%d)",
107261bdf1e0SAdrien Mazarguil 			      (void *)rxq->priv,
107361bdf1e0SAdrien Mazarguil 			      ret);
107461bdf1e0SAdrien Mazarguil 			abort();
107561bdf1e0SAdrien Mazarguil 		}
10763ee84446SAdrien Mazarguil 		if (++elts_head >= elts_n)
10773ee84446SAdrien Mazarguil 			elts_head = 0;
10783ee84446SAdrien Mazarguil 		continue;
10793ee84446SAdrien Mazarguil 	}
10803ee84446SAdrien Mazarguil 	if (unlikely(i == 0))
10813ee84446SAdrien Mazarguil 		return 0;
10823ee84446SAdrien Mazarguil 	rxq->elts_head = elts_head;
108387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
108487011737SAdrien Mazarguil 	/* Increment packets counter. */
108587011737SAdrien Mazarguil 	rxq->stats.ipackets += pkts_ret;
108687011737SAdrien Mazarguil #endif
10873ee84446SAdrien Mazarguil 	return pkts_ret;
10883ee84446SAdrien Mazarguil }
10893ee84446SAdrien Mazarguil 
10903ee84446SAdrien Mazarguil /**
10912e22920bSAdrien Mazarguil  * DPDK callback for RX.
10922e22920bSAdrien Mazarguil  *
10933ee84446SAdrien Mazarguil  * The following function is the same as mlx5_rx_burst_sp(), except it doesn't
10943ee84446SAdrien Mazarguil  * manage scattered packets. Improves performance when MRU is lower than the
10953ee84446SAdrien Mazarguil  * size of the first segment.
10963ee84446SAdrien Mazarguil  *
10972e22920bSAdrien Mazarguil  * @param dpdk_rxq
10982e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
10992e22920bSAdrien Mazarguil  * @param[out] pkts
11002e22920bSAdrien Mazarguil  *   Array to store received packets.
11012e22920bSAdrien Mazarguil  * @param pkts_n
11022e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
11032e22920bSAdrien Mazarguil  *
11042e22920bSAdrien Mazarguil  * @return
11052e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
11062e22920bSAdrien Mazarguil  */
11072e22920bSAdrien Mazarguil uint16_t
11082e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
11092e22920bSAdrien Mazarguil {
11102e22920bSAdrien Mazarguil 	struct rxq *rxq = (struct rxq *)dpdk_rxq;
11112e22920bSAdrien Mazarguil 	struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts.no_sp;
11122e22920bSAdrien Mazarguil 	const unsigned int elts_n = rxq->elts_n;
11132e22920bSAdrien Mazarguil 	unsigned int elts_head = rxq->elts_head;
11142e22920bSAdrien Mazarguil 	struct ibv_sge sges[pkts_n];
11152e22920bSAdrien Mazarguil 	unsigned int i;
11162e22920bSAdrien Mazarguil 	unsigned int pkts_ret = 0;
11172e22920bSAdrien Mazarguil 	int ret;
11182e22920bSAdrien Mazarguil 
11193ee84446SAdrien Mazarguil 	if (unlikely(rxq->sp))
11203ee84446SAdrien Mazarguil 		return mlx5_rx_burst_sp(dpdk_rxq, pkts, pkts_n);
11212e22920bSAdrien Mazarguil 	for (i = 0; (i != pkts_n); ++i) {
11222e22920bSAdrien Mazarguil 		struct rxq_elt *elt = &(*elts)[elts_head];
11232e22920bSAdrien Mazarguil 		unsigned int len;
1124aa7f63abSAdrien Mazarguil 		struct rte_mbuf *seg = elt->buf;
11252e22920bSAdrien Mazarguil 		struct rte_mbuf *rep;
11262e22920bSAdrien Mazarguil 		uint32_t flags;
1127f3db9489SYaacov Hazan 		uint16_t vlan_tci;
11282e22920bSAdrien Mazarguil 
11292e22920bSAdrien Mazarguil 		/* Sanity checks. */
1130aa7f63abSAdrien Mazarguil 		assert(seg != NULL);
11312e22920bSAdrien Mazarguil 		assert(elts_head < rxq->elts_n);
11322e22920bSAdrien Mazarguil 		assert(rxq->elts_head < rxq->elts_n);
11332e22920bSAdrien Mazarguil 		/*
11342e22920bSAdrien Mazarguil 		 * Fetch initial bytes of packet descriptor into a
11352e22920bSAdrien Mazarguil 		 * cacheline while allocating rep.
11362e22920bSAdrien Mazarguil 		 */
11372e22920bSAdrien Mazarguil 		rte_prefetch0(seg);
11382e22920bSAdrien Mazarguil 		rte_prefetch0(&seg->cacheline1);
1139e1682023SNelio Laranjeiro 		ret = rxq->poll(rxq->cq, NULL, NULL, &flags, &vlan_tci);
11402e22920bSAdrien Mazarguil 		if (unlikely(ret < 0)) {
11412e22920bSAdrien Mazarguil 			struct ibv_wc wc;
11422e22920bSAdrien Mazarguil 			int wcs_n;
11432e22920bSAdrien Mazarguil 
11442e22920bSAdrien Mazarguil 			DEBUG("rxq=%p, poll_length() failed (ret=%d)",
11452e22920bSAdrien Mazarguil 			      (void *)rxq, ret);
11462e22920bSAdrien Mazarguil 			/* ibv_poll_cq() must be used in case of failure. */
11472e22920bSAdrien Mazarguil 			wcs_n = ibv_poll_cq(rxq->cq, 1, &wc);
11482e22920bSAdrien Mazarguil 			if (unlikely(wcs_n == 0))
11492e22920bSAdrien Mazarguil 				break;
11502e22920bSAdrien Mazarguil 			if (unlikely(wcs_n < 0)) {
11512e22920bSAdrien Mazarguil 				DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)",
11522e22920bSAdrien Mazarguil 				      (void *)rxq, wcs_n);
11532e22920bSAdrien Mazarguil 				break;
11542e22920bSAdrien Mazarguil 			}
11552e22920bSAdrien Mazarguil 			assert(wcs_n == 1);
11562e22920bSAdrien Mazarguil 			if (unlikely(wc.status != IBV_WC_SUCCESS)) {
11572e22920bSAdrien Mazarguil 				/* Whatever, just repost the offending WR. */
11582e22920bSAdrien Mazarguil 				DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work"
11592e22920bSAdrien Mazarguil 				      " completion status (%d): %s",
11602e22920bSAdrien Mazarguil 				      (void *)rxq, wc.wr_id, wc.status,
11612e22920bSAdrien Mazarguil 				      ibv_wc_status_str(wc.status));
116287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
116387011737SAdrien Mazarguil 				/* Increment dropped packets counter. */
116487011737SAdrien Mazarguil 				++rxq->stats.idropped;
116587011737SAdrien Mazarguil #endif
11662e22920bSAdrien Mazarguil 				/* Add SGE to array for repost. */
11672e22920bSAdrien Mazarguil 				sges[i] = elt->sge;
11682e22920bSAdrien Mazarguil 				goto repost;
11692e22920bSAdrien Mazarguil 			}
11702e22920bSAdrien Mazarguil 			ret = wc.byte_len;
11712e22920bSAdrien Mazarguil 		}
11722e22920bSAdrien Mazarguil 		if (ret == 0)
11732e22920bSAdrien Mazarguil 			break;
11744d326709SOlga Shern 		assert(ret >= (rxq->crc_present << 2));
11754d326709SOlga Shern 		len = ret - (rxq->crc_present << 2);
1176fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
11772e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
11782e22920bSAdrien Mazarguil 			/*
11792e22920bSAdrien Mazarguil 			 * Unable to allocate a replacement mbuf,
11802e22920bSAdrien Mazarguil 			 * repost WR.
11812e22920bSAdrien Mazarguil 			 */
1182aa7f63abSAdrien Mazarguil 			DEBUG("rxq=%p: can't allocate a new mbuf",
1183aa7f63abSAdrien Mazarguil 			      (void *)rxq);
11842e22920bSAdrien Mazarguil 			/* Increment out of memory counters. */
118587011737SAdrien Mazarguil 			++rxq->stats.rx_nombuf;
11862e22920bSAdrien Mazarguil 			++rxq->priv->dev->data->rx_mbuf_alloc_failed;
11872e22920bSAdrien Mazarguil 			goto repost;
11882e22920bSAdrien Mazarguil 		}
11892e22920bSAdrien Mazarguil 
11902e22920bSAdrien Mazarguil 		/* Reconfigure sge to use rep instead of seg. */
11912e22920bSAdrien Mazarguil 		elt->sge.addr = (uintptr_t)rep->buf_addr + RTE_PKTMBUF_HEADROOM;
11922e22920bSAdrien Mazarguil 		assert(elt->sge.lkey == rxq->mr->lkey);
1193aa7f63abSAdrien Mazarguil 		elt->buf = rep;
11942e22920bSAdrien Mazarguil 
11952e22920bSAdrien Mazarguil 		/* Add SGE to array for repost. */
11962e22920bSAdrien Mazarguil 		sges[i] = elt->sge;
11972e22920bSAdrien Mazarguil 
11982e22920bSAdrien Mazarguil 		/* Update seg information. */
11992e22920bSAdrien Mazarguil 		SET_DATA_OFF(seg, RTE_PKTMBUF_HEADROOM);
12002e22920bSAdrien Mazarguil 		NB_SEGS(seg) = 1;
12012e22920bSAdrien Mazarguil 		PORT(seg) = rxq->port_id;
12022e22920bSAdrien Mazarguil 		NEXT(seg) = NULL;
12032e22920bSAdrien Mazarguil 		PKT_LEN(seg) = len;
12042e22920bSAdrien Mazarguil 		DATA_LEN(seg) = len;
1205081f7eaeSNelio Laranjeiro 		if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip) {
120667fa62bcSAdrien Mazarguil 			seg->packet_type = rxq_cq_to_pkt_type(flags);
120767fa62bcSAdrien Mazarguil 			seg->ol_flags = rxq_cq_to_ol_flags(rxq, flags);
1208f3db9489SYaacov Hazan #ifdef HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS
1209f3db9489SYaacov Hazan 			if (flags & IBV_EXP_CQ_RX_CVLAN_STRIPPED_V1) {
1210f3db9489SYaacov Hazan 				seg->ol_flags |= PKT_RX_VLAN_PKT;
1211f3db9489SYaacov Hazan 				seg->vlan_tci = vlan_tci;
1212f3db9489SYaacov Hazan 			}
1213f3db9489SYaacov Hazan #endif /* HAVE_EXP_DEVICE_ATTR_VLAN_OFFLOADS */
1214081f7eaeSNelio Laranjeiro 		}
12152e22920bSAdrien Mazarguil 		/* Return packet. */
12162e22920bSAdrien Mazarguil 		*(pkts++) = seg;
12172e22920bSAdrien Mazarguil 		++pkts_ret;
121887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
121987011737SAdrien Mazarguil 		/* Increment bytes counter. */
122087011737SAdrien Mazarguil 		rxq->stats.ibytes += len;
122187011737SAdrien Mazarguil #endif
12222e22920bSAdrien Mazarguil repost:
12232e22920bSAdrien Mazarguil 		if (++elts_head >= elts_n)
12242e22920bSAdrien Mazarguil 			elts_head = 0;
12252e22920bSAdrien Mazarguil 		continue;
12262e22920bSAdrien Mazarguil 	}
12272e22920bSAdrien Mazarguil 	if (unlikely(i == 0))
12282e22920bSAdrien Mazarguil 		return 0;
12292e22920bSAdrien Mazarguil 	/* Repost WRs. */
12302e22920bSAdrien Mazarguil #ifdef DEBUG_RECV
12312e22920bSAdrien Mazarguil 	DEBUG("%p: reposting %u WRs", (void *)rxq, i);
12322e22920bSAdrien Mazarguil #endif
1233e1682023SNelio Laranjeiro 	ret = rxq->recv(rxq->wq, sges, i);
12342e22920bSAdrien Mazarguil 	if (unlikely(ret)) {
12352e22920bSAdrien Mazarguil 		/* Inability to repost WRs is fatal. */
12362e22920bSAdrien Mazarguil 		DEBUG("%p: recv_burst(): failed (ret=%d)",
12372e22920bSAdrien Mazarguil 		      (void *)rxq->priv,
12382e22920bSAdrien Mazarguil 		      ret);
12392e22920bSAdrien Mazarguil 		abort();
12402e22920bSAdrien Mazarguil 	}
12412e22920bSAdrien Mazarguil 	rxq->elts_head = elts_head;
124287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
124387011737SAdrien Mazarguil 	/* Increment packets counter. */
124487011737SAdrien Mazarguil 	rxq->stats.ipackets += pkts_ret;
124587011737SAdrien Mazarguil #endif
12462e22920bSAdrien Mazarguil 	return pkts_ret;
12472e22920bSAdrien Mazarguil }
12482e22920bSAdrien Mazarguil 
12492e22920bSAdrien Mazarguil /**
12502e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
12512e22920bSAdrien Mazarguil  *
12522e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
12532e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
12542e22920bSAdrien Mazarguil  *
12552e22920bSAdrien Mazarguil  * @param dpdk_txq
12562e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
12572e22920bSAdrien Mazarguil  * @param[in] pkts
12582e22920bSAdrien Mazarguil  *   Packets to transmit.
12592e22920bSAdrien Mazarguil  * @param pkts_n
12602e22920bSAdrien Mazarguil  *   Number of packets in array.
12612e22920bSAdrien Mazarguil  *
12622e22920bSAdrien Mazarguil  * @return
12632e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
12642e22920bSAdrien Mazarguil  */
12652e22920bSAdrien Mazarguil uint16_t
12662e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
12672e22920bSAdrien Mazarguil {
12682e22920bSAdrien Mazarguil 	(void)dpdk_txq;
12692e22920bSAdrien Mazarguil 	(void)pkts;
12702e22920bSAdrien Mazarguil 	(void)pkts_n;
12712e22920bSAdrien Mazarguil 	return 0;
12722e22920bSAdrien Mazarguil }
12732e22920bSAdrien Mazarguil 
12742e22920bSAdrien Mazarguil /**
12752e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
12762e22920bSAdrien Mazarguil  *
12772e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
12782e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
12792e22920bSAdrien Mazarguil  *
12802e22920bSAdrien Mazarguil  * @param dpdk_rxq
12812e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
12822e22920bSAdrien Mazarguil  * @param[out] pkts
12832e22920bSAdrien Mazarguil  *   Array to store received packets.
12842e22920bSAdrien Mazarguil  * @param pkts_n
12852e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
12862e22920bSAdrien Mazarguil  *
12872e22920bSAdrien Mazarguil  * @return
12882e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
12892e22920bSAdrien Mazarguil  */
12902e22920bSAdrien Mazarguil uint16_t
12912e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
12922e22920bSAdrien Mazarguil {
12932e22920bSAdrien Mazarguil 	(void)dpdk_rxq;
12942e22920bSAdrien Mazarguil 	(void)pkts;
12952e22920bSAdrien Mazarguil 	(void)pkts_n;
12962e22920bSAdrien Mazarguil 	return 0;
12972e22920bSAdrien Mazarguil }
1298