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" 652e22920bSAdrien Mazarguil #include "mlx5_defs.h" 662e22920bSAdrien Mazarguil 672e22920bSAdrien Mazarguil /** 682e22920bSAdrien Mazarguil * Manage TX completions. 692e22920bSAdrien Mazarguil * 702e22920bSAdrien Mazarguil * When sending a burst, mlx5_tx_burst() posts several WRs. 712e22920bSAdrien Mazarguil * To improve performance, a completion event is only required once every 722e22920bSAdrien Mazarguil * MLX5_PMD_TX_PER_COMP_REQ sends. Doing so discards completion information 732e22920bSAdrien Mazarguil * for other WRs, but this information would not be used anyway. 742e22920bSAdrien Mazarguil * 752e22920bSAdrien Mazarguil * @param txq 762e22920bSAdrien Mazarguil * Pointer to TX queue structure. 772e22920bSAdrien Mazarguil * 782e22920bSAdrien Mazarguil * @return 792e22920bSAdrien Mazarguil * 0 on success, -1 on failure. 802e22920bSAdrien Mazarguil */ 812e22920bSAdrien Mazarguil static int 822e22920bSAdrien Mazarguil txq_complete(struct txq *txq) 832e22920bSAdrien Mazarguil { 842e22920bSAdrien Mazarguil unsigned int elts_comp = txq->elts_comp; 852e22920bSAdrien Mazarguil unsigned int elts_tail = txq->elts_tail; 862e22920bSAdrien Mazarguil const unsigned int elts_n = txq->elts_n; 872e22920bSAdrien Mazarguil int wcs_n; 882e22920bSAdrien Mazarguil 892e22920bSAdrien Mazarguil if (unlikely(elts_comp == 0)) 902e22920bSAdrien Mazarguil return 0; 912e22920bSAdrien Mazarguil #ifdef DEBUG_SEND 922e22920bSAdrien Mazarguil DEBUG("%p: processing %u work requests completions", 932e22920bSAdrien Mazarguil (void *)txq, elts_comp); 942e22920bSAdrien Mazarguil #endif 952e22920bSAdrien Mazarguil wcs_n = txq->if_cq->poll_cnt(txq->cq, elts_comp); 962e22920bSAdrien Mazarguil if (unlikely(wcs_n == 0)) 972e22920bSAdrien Mazarguil return 0; 982e22920bSAdrien Mazarguil if (unlikely(wcs_n < 0)) { 992e22920bSAdrien Mazarguil DEBUG("%p: ibv_poll_cq() failed (wcs_n=%d)", 1002e22920bSAdrien Mazarguil (void *)txq, wcs_n); 1012e22920bSAdrien Mazarguil return -1; 1022e22920bSAdrien Mazarguil } 1032e22920bSAdrien Mazarguil elts_comp -= wcs_n; 1042e22920bSAdrien Mazarguil assert(elts_comp <= txq->elts_comp); 1052e22920bSAdrien Mazarguil /* 1062e22920bSAdrien Mazarguil * Assume WC status is successful as nothing can be done about it 1072e22920bSAdrien Mazarguil * anyway. 1082e22920bSAdrien Mazarguil */ 1092e22920bSAdrien Mazarguil elts_tail += wcs_n * txq->elts_comp_cd_init; 1102e22920bSAdrien Mazarguil if (elts_tail >= elts_n) 1112e22920bSAdrien Mazarguil elts_tail -= elts_n; 1122e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 1132e22920bSAdrien Mazarguil txq->elts_comp = elts_comp; 1142e22920bSAdrien Mazarguil return 0; 1152e22920bSAdrien Mazarguil } 1162e22920bSAdrien Mazarguil 1172e22920bSAdrien Mazarguil /** 1188340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 1198340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 1208340392eSAdrien Mazarguil * 1218340392eSAdrien Mazarguil * @param buf 1228340392eSAdrien Mazarguil * Pointer to mbuf. 1238340392eSAdrien Mazarguil * 1248340392eSAdrien Mazarguil * @return 1258340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 1268340392eSAdrien Mazarguil */ 1278340392eSAdrien Mazarguil static struct rte_mempool * 1288340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 1298340392eSAdrien Mazarguil { 1308340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 1318340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 1328340392eSAdrien Mazarguil return buf->pool; 1338340392eSAdrien Mazarguil } 1348340392eSAdrien Mazarguil 1358340392eSAdrien Mazarguil /** 1362e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 1372e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 1382e22920bSAdrien Mazarguil * remove an entry first. 1392e22920bSAdrien Mazarguil * 1402e22920bSAdrien Mazarguil * @param txq 1412e22920bSAdrien Mazarguil * Pointer to TX queue structure. 1422e22920bSAdrien Mazarguil * @param[in] mp 1432e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 1442e22920bSAdrien Mazarguil * 1452e22920bSAdrien Mazarguil * @return 1462e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 1472e22920bSAdrien Mazarguil */ 1482e22920bSAdrien Mazarguil static uint32_t 1490a3b350dSOlga Shern txq_mp2mr(struct txq *txq, const struct rte_mempool *mp) 1502e22920bSAdrien Mazarguil { 1512e22920bSAdrien Mazarguil unsigned int i; 1522e22920bSAdrien Mazarguil struct ibv_mr *mr; 1532e22920bSAdrien Mazarguil 1542e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 1552e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 1562e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 1572e22920bSAdrien Mazarguil break; 1582e22920bSAdrien Mazarguil } 1592e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 1602e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 1612e22920bSAdrien Mazarguil assert(txq->mp2mr[i].mr->lkey == txq->mp2mr[i].lkey); 1622e22920bSAdrien Mazarguil return txq->mp2mr[i].lkey; 1632e22920bSAdrien Mazarguil } 1642e22920bSAdrien Mazarguil } 1652e22920bSAdrien Mazarguil /* Add a new entry, register MR first. */ 1660a3b350dSOlga Shern DEBUG("%p: discovered new memory pool \"%s\" (%p)", 1670a3b350dSOlga Shern (void *)txq, mp->name, (const void *)mp); 1682e22920bSAdrien Mazarguil mr = ibv_reg_mr(txq->priv->pd, 1692e22920bSAdrien Mazarguil (void *)mp->elt_va_start, 1702e22920bSAdrien Mazarguil (mp->elt_va_end - mp->elt_va_start), 1712e22920bSAdrien Mazarguil (IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE)); 1722e22920bSAdrien Mazarguil if (unlikely(mr == NULL)) { 1732e22920bSAdrien Mazarguil DEBUG("%p: unable to configure MR, ibv_reg_mr() failed.", 1742e22920bSAdrien Mazarguil (void *)txq); 1752e22920bSAdrien Mazarguil return (uint32_t)-1; 1762e22920bSAdrien Mazarguil } 1772e22920bSAdrien Mazarguil if (unlikely(i == RTE_DIM(txq->mp2mr))) { 1782e22920bSAdrien Mazarguil /* Table is full, remove oldest entry. */ 1792e22920bSAdrien Mazarguil DEBUG("%p: MR <-> MP table full, dropping oldest entry.", 1802e22920bSAdrien Mazarguil (void *)txq); 1812e22920bSAdrien Mazarguil --i; 182ecbfdbadSOlga Shern claim_zero(ibv_dereg_mr(txq->mp2mr[0].mr)); 1832e22920bSAdrien Mazarguil memmove(&txq->mp2mr[0], &txq->mp2mr[1], 1842e22920bSAdrien Mazarguil (sizeof(txq->mp2mr) - sizeof(txq->mp2mr[0]))); 1852e22920bSAdrien Mazarguil } 1862e22920bSAdrien Mazarguil /* Store the new entry. */ 1872e22920bSAdrien Mazarguil txq->mp2mr[i].mp = mp; 1882e22920bSAdrien Mazarguil txq->mp2mr[i].mr = mr; 1892e22920bSAdrien Mazarguil txq->mp2mr[i].lkey = mr->lkey; 1900a3b350dSOlga Shern DEBUG("%p: new MR lkey for MP \"%s\" (%p): 0x%08" PRIu32, 1910a3b350dSOlga Shern (void *)txq, mp->name, (const void *)mp, txq->mp2mr[i].lkey); 1922e22920bSAdrien Mazarguil return txq->mp2mr[i].lkey; 1932e22920bSAdrien Mazarguil } 1942e22920bSAdrien Mazarguil 1950a3b350dSOlga Shern struct txq_mp2mr_mbuf_check_data { 1960a3b350dSOlga Shern const struct rte_mempool *mp; 1970a3b350dSOlga Shern int ret; 1980a3b350dSOlga Shern }; 1990a3b350dSOlga Shern 2000a3b350dSOlga Shern /** 2010a3b350dSOlga Shern * Callback function for rte_mempool_obj_iter() to check whether a given 2020a3b350dSOlga Shern * mempool object looks like a mbuf. 2030a3b350dSOlga Shern * 2040a3b350dSOlga Shern * @param[in, out] arg 2050a3b350dSOlga Shern * Context data (struct txq_mp2mr_mbuf_check_data). Contains mempool pointer 2060a3b350dSOlga Shern * and return value. 2070a3b350dSOlga Shern * @param[in] start 2080a3b350dSOlga Shern * Object start address. 2090a3b350dSOlga Shern * @param[in] end 2100a3b350dSOlga Shern * Object end address. 2110a3b350dSOlga Shern * @param index 2120a3b350dSOlga Shern * Unused. 2130a3b350dSOlga Shern * 2140a3b350dSOlga Shern * @return 2150a3b350dSOlga Shern * Nonzero value when object is not a mbuf. 2160a3b350dSOlga Shern */ 2170a3b350dSOlga Shern static void 2180a3b350dSOlga Shern txq_mp2mr_mbuf_check(void *arg, void *start, void *end, 2190a3b350dSOlga Shern uint32_t index __rte_unused) 2200a3b350dSOlga Shern { 2210a3b350dSOlga Shern struct txq_mp2mr_mbuf_check_data *data = arg; 2220a3b350dSOlga Shern struct rte_mbuf *buf = 2230a3b350dSOlga Shern (void *)((uintptr_t)start + data->mp->header_size); 2240a3b350dSOlga Shern 2250a3b350dSOlga Shern (void)index; 2260a3b350dSOlga Shern /* Check whether mbuf structure fits element size and whether mempool 2270a3b350dSOlga Shern * pointer is valid. */ 2280a3b350dSOlga Shern if (((uintptr_t)end >= (uintptr_t)(buf + 1)) && 2290a3b350dSOlga Shern (buf->pool == data->mp)) 2300a3b350dSOlga Shern data->ret = 0; 2310a3b350dSOlga Shern else 2320a3b350dSOlga Shern data->ret = -1; 2330a3b350dSOlga Shern } 2340a3b350dSOlga Shern 2350a3b350dSOlga Shern /** 2360a3b350dSOlga Shern * Iterator function for rte_mempool_walk() to register existing mempools and 2370a3b350dSOlga Shern * fill the MP to MR cache of a TX queue. 2380a3b350dSOlga Shern * 2390a3b350dSOlga Shern * @param[in] mp 2400a3b350dSOlga Shern * Memory Pool to register. 2410a3b350dSOlga Shern * @param *arg 2420a3b350dSOlga Shern * Pointer to TX queue structure. 2430a3b350dSOlga Shern */ 2440a3b350dSOlga Shern void 2450a3b350dSOlga Shern txq_mp2mr_iter(const struct rte_mempool *mp, void *arg) 2460a3b350dSOlga Shern { 2470a3b350dSOlga Shern struct txq *txq = arg; 2480a3b350dSOlga Shern struct txq_mp2mr_mbuf_check_data data = { 2490a3b350dSOlga Shern .mp = mp, 2500a3b350dSOlga Shern .ret = -1, 2510a3b350dSOlga Shern }; 2520a3b350dSOlga Shern 2530a3b350dSOlga Shern /* Discard empty mempools. */ 2540a3b350dSOlga Shern if (mp->size == 0) 2550a3b350dSOlga Shern return; 2560a3b350dSOlga Shern /* Register mempool only if the first element looks like a mbuf. */ 2570a3b350dSOlga Shern rte_mempool_obj_iter((void *)mp->elt_va_start, 2580a3b350dSOlga Shern 1, 2590a3b350dSOlga Shern mp->header_size + mp->elt_size + mp->trailer_size, 2600a3b350dSOlga Shern 1, 2610a3b350dSOlga Shern mp->elt_pa, 2620a3b350dSOlga Shern mp->pg_num, 2630a3b350dSOlga Shern mp->pg_shift, 2640a3b350dSOlga Shern txq_mp2mr_mbuf_check, 2650a3b350dSOlga Shern &data); 2660a3b350dSOlga Shern if (data.ret) 2670a3b350dSOlga Shern return; 2680a3b350dSOlga Shern txq_mp2mr(txq, mp); 2690a3b350dSOlga Shern } 2700a3b350dSOlga Shern 2713ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1 2723ee84446SAdrien Mazarguil 2733ee84446SAdrien Mazarguil /** 2743ee84446SAdrien Mazarguil * Copy scattered mbuf contents to a single linear buffer. 2753ee84446SAdrien Mazarguil * 2763ee84446SAdrien Mazarguil * @param[out] linear 2773ee84446SAdrien Mazarguil * Linear output buffer. 2783ee84446SAdrien Mazarguil * @param[in] buf 2793ee84446SAdrien Mazarguil * Scattered input buffer. 2803ee84446SAdrien Mazarguil * 2813ee84446SAdrien Mazarguil * @return 2823ee84446SAdrien Mazarguil * Number of bytes copied to the output buffer or 0 if not large enough. 2833ee84446SAdrien Mazarguil */ 2843ee84446SAdrien Mazarguil static unsigned int 2853ee84446SAdrien Mazarguil linearize_mbuf(linear_t *linear, struct rte_mbuf *buf) 2863ee84446SAdrien Mazarguil { 2873ee84446SAdrien Mazarguil unsigned int size = 0; 2883ee84446SAdrien Mazarguil unsigned int offset; 2893ee84446SAdrien Mazarguil 2903ee84446SAdrien Mazarguil do { 2913ee84446SAdrien Mazarguil unsigned int len = DATA_LEN(buf); 2923ee84446SAdrien Mazarguil 2933ee84446SAdrien Mazarguil offset = size; 2943ee84446SAdrien Mazarguil size += len; 2953ee84446SAdrien Mazarguil if (unlikely(size > sizeof(*linear))) 2963ee84446SAdrien Mazarguil return 0; 2973ee84446SAdrien Mazarguil memcpy(&(*linear)[offset], 2983ee84446SAdrien Mazarguil rte_pktmbuf_mtod(buf, uint8_t *), 2993ee84446SAdrien Mazarguil len); 3003ee84446SAdrien Mazarguil buf = NEXT(buf); 3013ee84446SAdrien Mazarguil } while (buf != NULL); 3023ee84446SAdrien Mazarguil return size; 3033ee84446SAdrien Mazarguil } 3043ee84446SAdrien Mazarguil 3053ee84446SAdrien Mazarguil /** 3063ee84446SAdrien Mazarguil * Handle scattered buffers for mlx5_tx_burst(). 3073ee84446SAdrien Mazarguil * 3083ee84446SAdrien Mazarguil * @param txq 3093ee84446SAdrien Mazarguil * TX queue structure. 3103ee84446SAdrien Mazarguil * @param segs 3113ee84446SAdrien Mazarguil * Number of segments in buf. 3123ee84446SAdrien Mazarguil * @param elt 3133ee84446SAdrien Mazarguil * TX queue element to fill. 3143ee84446SAdrien Mazarguil * @param[in] buf 3153ee84446SAdrien Mazarguil * Buffer to process. 3163ee84446SAdrien Mazarguil * @param elts_head 3173ee84446SAdrien Mazarguil * Index of the linear buffer to use if necessary (normally txq->elts_head). 3183ee84446SAdrien Mazarguil * @param[out] sges 3193ee84446SAdrien Mazarguil * Array filled with SGEs on success. 3203ee84446SAdrien Mazarguil * 3213ee84446SAdrien Mazarguil * @return 3223ee84446SAdrien Mazarguil * A structure containing the processed packet size in bytes and the 3233ee84446SAdrien Mazarguil * number of SGEs. Both fields are set to (unsigned int)-1 in case of 3243ee84446SAdrien Mazarguil * failure. 3253ee84446SAdrien Mazarguil */ 3263ee84446SAdrien Mazarguil static struct tx_burst_sg_ret { 3273ee84446SAdrien Mazarguil unsigned int length; 3283ee84446SAdrien Mazarguil unsigned int num; 3293ee84446SAdrien Mazarguil } 3303ee84446SAdrien Mazarguil tx_burst_sg(struct txq *txq, unsigned int segs, struct txq_elt *elt, 3313ee84446SAdrien Mazarguil struct rte_mbuf *buf, unsigned int elts_head, 3323ee84446SAdrien Mazarguil struct ibv_sge (*sges)[MLX5_PMD_SGE_WR_N]) 3333ee84446SAdrien Mazarguil { 3343ee84446SAdrien Mazarguil unsigned int sent_size = 0; 3353ee84446SAdrien Mazarguil unsigned int j; 3363ee84446SAdrien Mazarguil int linearize = 0; 3373ee84446SAdrien Mazarguil 3383ee84446SAdrien Mazarguil /* When there are too many segments, extra segments are 3393ee84446SAdrien Mazarguil * linearized in the last SGE. */ 3403ee84446SAdrien Mazarguil if (unlikely(segs > RTE_DIM(*sges))) { 3413ee84446SAdrien Mazarguil segs = (RTE_DIM(*sges) - 1); 3423ee84446SAdrien Mazarguil linearize = 1; 3433ee84446SAdrien Mazarguil } 3443ee84446SAdrien Mazarguil /* Update element. */ 3453ee84446SAdrien Mazarguil elt->buf = buf; 3463ee84446SAdrien Mazarguil /* Register segments as SGEs. */ 3473ee84446SAdrien Mazarguil for (j = 0; (j != segs); ++j) { 3483ee84446SAdrien Mazarguil struct ibv_sge *sge = &(*sges)[j]; 3493ee84446SAdrien Mazarguil uint32_t lkey; 3503ee84446SAdrien Mazarguil 3513ee84446SAdrien Mazarguil /* Retrieve Memory Region key for this memory pool. */ 3528340392eSAdrien Mazarguil lkey = txq_mp2mr(txq, txq_mb2mp(buf)); 3533ee84446SAdrien Mazarguil if (unlikely(lkey == (uint32_t)-1)) { 3543ee84446SAdrien Mazarguil /* MR does not exist. */ 3553ee84446SAdrien Mazarguil DEBUG("%p: unable to get MP <-> MR association", 3563ee84446SAdrien Mazarguil (void *)txq); 3573ee84446SAdrien Mazarguil /* Clean up TX element. */ 3583ee84446SAdrien Mazarguil elt->buf = NULL; 3593ee84446SAdrien Mazarguil goto stop; 3603ee84446SAdrien Mazarguil } 3613ee84446SAdrien Mazarguil /* Update SGE. */ 3623ee84446SAdrien Mazarguil sge->addr = rte_pktmbuf_mtod(buf, uintptr_t); 3633ee84446SAdrien Mazarguil if (txq->priv->vf) 3643ee84446SAdrien Mazarguil rte_prefetch0((volatile void *) 3653ee84446SAdrien Mazarguil (uintptr_t)sge->addr); 3663ee84446SAdrien Mazarguil sge->length = DATA_LEN(buf); 3673ee84446SAdrien Mazarguil sge->lkey = lkey; 3683ee84446SAdrien Mazarguil sent_size += sge->length; 3693ee84446SAdrien Mazarguil buf = NEXT(buf); 3703ee84446SAdrien Mazarguil } 3713ee84446SAdrien Mazarguil /* If buf is not NULL here and is not going to be linearized, 3723ee84446SAdrien Mazarguil * nb_segs is not valid. */ 3733ee84446SAdrien Mazarguil assert(j == segs); 3743ee84446SAdrien Mazarguil assert((buf == NULL) || (linearize)); 3753ee84446SAdrien Mazarguil /* Linearize extra segments. */ 3763ee84446SAdrien Mazarguil if (linearize) { 3773ee84446SAdrien Mazarguil struct ibv_sge *sge = &(*sges)[segs]; 3783ee84446SAdrien Mazarguil linear_t *linear = &(*txq->elts_linear)[elts_head]; 3793ee84446SAdrien Mazarguil unsigned int size = linearize_mbuf(linear, buf); 3803ee84446SAdrien Mazarguil 3813ee84446SAdrien Mazarguil assert(segs == (RTE_DIM(*sges) - 1)); 3823ee84446SAdrien Mazarguil if (size == 0) { 3833ee84446SAdrien Mazarguil /* Invalid packet. */ 3843ee84446SAdrien Mazarguil DEBUG("%p: packet too large to be linearized.", 3853ee84446SAdrien Mazarguil (void *)txq); 3863ee84446SAdrien Mazarguil /* Clean up TX element. */ 3873ee84446SAdrien Mazarguil elt->buf = NULL; 3883ee84446SAdrien Mazarguil goto stop; 3893ee84446SAdrien Mazarguil } 3903ee84446SAdrien Mazarguil /* If MLX5_PMD_SGE_WR_N is 1, free mbuf immediately. */ 3913ee84446SAdrien Mazarguil if (RTE_DIM(*sges) == 1) { 3923ee84446SAdrien Mazarguil do { 3933ee84446SAdrien Mazarguil struct rte_mbuf *next = NEXT(buf); 3943ee84446SAdrien Mazarguil 3953ee84446SAdrien Mazarguil rte_pktmbuf_free_seg(buf); 3963ee84446SAdrien Mazarguil buf = next; 3973ee84446SAdrien Mazarguil } while (buf != NULL); 3983ee84446SAdrien Mazarguil elt->buf = NULL; 3993ee84446SAdrien Mazarguil } 4003ee84446SAdrien Mazarguil /* Update SGE. */ 4013ee84446SAdrien Mazarguil sge->addr = (uintptr_t)&(*linear)[0]; 4023ee84446SAdrien Mazarguil sge->length = size; 4033ee84446SAdrien Mazarguil sge->lkey = txq->mr_linear->lkey; 4043ee84446SAdrien Mazarguil sent_size += size; 40534d06263SAdrien Mazarguil /* Include last segment. */ 40634d06263SAdrien Mazarguil segs++; 4073ee84446SAdrien Mazarguil } 4083ee84446SAdrien Mazarguil return (struct tx_burst_sg_ret){ 4093ee84446SAdrien Mazarguil .length = sent_size, 4103ee84446SAdrien Mazarguil .num = segs, 4113ee84446SAdrien Mazarguil }; 4123ee84446SAdrien Mazarguil stop: 4133ee84446SAdrien Mazarguil return (struct tx_burst_sg_ret){ 4143ee84446SAdrien Mazarguil .length = -1, 4153ee84446SAdrien Mazarguil .num = -1, 4163ee84446SAdrien Mazarguil }; 4173ee84446SAdrien Mazarguil } 4183ee84446SAdrien Mazarguil 4193ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */ 4203ee84446SAdrien Mazarguil 4212e22920bSAdrien Mazarguil /** 4222e22920bSAdrien Mazarguil * DPDK callback for TX. 4232e22920bSAdrien Mazarguil * 4242e22920bSAdrien Mazarguil * @param dpdk_txq 4252e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 4262e22920bSAdrien Mazarguil * @param[in] pkts 4272e22920bSAdrien Mazarguil * Packets to transmit. 4282e22920bSAdrien Mazarguil * @param pkts_n 4292e22920bSAdrien Mazarguil * Number of packets in array. 4302e22920bSAdrien Mazarguil * 4312e22920bSAdrien Mazarguil * @return 4322e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 4332e22920bSAdrien Mazarguil */ 4342e22920bSAdrien Mazarguil uint16_t 4352e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 4362e22920bSAdrien Mazarguil { 4372e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 4382e22920bSAdrien Mazarguil unsigned int elts_head = txq->elts_head; 4392e22920bSAdrien Mazarguil const unsigned int elts_n = txq->elts_n; 4402e22920bSAdrien Mazarguil unsigned int elts_comp_cd = txq->elts_comp_cd; 4412e22920bSAdrien Mazarguil unsigned int elts_comp = 0; 4422e22920bSAdrien Mazarguil unsigned int i; 4432e22920bSAdrien Mazarguil unsigned int max; 4442e22920bSAdrien Mazarguil int err; 4452e22920bSAdrien Mazarguil 4462e22920bSAdrien Mazarguil assert(elts_comp_cd != 0); 4472e22920bSAdrien Mazarguil txq_complete(txq); 448*4f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 4492e22920bSAdrien Mazarguil if (max > elts_n) 4502e22920bSAdrien Mazarguil max -= elts_n; 4512e22920bSAdrien Mazarguil assert(max >= 1); 4522e22920bSAdrien Mazarguil assert(max <= elts_n); 4532e22920bSAdrien Mazarguil /* Always leave one free entry in the ring. */ 4542e22920bSAdrien Mazarguil --max; 4552e22920bSAdrien Mazarguil if (max == 0) 4562e22920bSAdrien Mazarguil return 0; 4572e22920bSAdrien Mazarguil if (max > pkts_n) 4582e22920bSAdrien Mazarguil max = pkts_n; 4592e22920bSAdrien Mazarguil for (i = 0; (i != max); ++i) { 4602e22920bSAdrien Mazarguil struct rte_mbuf *buf = pkts[i]; 4612e22920bSAdrien Mazarguil unsigned int elts_head_next = 4622e22920bSAdrien Mazarguil (((elts_head + 1) == elts_n) ? 0 : elts_head + 1); 4632e22920bSAdrien Mazarguil struct txq_elt *elt_next = &(*txq->elts)[elts_head_next]; 4642e22920bSAdrien Mazarguil struct txq_elt *elt = &(*txq->elts)[elts_head]; 4652e22920bSAdrien Mazarguil unsigned int segs = NB_SEGS(buf); 46687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 46787011737SAdrien Mazarguil unsigned int sent_size = 0; 46887011737SAdrien Mazarguil #endif 4692e22920bSAdrien Mazarguil uint32_t send_flags = 0; 4702e22920bSAdrien Mazarguil 4712e22920bSAdrien Mazarguil /* Clean up old buffer. */ 4722e22920bSAdrien Mazarguil if (likely(elt->buf != NULL)) { 4732e22920bSAdrien Mazarguil struct rte_mbuf *tmp = elt->buf; 4742e22920bSAdrien Mazarguil 4752e22920bSAdrien Mazarguil /* Faster than rte_pktmbuf_free(). */ 4762e22920bSAdrien Mazarguil do { 4772e22920bSAdrien Mazarguil struct rte_mbuf *next = NEXT(tmp); 4782e22920bSAdrien Mazarguil 4792e22920bSAdrien Mazarguil rte_pktmbuf_free_seg(tmp); 4802e22920bSAdrien Mazarguil tmp = next; 4812e22920bSAdrien Mazarguil } while (tmp != NULL); 4822e22920bSAdrien Mazarguil } 4832e22920bSAdrien Mazarguil /* Request TX completion. */ 4842e22920bSAdrien Mazarguil if (unlikely(--elts_comp_cd == 0)) { 4852e22920bSAdrien Mazarguil elts_comp_cd = txq->elts_comp_cd_init; 4862e22920bSAdrien Mazarguil ++elts_comp; 4872e22920bSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_SIGNALED; 4882e22920bSAdrien Mazarguil } 48967fa62bcSAdrien Mazarguil /* Should we enable HW CKSUM offload */ 49067fa62bcSAdrien Mazarguil if (buf->ol_flags & 49167fa62bcSAdrien Mazarguil (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 49267fa62bcSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_IP_CSUM; 49367fa62bcSAdrien Mazarguil /* HW does not support checksum offloads at arbitrary 49467fa62bcSAdrien Mazarguil * offsets but automatically recognizes the packet 49567fa62bcSAdrien Mazarguil * type. For inner L3/L4 checksums, only VXLAN (UDP) 49667fa62bcSAdrien Mazarguil * tunnels are currently supported. */ 49767fa62bcSAdrien Mazarguil if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type)) 49867fa62bcSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_TUNNEL; 49967fa62bcSAdrien Mazarguil } 5002e22920bSAdrien Mazarguil if (likely(segs == 1)) { 5012e22920bSAdrien Mazarguil uintptr_t addr; 5022e22920bSAdrien Mazarguil uint32_t length; 5032e22920bSAdrien Mazarguil uint32_t lkey; 5042e22920bSAdrien Mazarguil 5052e22920bSAdrien Mazarguil /* Retrieve buffer information. */ 5062e22920bSAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 5072e22920bSAdrien Mazarguil length = DATA_LEN(buf); 5082e22920bSAdrien Mazarguil /* Retrieve Memory Region key for this memory pool. */ 5098340392eSAdrien Mazarguil lkey = txq_mp2mr(txq, txq_mb2mp(buf)); 5102e22920bSAdrien Mazarguil if (unlikely(lkey == (uint32_t)-1)) { 5112e22920bSAdrien Mazarguil /* MR does not exist. */ 5122e22920bSAdrien Mazarguil DEBUG("%p: unable to get MP <-> MR" 5132e22920bSAdrien Mazarguil " association", (void *)txq); 5142e22920bSAdrien Mazarguil /* Clean up TX element. */ 5152e22920bSAdrien Mazarguil elt->buf = NULL; 5162e22920bSAdrien Mazarguil goto stop; 5172e22920bSAdrien Mazarguil } 5182e22920bSAdrien Mazarguil /* Update element. */ 5192e22920bSAdrien Mazarguil elt->buf = buf; 5202e22920bSAdrien Mazarguil if (txq->priv->vf) 5212e22920bSAdrien Mazarguil rte_prefetch0((volatile void *) 5222e22920bSAdrien Mazarguil (uintptr_t)addr); 5232e22920bSAdrien Mazarguil RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf); 5242e22920bSAdrien Mazarguil /* Put packet into send queue. */ 5252e22920bSAdrien Mazarguil #if MLX5_PMD_MAX_INLINE > 0 5262e22920bSAdrien Mazarguil if (length <= txq->max_inline) 5272e22920bSAdrien Mazarguil err = txq->if_qp->send_pending_inline 5282e22920bSAdrien Mazarguil (txq->qp, 5292e22920bSAdrien Mazarguil (void *)addr, 5302e22920bSAdrien Mazarguil length, 5312e22920bSAdrien Mazarguil send_flags); 5322e22920bSAdrien Mazarguil else 5332e22920bSAdrien Mazarguil #endif 5342e22920bSAdrien Mazarguil err = txq->if_qp->send_pending 5352e22920bSAdrien Mazarguil (txq->qp, 5362e22920bSAdrien Mazarguil addr, 5372e22920bSAdrien Mazarguil length, 5382e22920bSAdrien Mazarguil lkey, 5392e22920bSAdrien Mazarguil send_flags); 5402e22920bSAdrien Mazarguil if (unlikely(err)) 5412e22920bSAdrien Mazarguil goto stop; 54287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 54387011737SAdrien Mazarguil sent_size += length; 54487011737SAdrien Mazarguil #endif 5452e22920bSAdrien Mazarguil } else { 5463ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1 5473ee84446SAdrien Mazarguil struct ibv_sge sges[MLX5_PMD_SGE_WR_N]; 5483ee84446SAdrien Mazarguil struct tx_burst_sg_ret ret; 5493ee84446SAdrien Mazarguil 5503ee84446SAdrien Mazarguil ret = tx_burst_sg(txq, segs, elt, buf, elts_head, 5513ee84446SAdrien Mazarguil &sges); 5523ee84446SAdrien Mazarguil if (ret.length == (unsigned int)-1) 5533ee84446SAdrien Mazarguil goto stop; 5543ee84446SAdrien Mazarguil RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf); 5553ee84446SAdrien Mazarguil /* Put SG list into send queue. */ 5563ee84446SAdrien Mazarguil err = txq->if_qp->send_pending_sg_list 5573ee84446SAdrien Mazarguil (txq->qp, 5583ee84446SAdrien Mazarguil sges, 5593ee84446SAdrien Mazarguil ret.num, 5603ee84446SAdrien Mazarguil send_flags); 5613ee84446SAdrien Mazarguil if (unlikely(err)) 5623ee84446SAdrien Mazarguil goto stop; 56387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 56487011737SAdrien Mazarguil sent_size += ret.length; 56587011737SAdrien Mazarguil #endif 5663ee84446SAdrien Mazarguil #else /* MLX5_PMD_SGE_WR_N > 1 */ 5672e22920bSAdrien Mazarguil DEBUG("%p: TX scattered buffers support not" 5682e22920bSAdrien Mazarguil " compiled in", (void *)txq); 5692e22920bSAdrien Mazarguil goto stop; 5703ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */ 5712e22920bSAdrien Mazarguil } 5722e22920bSAdrien Mazarguil elts_head = elts_head_next; 57387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 57487011737SAdrien Mazarguil /* Increment sent bytes counter. */ 57587011737SAdrien Mazarguil txq->stats.obytes += sent_size; 57687011737SAdrien Mazarguil #endif 5772e22920bSAdrien Mazarguil } 5782e22920bSAdrien Mazarguil stop: 5792e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 5802e22920bSAdrien Mazarguil if (unlikely(i == 0)) 5812e22920bSAdrien Mazarguil return 0; 58287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 58387011737SAdrien Mazarguil /* Increment sent packets counter. */ 58487011737SAdrien Mazarguil txq->stats.opackets += i; 58587011737SAdrien Mazarguil #endif 5862e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 5872e22920bSAdrien Mazarguil err = txq->if_qp->send_flush(txq->qp); 5882e22920bSAdrien Mazarguil if (unlikely(err)) { 5892e22920bSAdrien Mazarguil /* A nonzero value is not supposed to be returned. 5902e22920bSAdrien Mazarguil * Nothing can be done about it. */ 5912e22920bSAdrien Mazarguil DEBUG("%p: send_flush() failed with error %d", 5922e22920bSAdrien Mazarguil (void *)txq, err); 5932e22920bSAdrien Mazarguil } 5942e22920bSAdrien Mazarguil txq->elts_head = elts_head; 5952e22920bSAdrien Mazarguil txq->elts_comp += elts_comp; 5962e22920bSAdrien Mazarguil txq->elts_comp_cd = elts_comp_cd; 5972e22920bSAdrien Mazarguil return i; 5982e22920bSAdrien Mazarguil } 5992e22920bSAdrien Mazarguil 6002e22920bSAdrien Mazarguil /** 60167fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 60267fa62bcSAdrien Mazarguil * 60367fa62bcSAdrien Mazarguil * @param flags 60467fa62bcSAdrien Mazarguil * RX completion flags returned by poll_length_flags(). 60567fa62bcSAdrien Mazarguil * 60667fa62bcSAdrien Mazarguil * @return 60767fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 60867fa62bcSAdrien Mazarguil */ 60967fa62bcSAdrien Mazarguil static inline uint32_t 61067fa62bcSAdrien Mazarguil rxq_cq_to_pkt_type(uint32_t flags) 61167fa62bcSAdrien Mazarguil { 61267fa62bcSAdrien Mazarguil uint32_t pkt_type; 61367fa62bcSAdrien Mazarguil 61467fa62bcSAdrien Mazarguil if (flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) 61567fa62bcSAdrien Mazarguil pkt_type = 61667fa62bcSAdrien Mazarguil TRANSPOSE(flags, 61767fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV4_PACKET, 61867fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 61967fa62bcSAdrien Mazarguil TRANSPOSE(flags, 62067fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV6_PACKET, 62167fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6) | 62267fa62bcSAdrien Mazarguil TRANSPOSE(flags, 62367fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 62467fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV4) | 62567fa62bcSAdrien Mazarguil TRANSPOSE(flags, 62667fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 62767fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV6); 62867fa62bcSAdrien Mazarguil else 62967fa62bcSAdrien Mazarguil pkt_type = 63067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 63167fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 63267fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 63367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 63467fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 63567fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6); 63667fa62bcSAdrien Mazarguil return pkt_type; 63767fa62bcSAdrien Mazarguil } 63867fa62bcSAdrien Mazarguil 63967fa62bcSAdrien Mazarguil /** 64067fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 64167fa62bcSAdrien Mazarguil * 64267fa62bcSAdrien Mazarguil * @param[in] rxq 64367fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 64467fa62bcSAdrien Mazarguil * @param flags 64567fa62bcSAdrien Mazarguil * RX completion flags returned by poll_length_flags(). 64667fa62bcSAdrien Mazarguil * 64767fa62bcSAdrien Mazarguil * @return 64867fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 64967fa62bcSAdrien Mazarguil */ 65067fa62bcSAdrien Mazarguil static inline uint32_t 65167fa62bcSAdrien Mazarguil rxq_cq_to_ol_flags(const struct rxq *rxq, uint32_t flags) 65267fa62bcSAdrien Mazarguil { 65367fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 65467fa62bcSAdrien Mazarguil 65567fa62bcSAdrien Mazarguil if (rxq->csum) 65667fa62bcSAdrien Mazarguil ol_flags |= 65767fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 65867fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IP_CSUM_OK, 65967fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 66067fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 66167fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_TCP_UDP_CSUM_OK, 66267fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 66367fa62bcSAdrien Mazarguil /* 66467fa62bcSAdrien Mazarguil * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place 66567fa62bcSAdrien Mazarguil * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional 66667fa62bcSAdrien Mazarguil * (its value is 0). 66767fa62bcSAdrien Mazarguil */ 66867fa62bcSAdrien Mazarguil if ((flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 66967fa62bcSAdrien Mazarguil ol_flags |= 67067fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 67167fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK, 67267fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 67367fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 67467fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK, 67567fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 67667fa62bcSAdrien Mazarguil return ol_flags; 67767fa62bcSAdrien Mazarguil } 67867fa62bcSAdrien Mazarguil 67967fa62bcSAdrien Mazarguil /** 6803ee84446SAdrien Mazarguil * DPDK callback for RX with scattered packets support. 6813ee84446SAdrien Mazarguil * 6823ee84446SAdrien Mazarguil * @param dpdk_rxq 6833ee84446SAdrien Mazarguil * Generic pointer to RX queue structure. 6843ee84446SAdrien Mazarguil * @param[out] pkts 6853ee84446SAdrien Mazarguil * Array to store received packets. 6863ee84446SAdrien Mazarguil * @param pkts_n 6873ee84446SAdrien Mazarguil * Maximum number of packets in array. 6883ee84446SAdrien Mazarguil * 6893ee84446SAdrien Mazarguil * @return 6903ee84446SAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 6913ee84446SAdrien Mazarguil */ 6923ee84446SAdrien Mazarguil uint16_t 6933ee84446SAdrien Mazarguil mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 6943ee84446SAdrien Mazarguil { 6953ee84446SAdrien Mazarguil struct rxq *rxq = (struct rxq *)dpdk_rxq; 6963ee84446SAdrien Mazarguil struct rxq_elt_sp (*elts)[rxq->elts_n] = rxq->elts.sp; 6973ee84446SAdrien Mazarguil const unsigned int elts_n = rxq->elts_n; 6983ee84446SAdrien Mazarguil unsigned int elts_head = rxq->elts_head; 6993ee84446SAdrien Mazarguil unsigned int i; 7003ee84446SAdrien Mazarguil unsigned int pkts_ret = 0; 7013ee84446SAdrien Mazarguil int ret; 7023ee84446SAdrien Mazarguil 7033ee84446SAdrien Mazarguil if (unlikely(!rxq->sp)) 7043ee84446SAdrien Mazarguil return mlx5_rx_burst(dpdk_rxq, pkts, pkts_n); 7053ee84446SAdrien Mazarguil if (unlikely(elts == NULL)) /* See RTE_DEV_CMD_SET_MTU. */ 7063ee84446SAdrien Mazarguil return 0; 7073ee84446SAdrien Mazarguil for (i = 0; (i != pkts_n); ++i) { 7083ee84446SAdrien Mazarguil struct rxq_elt_sp *elt = &(*elts)[elts_head]; 7093ee84446SAdrien Mazarguil unsigned int len; 7103ee84446SAdrien Mazarguil unsigned int pkt_buf_len; 7113ee84446SAdrien Mazarguil struct rte_mbuf *pkt_buf = NULL; /* Buffer returned in pkts. */ 7123ee84446SAdrien Mazarguil struct rte_mbuf **pkt_buf_next = &pkt_buf; 7133ee84446SAdrien Mazarguil unsigned int seg_headroom = RTE_PKTMBUF_HEADROOM; 7143ee84446SAdrien Mazarguil unsigned int j = 0; 7153ee84446SAdrien Mazarguil uint32_t flags; 7163ee84446SAdrien Mazarguil 7173ee84446SAdrien Mazarguil /* Sanity checks. */ 7183ee84446SAdrien Mazarguil assert(elts_head < rxq->elts_n); 7193ee84446SAdrien Mazarguil assert(rxq->elts_head < rxq->elts_n); 7203ee84446SAdrien Mazarguil ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL, 7213ee84446SAdrien Mazarguil &flags); 7223ee84446SAdrien Mazarguil if (unlikely(ret < 0)) { 7233ee84446SAdrien Mazarguil struct ibv_wc wc; 7243ee84446SAdrien Mazarguil int wcs_n; 7253ee84446SAdrien Mazarguil 7263ee84446SAdrien Mazarguil DEBUG("rxq=%p, poll_length() failed (ret=%d)", 7273ee84446SAdrien Mazarguil (void *)rxq, ret); 7283ee84446SAdrien Mazarguil /* ibv_poll_cq() must be used in case of failure. */ 7293ee84446SAdrien Mazarguil wcs_n = ibv_poll_cq(rxq->cq, 1, &wc); 7303ee84446SAdrien Mazarguil if (unlikely(wcs_n == 0)) 7313ee84446SAdrien Mazarguil break; 7323ee84446SAdrien Mazarguil if (unlikely(wcs_n < 0)) { 7333ee84446SAdrien Mazarguil DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)", 7343ee84446SAdrien Mazarguil (void *)rxq, wcs_n); 7353ee84446SAdrien Mazarguil break; 7363ee84446SAdrien Mazarguil } 7373ee84446SAdrien Mazarguil assert(wcs_n == 1); 7383ee84446SAdrien Mazarguil if (unlikely(wc.status != IBV_WC_SUCCESS)) { 7393ee84446SAdrien Mazarguil /* Whatever, just repost the offending WR. */ 7403ee84446SAdrien Mazarguil DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work" 7413ee84446SAdrien Mazarguil " completion status (%d): %s", 7423ee84446SAdrien Mazarguil (void *)rxq, wc.wr_id, wc.status, 7433ee84446SAdrien Mazarguil ibv_wc_status_str(wc.status)); 74487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 74587011737SAdrien Mazarguil /* Increment dropped packets counter. */ 74687011737SAdrien Mazarguil ++rxq->stats.idropped; 74787011737SAdrien Mazarguil #endif 7483ee84446SAdrien Mazarguil goto repost; 7493ee84446SAdrien Mazarguil } 7503ee84446SAdrien Mazarguil ret = wc.byte_len; 7513ee84446SAdrien Mazarguil } 7523ee84446SAdrien Mazarguil if (ret == 0) 7533ee84446SAdrien Mazarguil break; 7543ee84446SAdrien Mazarguil len = ret; 7553ee84446SAdrien Mazarguil pkt_buf_len = len; 7563ee84446SAdrien Mazarguil /* 7573ee84446SAdrien Mazarguil * Replace spent segments with new ones, concatenate and 7583ee84446SAdrien Mazarguil * return them as pkt_buf. 7593ee84446SAdrien Mazarguil */ 7603ee84446SAdrien Mazarguil while (1) { 7613ee84446SAdrien Mazarguil struct ibv_sge *sge = &elt->sges[j]; 7623ee84446SAdrien Mazarguil struct rte_mbuf *seg = elt->bufs[j]; 7633ee84446SAdrien Mazarguil struct rte_mbuf *rep; 7643ee84446SAdrien Mazarguil unsigned int seg_tailroom; 7653ee84446SAdrien Mazarguil 766aa7f63abSAdrien Mazarguil assert(seg != NULL); 7673ee84446SAdrien Mazarguil /* 7683ee84446SAdrien Mazarguil * Fetch initial bytes of packet descriptor into a 7693ee84446SAdrien Mazarguil * cacheline while allocating rep. 7703ee84446SAdrien Mazarguil */ 7713ee84446SAdrien Mazarguil rte_prefetch0(seg); 7723ee84446SAdrien Mazarguil rep = __rte_mbuf_raw_alloc(rxq->mp); 7733ee84446SAdrien Mazarguil if (unlikely(rep == NULL)) { 7743ee84446SAdrien Mazarguil /* 7753ee84446SAdrien Mazarguil * Unable to allocate a replacement mbuf, 7763ee84446SAdrien Mazarguil * repost WR. 7773ee84446SAdrien Mazarguil */ 778aa7f63abSAdrien Mazarguil DEBUG("rxq=%p: can't allocate a new mbuf", 779aa7f63abSAdrien Mazarguil (void *)rxq); 7803ee84446SAdrien Mazarguil if (pkt_buf != NULL) { 7813ee84446SAdrien Mazarguil *pkt_buf_next = NULL; 7823ee84446SAdrien Mazarguil rte_pktmbuf_free(pkt_buf); 7833ee84446SAdrien Mazarguil } 7843ee84446SAdrien Mazarguil /* Increment out of memory counters. */ 78587011737SAdrien Mazarguil ++rxq->stats.rx_nombuf; 7863ee84446SAdrien Mazarguil ++rxq->priv->dev->data->rx_mbuf_alloc_failed; 7873ee84446SAdrien Mazarguil goto repost; 7883ee84446SAdrien Mazarguil } 7893ee84446SAdrien Mazarguil #ifndef NDEBUG 7903ee84446SAdrien Mazarguil /* Poison user-modifiable fields in rep. */ 7913ee84446SAdrien Mazarguil NEXT(rep) = (void *)((uintptr_t)-1); 7923ee84446SAdrien Mazarguil SET_DATA_OFF(rep, 0xdead); 7933ee84446SAdrien Mazarguil DATA_LEN(rep) = 0xd00d; 7943ee84446SAdrien Mazarguil PKT_LEN(rep) = 0xdeadd00d; 7953ee84446SAdrien Mazarguil NB_SEGS(rep) = 0x2a; 7963ee84446SAdrien Mazarguil PORT(rep) = 0x2a; 7973ee84446SAdrien Mazarguil rep->ol_flags = -1; 7983ee84446SAdrien Mazarguil #endif 7993ee84446SAdrien Mazarguil assert(rep->buf_len == seg->buf_len); 8003ee84446SAdrien Mazarguil assert(rep->buf_len == rxq->mb_len); 8013ee84446SAdrien Mazarguil /* Reconfigure sge to use rep instead of seg. */ 8023ee84446SAdrien Mazarguil assert(sge->lkey == rxq->mr->lkey); 8033ee84446SAdrien Mazarguil sge->addr = ((uintptr_t)rep->buf_addr + seg_headroom); 8043ee84446SAdrien Mazarguil elt->bufs[j] = rep; 8053ee84446SAdrien Mazarguil ++j; 8063ee84446SAdrien Mazarguil /* Update pkt_buf if it's the first segment, or link 8073ee84446SAdrien Mazarguil * seg to the previous one and update pkt_buf_next. */ 8083ee84446SAdrien Mazarguil *pkt_buf_next = seg; 8093ee84446SAdrien Mazarguil pkt_buf_next = &NEXT(seg); 8103ee84446SAdrien Mazarguil /* Update seg information. */ 8113ee84446SAdrien Mazarguil seg_tailroom = (seg->buf_len - seg_headroom); 8123ee84446SAdrien Mazarguil assert(sge->length == seg_tailroom); 8133ee84446SAdrien Mazarguil SET_DATA_OFF(seg, seg_headroom); 8143ee84446SAdrien Mazarguil if (likely(len <= seg_tailroom)) { 8153ee84446SAdrien Mazarguil /* Last segment. */ 8163ee84446SAdrien Mazarguil DATA_LEN(seg) = len; 8173ee84446SAdrien Mazarguil PKT_LEN(seg) = len; 8183ee84446SAdrien Mazarguil /* Sanity check. */ 8193ee84446SAdrien Mazarguil assert(rte_pktmbuf_headroom(seg) == 8203ee84446SAdrien Mazarguil seg_headroom); 8213ee84446SAdrien Mazarguil assert(rte_pktmbuf_tailroom(seg) == 8223ee84446SAdrien Mazarguil (seg_tailroom - len)); 8233ee84446SAdrien Mazarguil break; 8243ee84446SAdrien Mazarguil } 8253ee84446SAdrien Mazarguil DATA_LEN(seg) = seg_tailroom; 8263ee84446SAdrien Mazarguil PKT_LEN(seg) = seg_tailroom; 8273ee84446SAdrien Mazarguil /* Sanity check. */ 8283ee84446SAdrien Mazarguil assert(rte_pktmbuf_headroom(seg) == seg_headroom); 8293ee84446SAdrien Mazarguil assert(rte_pktmbuf_tailroom(seg) == 0); 8303ee84446SAdrien Mazarguil /* Fix len and clear headroom for next segments. */ 8313ee84446SAdrien Mazarguil len -= seg_tailroom; 8323ee84446SAdrien Mazarguil seg_headroom = 0; 8333ee84446SAdrien Mazarguil } 8343ee84446SAdrien Mazarguil /* Update head and tail segments. */ 8353ee84446SAdrien Mazarguil *pkt_buf_next = NULL; 8363ee84446SAdrien Mazarguil assert(pkt_buf != NULL); 8373ee84446SAdrien Mazarguil assert(j != 0); 8383ee84446SAdrien Mazarguil NB_SEGS(pkt_buf) = j; 8393ee84446SAdrien Mazarguil PORT(pkt_buf) = rxq->port_id; 8403ee84446SAdrien Mazarguil PKT_LEN(pkt_buf) = pkt_buf_len; 84167fa62bcSAdrien Mazarguil pkt_buf->packet_type = rxq_cq_to_pkt_type(flags); 84267fa62bcSAdrien Mazarguil pkt_buf->ol_flags = rxq_cq_to_ol_flags(rxq, flags); 8433ee84446SAdrien Mazarguil 8443ee84446SAdrien Mazarguil /* Return packet. */ 8453ee84446SAdrien Mazarguil *(pkts++) = pkt_buf; 8463ee84446SAdrien Mazarguil ++pkts_ret; 84787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 84887011737SAdrien Mazarguil /* Increment bytes counter. */ 84987011737SAdrien Mazarguil rxq->stats.ibytes += pkt_buf_len; 85087011737SAdrien Mazarguil #endif 8513ee84446SAdrien Mazarguil repost: 852ecc1c29dSAdrien Mazarguil ret = rxq->if_wq->recv_sg_list(rxq->wq, 85361bdf1e0SAdrien Mazarguil elt->sges, 85461bdf1e0SAdrien Mazarguil RTE_DIM(elt->sges)); 85561bdf1e0SAdrien Mazarguil if (unlikely(ret)) { 85661bdf1e0SAdrien Mazarguil /* Inability to repost WRs is fatal. */ 85761bdf1e0SAdrien Mazarguil DEBUG("%p: recv_sg_list(): failed (ret=%d)", 85861bdf1e0SAdrien Mazarguil (void *)rxq->priv, 85961bdf1e0SAdrien Mazarguil ret); 86061bdf1e0SAdrien Mazarguil abort(); 86161bdf1e0SAdrien Mazarguil } 8623ee84446SAdrien Mazarguil if (++elts_head >= elts_n) 8633ee84446SAdrien Mazarguil elts_head = 0; 8643ee84446SAdrien Mazarguil continue; 8653ee84446SAdrien Mazarguil } 8663ee84446SAdrien Mazarguil if (unlikely(i == 0)) 8673ee84446SAdrien Mazarguil return 0; 8683ee84446SAdrien Mazarguil rxq->elts_head = elts_head; 86987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 87087011737SAdrien Mazarguil /* Increment packets counter. */ 87187011737SAdrien Mazarguil rxq->stats.ipackets += pkts_ret; 87287011737SAdrien Mazarguil #endif 8733ee84446SAdrien Mazarguil return pkts_ret; 8743ee84446SAdrien Mazarguil } 8753ee84446SAdrien Mazarguil 8763ee84446SAdrien Mazarguil /** 8772e22920bSAdrien Mazarguil * DPDK callback for RX. 8782e22920bSAdrien Mazarguil * 8793ee84446SAdrien Mazarguil * The following function is the same as mlx5_rx_burst_sp(), except it doesn't 8803ee84446SAdrien Mazarguil * manage scattered packets. Improves performance when MRU is lower than the 8813ee84446SAdrien Mazarguil * size of the first segment. 8823ee84446SAdrien Mazarguil * 8832e22920bSAdrien Mazarguil * @param dpdk_rxq 8842e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 8852e22920bSAdrien Mazarguil * @param[out] pkts 8862e22920bSAdrien Mazarguil * Array to store received packets. 8872e22920bSAdrien Mazarguil * @param pkts_n 8882e22920bSAdrien Mazarguil * Maximum number of packets in array. 8892e22920bSAdrien Mazarguil * 8902e22920bSAdrien Mazarguil * @return 8912e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 8922e22920bSAdrien Mazarguil */ 8932e22920bSAdrien Mazarguil uint16_t 8942e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 8952e22920bSAdrien Mazarguil { 8962e22920bSAdrien Mazarguil struct rxq *rxq = (struct rxq *)dpdk_rxq; 8972e22920bSAdrien Mazarguil struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts.no_sp; 8982e22920bSAdrien Mazarguil const unsigned int elts_n = rxq->elts_n; 8992e22920bSAdrien Mazarguil unsigned int elts_head = rxq->elts_head; 9002e22920bSAdrien Mazarguil struct ibv_sge sges[pkts_n]; 9012e22920bSAdrien Mazarguil unsigned int i; 9022e22920bSAdrien Mazarguil unsigned int pkts_ret = 0; 9032e22920bSAdrien Mazarguil int ret; 9042e22920bSAdrien Mazarguil 9053ee84446SAdrien Mazarguil if (unlikely(rxq->sp)) 9063ee84446SAdrien Mazarguil return mlx5_rx_burst_sp(dpdk_rxq, pkts, pkts_n); 9072e22920bSAdrien Mazarguil for (i = 0; (i != pkts_n); ++i) { 9082e22920bSAdrien Mazarguil struct rxq_elt *elt = &(*elts)[elts_head]; 9092e22920bSAdrien Mazarguil unsigned int len; 910aa7f63abSAdrien Mazarguil struct rte_mbuf *seg = elt->buf; 9112e22920bSAdrien Mazarguil struct rte_mbuf *rep; 9122e22920bSAdrien Mazarguil uint32_t flags; 9132e22920bSAdrien Mazarguil 9142e22920bSAdrien Mazarguil /* Sanity checks. */ 915aa7f63abSAdrien Mazarguil assert(seg != NULL); 9162e22920bSAdrien Mazarguil assert(elts_head < rxq->elts_n); 9172e22920bSAdrien Mazarguil assert(rxq->elts_head < rxq->elts_n); 9182e22920bSAdrien Mazarguil /* 9192e22920bSAdrien Mazarguil * Fetch initial bytes of packet descriptor into a 9202e22920bSAdrien Mazarguil * cacheline while allocating rep. 9212e22920bSAdrien Mazarguil */ 9222e22920bSAdrien Mazarguil rte_prefetch0(seg); 9232e22920bSAdrien Mazarguil rte_prefetch0(&seg->cacheline1); 9242e22920bSAdrien Mazarguil ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL, 9252e22920bSAdrien Mazarguil &flags); 9262e22920bSAdrien Mazarguil if (unlikely(ret < 0)) { 9272e22920bSAdrien Mazarguil struct ibv_wc wc; 9282e22920bSAdrien Mazarguil int wcs_n; 9292e22920bSAdrien Mazarguil 9302e22920bSAdrien Mazarguil DEBUG("rxq=%p, poll_length() failed (ret=%d)", 9312e22920bSAdrien Mazarguil (void *)rxq, ret); 9322e22920bSAdrien Mazarguil /* ibv_poll_cq() must be used in case of failure. */ 9332e22920bSAdrien Mazarguil wcs_n = ibv_poll_cq(rxq->cq, 1, &wc); 9342e22920bSAdrien Mazarguil if (unlikely(wcs_n == 0)) 9352e22920bSAdrien Mazarguil break; 9362e22920bSAdrien Mazarguil if (unlikely(wcs_n < 0)) { 9372e22920bSAdrien Mazarguil DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)", 9382e22920bSAdrien Mazarguil (void *)rxq, wcs_n); 9392e22920bSAdrien Mazarguil break; 9402e22920bSAdrien Mazarguil } 9412e22920bSAdrien Mazarguil assert(wcs_n == 1); 9422e22920bSAdrien Mazarguil if (unlikely(wc.status != IBV_WC_SUCCESS)) { 9432e22920bSAdrien Mazarguil /* Whatever, just repost the offending WR. */ 9442e22920bSAdrien Mazarguil DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work" 9452e22920bSAdrien Mazarguil " completion status (%d): %s", 9462e22920bSAdrien Mazarguil (void *)rxq, wc.wr_id, wc.status, 9472e22920bSAdrien Mazarguil ibv_wc_status_str(wc.status)); 94887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 94987011737SAdrien Mazarguil /* Increment dropped packets counter. */ 95087011737SAdrien Mazarguil ++rxq->stats.idropped; 95187011737SAdrien Mazarguil #endif 9522e22920bSAdrien Mazarguil /* Add SGE to array for repost. */ 9532e22920bSAdrien Mazarguil sges[i] = elt->sge; 9542e22920bSAdrien Mazarguil goto repost; 9552e22920bSAdrien Mazarguil } 9562e22920bSAdrien Mazarguil ret = wc.byte_len; 9572e22920bSAdrien Mazarguil } 9582e22920bSAdrien Mazarguil if (ret == 0) 9592e22920bSAdrien Mazarguil break; 9602e22920bSAdrien Mazarguil len = ret; 9612e22920bSAdrien Mazarguil rep = __rte_mbuf_raw_alloc(rxq->mp); 9622e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 9632e22920bSAdrien Mazarguil /* 9642e22920bSAdrien Mazarguil * Unable to allocate a replacement mbuf, 9652e22920bSAdrien Mazarguil * repost WR. 9662e22920bSAdrien Mazarguil */ 967aa7f63abSAdrien Mazarguil DEBUG("rxq=%p: can't allocate a new mbuf", 968aa7f63abSAdrien Mazarguil (void *)rxq); 9692e22920bSAdrien Mazarguil /* Increment out of memory counters. */ 97087011737SAdrien Mazarguil ++rxq->stats.rx_nombuf; 9712e22920bSAdrien Mazarguil ++rxq->priv->dev->data->rx_mbuf_alloc_failed; 9722e22920bSAdrien Mazarguil goto repost; 9732e22920bSAdrien Mazarguil } 9742e22920bSAdrien Mazarguil 9752e22920bSAdrien Mazarguil /* Reconfigure sge to use rep instead of seg. */ 9762e22920bSAdrien Mazarguil elt->sge.addr = (uintptr_t)rep->buf_addr + RTE_PKTMBUF_HEADROOM; 9772e22920bSAdrien Mazarguil assert(elt->sge.lkey == rxq->mr->lkey); 978aa7f63abSAdrien Mazarguil elt->buf = rep; 9792e22920bSAdrien Mazarguil 9802e22920bSAdrien Mazarguil /* Add SGE to array for repost. */ 9812e22920bSAdrien Mazarguil sges[i] = elt->sge; 9822e22920bSAdrien Mazarguil 9832e22920bSAdrien Mazarguil /* Update seg information. */ 9842e22920bSAdrien Mazarguil SET_DATA_OFF(seg, RTE_PKTMBUF_HEADROOM); 9852e22920bSAdrien Mazarguil NB_SEGS(seg) = 1; 9862e22920bSAdrien Mazarguil PORT(seg) = rxq->port_id; 9872e22920bSAdrien Mazarguil NEXT(seg) = NULL; 9882e22920bSAdrien Mazarguil PKT_LEN(seg) = len; 9892e22920bSAdrien Mazarguil DATA_LEN(seg) = len; 99067fa62bcSAdrien Mazarguil seg->packet_type = rxq_cq_to_pkt_type(flags); 99167fa62bcSAdrien Mazarguil seg->ol_flags = rxq_cq_to_ol_flags(rxq, flags); 9922e22920bSAdrien Mazarguil 9932e22920bSAdrien Mazarguil /* Return packet. */ 9942e22920bSAdrien Mazarguil *(pkts++) = seg; 9952e22920bSAdrien Mazarguil ++pkts_ret; 99687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 99787011737SAdrien Mazarguil /* Increment bytes counter. */ 99887011737SAdrien Mazarguil rxq->stats.ibytes += len; 99987011737SAdrien Mazarguil #endif 10002e22920bSAdrien Mazarguil repost: 10012e22920bSAdrien Mazarguil if (++elts_head >= elts_n) 10022e22920bSAdrien Mazarguil elts_head = 0; 10032e22920bSAdrien Mazarguil continue; 10042e22920bSAdrien Mazarguil } 10052e22920bSAdrien Mazarguil if (unlikely(i == 0)) 10062e22920bSAdrien Mazarguil return 0; 10072e22920bSAdrien Mazarguil /* Repost WRs. */ 10082e22920bSAdrien Mazarguil #ifdef DEBUG_RECV 10092e22920bSAdrien Mazarguil DEBUG("%p: reposting %u WRs", (void *)rxq, i); 10102e22920bSAdrien Mazarguil #endif 1011ecc1c29dSAdrien Mazarguil ret = rxq->if_wq->recv_burst(rxq->wq, sges, i); 10122e22920bSAdrien Mazarguil if (unlikely(ret)) { 10132e22920bSAdrien Mazarguil /* Inability to repost WRs is fatal. */ 10142e22920bSAdrien Mazarguil DEBUG("%p: recv_burst(): failed (ret=%d)", 10152e22920bSAdrien Mazarguil (void *)rxq->priv, 10162e22920bSAdrien Mazarguil ret); 10172e22920bSAdrien Mazarguil abort(); 10182e22920bSAdrien Mazarguil } 10192e22920bSAdrien Mazarguil rxq->elts_head = elts_head; 102087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 102187011737SAdrien Mazarguil /* Increment packets counter. */ 102287011737SAdrien Mazarguil rxq->stats.ipackets += pkts_ret; 102387011737SAdrien Mazarguil #endif 10242e22920bSAdrien Mazarguil return pkts_ret; 10252e22920bSAdrien Mazarguil } 10262e22920bSAdrien Mazarguil 10272e22920bSAdrien Mazarguil /** 10282e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 10292e22920bSAdrien Mazarguil * 10302e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 10312e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 10322e22920bSAdrien Mazarguil * 10332e22920bSAdrien Mazarguil * @param dpdk_txq 10342e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 10352e22920bSAdrien Mazarguil * @param[in] pkts 10362e22920bSAdrien Mazarguil * Packets to transmit. 10372e22920bSAdrien Mazarguil * @param pkts_n 10382e22920bSAdrien Mazarguil * Number of packets in array. 10392e22920bSAdrien Mazarguil * 10402e22920bSAdrien Mazarguil * @return 10412e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 10422e22920bSAdrien Mazarguil */ 10432e22920bSAdrien Mazarguil uint16_t 10442e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 10452e22920bSAdrien Mazarguil { 10462e22920bSAdrien Mazarguil (void)dpdk_txq; 10472e22920bSAdrien Mazarguil (void)pkts; 10482e22920bSAdrien Mazarguil (void)pkts_n; 10492e22920bSAdrien Mazarguil return 0; 10502e22920bSAdrien Mazarguil } 10512e22920bSAdrien Mazarguil 10522e22920bSAdrien Mazarguil /** 10532e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 10542e22920bSAdrien Mazarguil * 10552e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 10562e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 10572e22920bSAdrien Mazarguil * 10582e22920bSAdrien Mazarguil * @param dpdk_rxq 10592e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 10602e22920bSAdrien Mazarguil * @param[out] pkts 10612e22920bSAdrien Mazarguil * Array to store received packets. 10622e22920bSAdrien Mazarguil * @param pkts_n 10632e22920bSAdrien Mazarguil * Maximum number of packets in array. 10642e22920bSAdrien Mazarguil * 10652e22920bSAdrien Mazarguil * @return 10662e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 10672e22920bSAdrien Mazarguil */ 10682e22920bSAdrien Mazarguil uint16_t 10692e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 10702e22920bSAdrien Mazarguil { 10712e22920bSAdrien Mazarguil (void)dpdk_rxq; 10722e22920bSAdrien Mazarguil (void)pkts; 10732e22920bSAdrien Mazarguil (void)pkts_n; 10742e22920bSAdrien Mazarguil return 0; 10752e22920bSAdrien Mazarguil } 1076