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