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 /** 1182e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 1192e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 1202e22920bSAdrien Mazarguil * remove an entry first. 1212e22920bSAdrien Mazarguil * 1222e22920bSAdrien Mazarguil * @param txq 1232e22920bSAdrien Mazarguil * Pointer to TX queue structure. 1242e22920bSAdrien Mazarguil * @param[in] mp 1252e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 1262e22920bSAdrien Mazarguil * 1272e22920bSAdrien Mazarguil * @return 1282e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 1292e22920bSAdrien Mazarguil */ 1302e22920bSAdrien Mazarguil static uint32_t 1312e22920bSAdrien Mazarguil txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 1322e22920bSAdrien Mazarguil { 1332e22920bSAdrien Mazarguil unsigned int i; 1342e22920bSAdrien Mazarguil struct ibv_mr *mr; 1352e22920bSAdrien Mazarguil 1362e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 1372e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 1382e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 1392e22920bSAdrien Mazarguil break; 1402e22920bSAdrien Mazarguil } 1412e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 1422e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 1432e22920bSAdrien Mazarguil assert(txq->mp2mr[i].mr->lkey == txq->mp2mr[i].lkey); 1442e22920bSAdrien Mazarguil return txq->mp2mr[i].lkey; 1452e22920bSAdrien Mazarguil } 1462e22920bSAdrien Mazarguil } 1472e22920bSAdrien Mazarguil /* Add a new entry, register MR first. */ 1482e22920bSAdrien Mazarguil DEBUG("%p: discovered new memory pool %p", (void *)txq, (void *)mp); 1492e22920bSAdrien Mazarguil mr = ibv_reg_mr(txq->priv->pd, 1502e22920bSAdrien Mazarguil (void *)mp->elt_va_start, 1512e22920bSAdrien Mazarguil (mp->elt_va_end - mp->elt_va_start), 1522e22920bSAdrien Mazarguil (IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE)); 1532e22920bSAdrien Mazarguil if (unlikely(mr == NULL)) { 1542e22920bSAdrien Mazarguil DEBUG("%p: unable to configure MR, ibv_reg_mr() failed.", 1552e22920bSAdrien Mazarguil (void *)txq); 1562e22920bSAdrien Mazarguil return (uint32_t)-1; 1572e22920bSAdrien Mazarguil } 1582e22920bSAdrien Mazarguil if (unlikely(i == RTE_DIM(txq->mp2mr))) { 1592e22920bSAdrien Mazarguil /* Table is full, remove oldest entry. */ 1602e22920bSAdrien Mazarguil DEBUG("%p: MR <-> MP table full, dropping oldest entry.", 1612e22920bSAdrien Mazarguil (void *)txq); 1622e22920bSAdrien Mazarguil --i; 1632e22920bSAdrien Mazarguil claim_zero(ibv_dereg_mr(txq->mp2mr[i].mr)); 1642e22920bSAdrien Mazarguil memmove(&txq->mp2mr[0], &txq->mp2mr[1], 1652e22920bSAdrien Mazarguil (sizeof(txq->mp2mr) - sizeof(txq->mp2mr[0]))); 1662e22920bSAdrien Mazarguil } 1672e22920bSAdrien Mazarguil /* Store the new entry. */ 1682e22920bSAdrien Mazarguil txq->mp2mr[i].mp = mp; 1692e22920bSAdrien Mazarguil txq->mp2mr[i].mr = mr; 1702e22920bSAdrien Mazarguil txq->mp2mr[i].lkey = mr->lkey; 1712e22920bSAdrien Mazarguil DEBUG("%p: new MR lkey for MP %p: 0x%08" PRIu32, 1722e22920bSAdrien Mazarguil (void *)txq, (void *)mp, txq->mp2mr[i].lkey); 1732e22920bSAdrien Mazarguil return txq->mp2mr[i].lkey; 1742e22920bSAdrien Mazarguil } 1752e22920bSAdrien Mazarguil 1763ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1 1773ee84446SAdrien Mazarguil 1783ee84446SAdrien Mazarguil /** 1793ee84446SAdrien Mazarguil * Copy scattered mbuf contents to a single linear buffer. 1803ee84446SAdrien Mazarguil * 1813ee84446SAdrien Mazarguil * @param[out] linear 1823ee84446SAdrien Mazarguil * Linear output buffer. 1833ee84446SAdrien Mazarguil * @param[in] buf 1843ee84446SAdrien Mazarguil * Scattered input buffer. 1853ee84446SAdrien Mazarguil * 1863ee84446SAdrien Mazarguil * @return 1873ee84446SAdrien Mazarguil * Number of bytes copied to the output buffer or 0 if not large enough. 1883ee84446SAdrien Mazarguil */ 1893ee84446SAdrien Mazarguil static unsigned int 1903ee84446SAdrien Mazarguil linearize_mbuf(linear_t *linear, struct rte_mbuf *buf) 1913ee84446SAdrien Mazarguil { 1923ee84446SAdrien Mazarguil unsigned int size = 0; 1933ee84446SAdrien Mazarguil unsigned int offset; 1943ee84446SAdrien Mazarguil 1953ee84446SAdrien Mazarguil do { 1963ee84446SAdrien Mazarguil unsigned int len = DATA_LEN(buf); 1973ee84446SAdrien Mazarguil 1983ee84446SAdrien Mazarguil offset = size; 1993ee84446SAdrien Mazarguil size += len; 2003ee84446SAdrien Mazarguil if (unlikely(size > sizeof(*linear))) 2013ee84446SAdrien Mazarguil return 0; 2023ee84446SAdrien Mazarguil memcpy(&(*linear)[offset], 2033ee84446SAdrien Mazarguil rte_pktmbuf_mtod(buf, uint8_t *), 2043ee84446SAdrien Mazarguil len); 2053ee84446SAdrien Mazarguil buf = NEXT(buf); 2063ee84446SAdrien Mazarguil } while (buf != NULL); 2073ee84446SAdrien Mazarguil return size; 2083ee84446SAdrien Mazarguil } 2093ee84446SAdrien Mazarguil 2103ee84446SAdrien Mazarguil /** 2113ee84446SAdrien Mazarguil * Handle scattered buffers for mlx5_tx_burst(). 2123ee84446SAdrien Mazarguil * 2133ee84446SAdrien Mazarguil * @param txq 2143ee84446SAdrien Mazarguil * TX queue structure. 2153ee84446SAdrien Mazarguil * @param segs 2163ee84446SAdrien Mazarguil * Number of segments in buf. 2173ee84446SAdrien Mazarguil * @param elt 2183ee84446SAdrien Mazarguil * TX queue element to fill. 2193ee84446SAdrien Mazarguil * @param[in] buf 2203ee84446SAdrien Mazarguil * Buffer to process. 2213ee84446SAdrien Mazarguil * @param elts_head 2223ee84446SAdrien Mazarguil * Index of the linear buffer to use if necessary (normally txq->elts_head). 2233ee84446SAdrien Mazarguil * @param[out] sges 2243ee84446SAdrien Mazarguil * Array filled with SGEs on success. 2253ee84446SAdrien Mazarguil * 2263ee84446SAdrien Mazarguil * @return 2273ee84446SAdrien Mazarguil * A structure containing the processed packet size in bytes and the 2283ee84446SAdrien Mazarguil * number of SGEs. Both fields are set to (unsigned int)-1 in case of 2293ee84446SAdrien Mazarguil * failure. 2303ee84446SAdrien Mazarguil */ 2313ee84446SAdrien Mazarguil static struct tx_burst_sg_ret { 2323ee84446SAdrien Mazarguil unsigned int length; 2333ee84446SAdrien Mazarguil unsigned int num; 2343ee84446SAdrien Mazarguil } 2353ee84446SAdrien Mazarguil tx_burst_sg(struct txq *txq, unsigned int segs, struct txq_elt *elt, 2363ee84446SAdrien Mazarguil struct rte_mbuf *buf, unsigned int elts_head, 2373ee84446SAdrien Mazarguil struct ibv_sge (*sges)[MLX5_PMD_SGE_WR_N]) 2383ee84446SAdrien Mazarguil { 2393ee84446SAdrien Mazarguil unsigned int sent_size = 0; 2403ee84446SAdrien Mazarguil unsigned int j; 2413ee84446SAdrien Mazarguil int linearize = 0; 2423ee84446SAdrien Mazarguil 2433ee84446SAdrien Mazarguil /* When there are too many segments, extra segments are 2443ee84446SAdrien Mazarguil * linearized in the last SGE. */ 2453ee84446SAdrien Mazarguil if (unlikely(segs > RTE_DIM(*sges))) { 2463ee84446SAdrien Mazarguil segs = (RTE_DIM(*sges) - 1); 2473ee84446SAdrien Mazarguil linearize = 1; 2483ee84446SAdrien Mazarguil } 2493ee84446SAdrien Mazarguil /* Update element. */ 2503ee84446SAdrien Mazarguil elt->buf = buf; 2513ee84446SAdrien Mazarguil /* Register segments as SGEs. */ 2523ee84446SAdrien Mazarguil for (j = 0; (j != segs); ++j) { 2533ee84446SAdrien Mazarguil struct ibv_sge *sge = &(*sges)[j]; 2543ee84446SAdrien Mazarguil uint32_t lkey; 2553ee84446SAdrien Mazarguil 2563ee84446SAdrien Mazarguil /* Retrieve Memory Region key for this memory pool. */ 2573ee84446SAdrien Mazarguil lkey = txq_mp2mr(txq, buf->pool); 2583ee84446SAdrien Mazarguil if (unlikely(lkey == (uint32_t)-1)) { 2593ee84446SAdrien Mazarguil /* MR does not exist. */ 2603ee84446SAdrien Mazarguil DEBUG("%p: unable to get MP <-> MR association", 2613ee84446SAdrien Mazarguil (void *)txq); 2623ee84446SAdrien Mazarguil /* Clean up TX element. */ 2633ee84446SAdrien Mazarguil elt->buf = NULL; 2643ee84446SAdrien Mazarguil goto stop; 2653ee84446SAdrien Mazarguil } 2663ee84446SAdrien Mazarguil /* Update SGE. */ 2673ee84446SAdrien Mazarguil sge->addr = rte_pktmbuf_mtod(buf, uintptr_t); 2683ee84446SAdrien Mazarguil if (txq->priv->vf) 2693ee84446SAdrien Mazarguil rte_prefetch0((volatile void *) 2703ee84446SAdrien Mazarguil (uintptr_t)sge->addr); 2713ee84446SAdrien Mazarguil sge->length = DATA_LEN(buf); 2723ee84446SAdrien Mazarguil sge->lkey = lkey; 2733ee84446SAdrien Mazarguil sent_size += sge->length; 2743ee84446SAdrien Mazarguil buf = NEXT(buf); 2753ee84446SAdrien Mazarguil } 2763ee84446SAdrien Mazarguil /* If buf is not NULL here and is not going to be linearized, 2773ee84446SAdrien Mazarguil * nb_segs is not valid. */ 2783ee84446SAdrien Mazarguil assert(j == segs); 2793ee84446SAdrien Mazarguil assert((buf == NULL) || (linearize)); 2803ee84446SAdrien Mazarguil /* Linearize extra segments. */ 2813ee84446SAdrien Mazarguil if (linearize) { 2823ee84446SAdrien Mazarguil struct ibv_sge *sge = &(*sges)[segs]; 2833ee84446SAdrien Mazarguil linear_t *linear = &(*txq->elts_linear)[elts_head]; 2843ee84446SAdrien Mazarguil unsigned int size = linearize_mbuf(linear, buf); 2853ee84446SAdrien Mazarguil 2863ee84446SAdrien Mazarguil assert(segs == (RTE_DIM(*sges) - 1)); 2873ee84446SAdrien Mazarguil if (size == 0) { 2883ee84446SAdrien Mazarguil /* Invalid packet. */ 2893ee84446SAdrien Mazarguil DEBUG("%p: packet too large to be linearized.", 2903ee84446SAdrien Mazarguil (void *)txq); 2913ee84446SAdrien Mazarguil /* Clean up TX element. */ 2923ee84446SAdrien Mazarguil elt->buf = NULL; 2933ee84446SAdrien Mazarguil goto stop; 2943ee84446SAdrien Mazarguil } 2953ee84446SAdrien Mazarguil /* If MLX5_PMD_SGE_WR_N is 1, free mbuf immediately. */ 2963ee84446SAdrien Mazarguil if (RTE_DIM(*sges) == 1) { 2973ee84446SAdrien Mazarguil do { 2983ee84446SAdrien Mazarguil struct rte_mbuf *next = NEXT(buf); 2993ee84446SAdrien Mazarguil 3003ee84446SAdrien Mazarguil rte_pktmbuf_free_seg(buf); 3013ee84446SAdrien Mazarguil buf = next; 3023ee84446SAdrien Mazarguil } while (buf != NULL); 3033ee84446SAdrien Mazarguil elt->buf = NULL; 3043ee84446SAdrien Mazarguil } 3053ee84446SAdrien Mazarguil /* Update SGE. */ 3063ee84446SAdrien Mazarguil sge->addr = (uintptr_t)&(*linear)[0]; 3073ee84446SAdrien Mazarguil sge->length = size; 3083ee84446SAdrien Mazarguil sge->lkey = txq->mr_linear->lkey; 3093ee84446SAdrien Mazarguil sent_size += size; 3103ee84446SAdrien Mazarguil } 3113ee84446SAdrien Mazarguil return (struct tx_burst_sg_ret){ 3123ee84446SAdrien Mazarguil .length = sent_size, 3133ee84446SAdrien Mazarguil .num = segs, 3143ee84446SAdrien Mazarguil }; 3153ee84446SAdrien Mazarguil stop: 3163ee84446SAdrien Mazarguil return (struct tx_burst_sg_ret){ 3173ee84446SAdrien Mazarguil .length = -1, 3183ee84446SAdrien Mazarguil .num = -1, 3193ee84446SAdrien Mazarguil }; 3203ee84446SAdrien Mazarguil } 3213ee84446SAdrien Mazarguil 3223ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */ 3233ee84446SAdrien Mazarguil 3242e22920bSAdrien Mazarguil /** 3252e22920bSAdrien Mazarguil * DPDK callback for TX. 3262e22920bSAdrien Mazarguil * 3272e22920bSAdrien Mazarguil * @param dpdk_txq 3282e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 3292e22920bSAdrien Mazarguil * @param[in] pkts 3302e22920bSAdrien Mazarguil * Packets to transmit. 3312e22920bSAdrien Mazarguil * @param pkts_n 3322e22920bSAdrien Mazarguil * Number of packets in array. 3332e22920bSAdrien Mazarguil * 3342e22920bSAdrien Mazarguil * @return 3352e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 3362e22920bSAdrien Mazarguil */ 3372e22920bSAdrien Mazarguil uint16_t 3382e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 3392e22920bSAdrien Mazarguil { 3402e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 3412e22920bSAdrien Mazarguil unsigned int elts_head = txq->elts_head; 3422e22920bSAdrien Mazarguil const unsigned int elts_tail = txq->elts_tail; 3432e22920bSAdrien Mazarguil const unsigned int elts_n = txq->elts_n; 3442e22920bSAdrien Mazarguil unsigned int elts_comp_cd = txq->elts_comp_cd; 3452e22920bSAdrien Mazarguil unsigned int elts_comp = 0; 3462e22920bSAdrien Mazarguil unsigned int i; 3472e22920bSAdrien Mazarguil unsigned int max; 3482e22920bSAdrien Mazarguil int err; 3492e22920bSAdrien Mazarguil 3502e22920bSAdrien Mazarguil assert(elts_comp_cd != 0); 3512e22920bSAdrien Mazarguil txq_complete(txq); 3522e22920bSAdrien Mazarguil max = (elts_n - (elts_head - elts_tail)); 3532e22920bSAdrien Mazarguil if (max > elts_n) 3542e22920bSAdrien Mazarguil max -= elts_n; 3552e22920bSAdrien Mazarguil assert(max >= 1); 3562e22920bSAdrien Mazarguil assert(max <= elts_n); 3572e22920bSAdrien Mazarguil /* Always leave one free entry in the ring. */ 3582e22920bSAdrien Mazarguil --max; 3592e22920bSAdrien Mazarguil if (max == 0) 3602e22920bSAdrien Mazarguil return 0; 3612e22920bSAdrien Mazarguil if (max > pkts_n) 3622e22920bSAdrien Mazarguil max = pkts_n; 3632e22920bSAdrien Mazarguil for (i = 0; (i != max); ++i) { 3642e22920bSAdrien Mazarguil struct rte_mbuf *buf = pkts[i]; 3652e22920bSAdrien Mazarguil unsigned int elts_head_next = 3662e22920bSAdrien Mazarguil (((elts_head + 1) == elts_n) ? 0 : elts_head + 1); 3672e22920bSAdrien Mazarguil struct txq_elt *elt_next = &(*txq->elts)[elts_head_next]; 3682e22920bSAdrien Mazarguil struct txq_elt *elt = &(*txq->elts)[elts_head]; 3692e22920bSAdrien Mazarguil unsigned int segs = NB_SEGS(buf); 37087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 37187011737SAdrien Mazarguil unsigned int sent_size = 0; 37287011737SAdrien Mazarguil #endif 3732e22920bSAdrien Mazarguil uint32_t send_flags = 0; 3742e22920bSAdrien Mazarguil 3752e22920bSAdrien Mazarguil /* Clean up old buffer. */ 3762e22920bSAdrien Mazarguil if (likely(elt->buf != NULL)) { 3772e22920bSAdrien Mazarguil struct rte_mbuf *tmp = elt->buf; 3782e22920bSAdrien Mazarguil 3792e22920bSAdrien Mazarguil /* Faster than rte_pktmbuf_free(). */ 3802e22920bSAdrien Mazarguil do { 3812e22920bSAdrien Mazarguil struct rte_mbuf *next = NEXT(tmp); 3822e22920bSAdrien Mazarguil 3832e22920bSAdrien Mazarguil rte_pktmbuf_free_seg(tmp); 3842e22920bSAdrien Mazarguil tmp = next; 3852e22920bSAdrien Mazarguil } while (tmp != NULL); 3862e22920bSAdrien Mazarguil } 3872e22920bSAdrien Mazarguil /* Request TX completion. */ 3882e22920bSAdrien Mazarguil if (unlikely(--elts_comp_cd == 0)) { 3892e22920bSAdrien Mazarguil elts_comp_cd = txq->elts_comp_cd_init; 3902e22920bSAdrien Mazarguil ++elts_comp; 3912e22920bSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_SIGNALED; 3922e22920bSAdrien Mazarguil } 39367fa62bcSAdrien Mazarguil /* Should we enable HW CKSUM offload */ 39467fa62bcSAdrien Mazarguil if (buf->ol_flags & 39567fa62bcSAdrien Mazarguil (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 39667fa62bcSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_IP_CSUM; 39767fa62bcSAdrien Mazarguil /* HW does not support checksum offloads at arbitrary 39867fa62bcSAdrien Mazarguil * offsets but automatically recognizes the packet 39967fa62bcSAdrien Mazarguil * type. For inner L3/L4 checksums, only VXLAN (UDP) 40067fa62bcSAdrien Mazarguil * tunnels are currently supported. */ 40167fa62bcSAdrien Mazarguil if (RTE_ETH_IS_TUNNEL_PKT(buf->packet_type)) 40267fa62bcSAdrien Mazarguil send_flags |= IBV_EXP_QP_BURST_TUNNEL; 40367fa62bcSAdrien Mazarguil } 4042e22920bSAdrien Mazarguil if (likely(segs == 1)) { 4052e22920bSAdrien Mazarguil uintptr_t addr; 4062e22920bSAdrien Mazarguil uint32_t length; 4072e22920bSAdrien Mazarguil uint32_t lkey; 4082e22920bSAdrien Mazarguil 4092e22920bSAdrien Mazarguil /* Retrieve buffer information. */ 4102e22920bSAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 4112e22920bSAdrien Mazarguil length = DATA_LEN(buf); 4122e22920bSAdrien Mazarguil /* Retrieve Memory Region key for this memory pool. */ 4132e22920bSAdrien Mazarguil lkey = txq_mp2mr(txq, buf->pool); 4142e22920bSAdrien Mazarguil if (unlikely(lkey == (uint32_t)-1)) { 4152e22920bSAdrien Mazarguil /* MR does not exist. */ 4162e22920bSAdrien Mazarguil DEBUG("%p: unable to get MP <-> MR" 4172e22920bSAdrien Mazarguil " association", (void *)txq); 4182e22920bSAdrien Mazarguil /* Clean up TX element. */ 4192e22920bSAdrien Mazarguil elt->buf = NULL; 4202e22920bSAdrien Mazarguil goto stop; 4212e22920bSAdrien Mazarguil } 4222e22920bSAdrien Mazarguil /* Update element. */ 4232e22920bSAdrien Mazarguil elt->buf = buf; 4242e22920bSAdrien Mazarguil if (txq->priv->vf) 4252e22920bSAdrien Mazarguil rte_prefetch0((volatile void *) 4262e22920bSAdrien Mazarguil (uintptr_t)addr); 4272e22920bSAdrien Mazarguil RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf); 4282e22920bSAdrien Mazarguil /* Put packet into send queue. */ 4292e22920bSAdrien Mazarguil #if MLX5_PMD_MAX_INLINE > 0 4302e22920bSAdrien Mazarguil if (length <= txq->max_inline) 4312e22920bSAdrien Mazarguil err = txq->if_qp->send_pending_inline 4322e22920bSAdrien Mazarguil (txq->qp, 4332e22920bSAdrien Mazarguil (void *)addr, 4342e22920bSAdrien Mazarguil length, 4352e22920bSAdrien Mazarguil send_flags); 4362e22920bSAdrien Mazarguil else 4372e22920bSAdrien Mazarguil #endif 4382e22920bSAdrien Mazarguil err = txq->if_qp->send_pending 4392e22920bSAdrien Mazarguil (txq->qp, 4402e22920bSAdrien Mazarguil addr, 4412e22920bSAdrien Mazarguil length, 4422e22920bSAdrien Mazarguil lkey, 4432e22920bSAdrien Mazarguil send_flags); 4442e22920bSAdrien Mazarguil if (unlikely(err)) 4452e22920bSAdrien Mazarguil goto stop; 44687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 44787011737SAdrien Mazarguil sent_size += length; 44887011737SAdrien Mazarguil #endif 4492e22920bSAdrien Mazarguil } else { 4503ee84446SAdrien Mazarguil #if MLX5_PMD_SGE_WR_N > 1 4513ee84446SAdrien Mazarguil struct ibv_sge sges[MLX5_PMD_SGE_WR_N]; 4523ee84446SAdrien Mazarguil struct tx_burst_sg_ret ret; 4533ee84446SAdrien Mazarguil 4543ee84446SAdrien Mazarguil ret = tx_burst_sg(txq, segs, elt, buf, elts_head, 4553ee84446SAdrien Mazarguil &sges); 4563ee84446SAdrien Mazarguil if (ret.length == (unsigned int)-1) 4573ee84446SAdrien Mazarguil goto stop; 4583ee84446SAdrien Mazarguil RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf); 4593ee84446SAdrien Mazarguil /* Put SG list into send queue. */ 4603ee84446SAdrien Mazarguil err = txq->if_qp->send_pending_sg_list 4613ee84446SAdrien Mazarguil (txq->qp, 4623ee84446SAdrien Mazarguil sges, 4633ee84446SAdrien Mazarguil ret.num, 4643ee84446SAdrien Mazarguil send_flags); 4653ee84446SAdrien Mazarguil if (unlikely(err)) 4663ee84446SAdrien Mazarguil goto stop; 46787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 46887011737SAdrien Mazarguil sent_size += ret.length; 46987011737SAdrien Mazarguil #endif 4703ee84446SAdrien Mazarguil #else /* MLX5_PMD_SGE_WR_N > 1 */ 4712e22920bSAdrien Mazarguil DEBUG("%p: TX scattered buffers support not" 4722e22920bSAdrien Mazarguil " compiled in", (void *)txq); 4732e22920bSAdrien Mazarguil goto stop; 4743ee84446SAdrien Mazarguil #endif /* MLX5_PMD_SGE_WR_N > 1 */ 4752e22920bSAdrien Mazarguil } 4762e22920bSAdrien Mazarguil elts_head = elts_head_next; 47787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 47887011737SAdrien Mazarguil /* Increment sent bytes counter. */ 47987011737SAdrien Mazarguil txq->stats.obytes += sent_size; 48087011737SAdrien Mazarguil #endif 4812e22920bSAdrien Mazarguil } 4822e22920bSAdrien Mazarguil stop: 4832e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 4842e22920bSAdrien Mazarguil if (unlikely(i == 0)) 4852e22920bSAdrien Mazarguil return 0; 48687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 48787011737SAdrien Mazarguil /* Increment sent packets counter. */ 48887011737SAdrien Mazarguil txq->stats.opackets += i; 48987011737SAdrien Mazarguil #endif 4902e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 4912e22920bSAdrien Mazarguil err = txq->if_qp->send_flush(txq->qp); 4922e22920bSAdrien Mazarguil if (unlikely(err)) { 4932e22920bSAdrien Mazarguil /* A nonzero value is not supposed to be returned. 4942e22920bSAdrien Mazarguil * Nothing can be done about it. */ 4952e22920bSAdrien Mazarguil DEBUG("%p: send_flush() failed with error %d", 4962e22920bSAdrien Mazarguil (void *)txq, err); 4972e22920bSAdrien Mazarguil } 4982e22920bSAdrien Mazarguil txq->elts_head = elts_head; 4992e22920bSAdrien Mazarguil txq->elts_comp += elts_comp; 5002e22920bSAdrien Mazarguil txq->elts_comp_cd = elts_comp_cd; 5012e22920bSAdrien Mazarguil return i; 5022e22920bSAdrien Mazarguil } 5032e22920bSAdrien Mazarguil 5042e22920bSAdrien Mazarguil /** 50567fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 50667fa62bcSAdrien Mazarguil * 50767fa62bcSAdrien Mazarguil * @param flags 50867fa62bcSAdrien Mazarguil * RX completion flags returned by poll_length_flags(). 50967fa62bcSAdrien Mazarguil * 51067fa62bcSAdrien Mazarguil * @return 51167fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 51267fa62bcSAdrien Mazarguil */ 51367fa62bcSAdrien Mazarguil static inline uint32_t 51467fa62bcSAdrien Mazarguil rxq_cq_to_pkt_type(uint32_t flags) 51567fa62bcSAdrien Mazarguil { 51667fa62bcSAdrien Mazarguil uint32_t pkt_type; 51767fa62bcSAdrien Mazarguil 51867fa62bcSAdrien Mazarguil if (flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) 51967fa62bcSAdrien Mazarguil pkt_type = 52067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 52167fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV4_PACKET, 52267fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 52367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 52467fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV6_PACKET, 52567fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6) | 52667fa62bcSAdrien Mazarguil TRANSPOSE(flags, 52767fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 52867fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV4) | 52967fa62bcSAdrien Mazarguil TRANSPOSE(flags, 53067fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 53167fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV6); 53267fa62bcSAdrien Mazarguil else 53367fa62bcSAdrien Mazarguil pkt_type = 53467fa62bcSAdrien Mazarguil TRANSPOSE(flags, 53567fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 53667fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 53767fa62bcSAdrien Mazarguil TRANSPOSE(flags, 53867fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 53967fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6); 54067fa62bcSAdrien Mazarguil return pkt_type; 54167fa62bcSAdrien Mazarguil } 54267fa62bcSAdrien Mazarguil 54367fa62bcSAdrien Mazarguil /** 54467fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 54567fa62bcSAdrien Mazarguil * 54667fa62bcSAdrien Mazarguil * @param[in] rxq 54767fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 54867fa62bcSAdrien Mazarguil * @param flags 54967fa62bcSAdrien Mazarguil * RX completion flags returned by poll_length_flags(). 55067fa62bcSAdrien Mazarguil * 55167fa62bcSAdrien Mazarguil * @return 55267fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 55367fa62bcSAdrien Mazarguil */ 55467fa62bcSAdrien Mazarguil static inline uint32_t 55567fa62bcSAdrien Mazarguil rxq_cq_to_ol_flags(const struct rxq *rxq, uint32_t flags) 55667fa62bcSAdrien Mazarguil { 55767fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 55867fa62bcSAdrien Mazarguil 55967fa62bcSAdrien Mazarguil if (rxq->csum) 56067fa62bcSAdrien Mazarguil ol_flags |= 56167fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 56267fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IP_CSUM_OK, 56367fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 56467fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 56567fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_TCP_UDP_CSUM_OK, 56667fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 56767fa62bcSAdrien Mazarguil /* 56867fa62bcSAdrien Mazarguil * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place 56967fa62bcSAdrien Mazarguil * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional 57067fa62bcSAdrien Mazarguil * (its value is 0). 57167fa62bcSAdrien Mazarguil */ 57267fa62bcSAdrien Mazarguil if ((flags & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 57367fa62bcSAdrien Mazarguil ol_flags |= 57467fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 57567fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK, 57667fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 57767fa62bcSAdrien Mazarguil TRANSPOSE(~flags, 57867fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK, 57967fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 58067fa62bcSAdrien Mazarguil return ol_flags; 58167fa62bcSAdrien Mazarguil } 58267fa62bcSAdrien Mazarguil 58367fa62bcSAdrien Mazarguil /** 5843ee84446SAdrien Mazarguil * DPDK callback for RX with scattered packets support. 5853ee84446SAdrien Mazarguil * 5863ee84446SAdrien Mazarguil * @param dpdk_rxq 5873ee84446SAdrien Mazarguil * Generic pointer to RX queue structure. 5883ee84446SAdrien Mazarguil * @param[out] pkts 5893ee84446SAdrien Mazarguil * Array to store received packets. 5903ee84446SAdrien Mazarguil * @param pkts_n 5913ee84446SAdrien Mazarguil * Maximum number of packets in array. 5923ee84446SAdrien Mazarguil * 5933ee84446SAdrien Mazarguil * @return 5943ee84446SAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 5953ee84446SAdrien Mazarguil */ 5963ee84446SAdrien Mazarguil uint16_t 5973ee84446SAdrien Mazarguil mlx5_rx_burst_sp(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 5983ee84446SAdrien Mazarguil { 5993ee84446SAdrien Mazarguil struct rxq *rxq = (struct rxq *)dpdk_rxq; 6003ee84446SAdrien Mazarguil struct rxq_elt_sp (*elts)[rxq->elts_n] = rxq->elts.sp; 6013ee84446SAdrien Mazarguil const unsigned int elts_n = rxq->elts_n; 6023ee84446SAdrien Mazarguil unsigned int elts_head = rxq->elts_head; 6033ee84446SAdrien Mazarguil unsigned int i; 6043ee84446SAdrien Mazarguil unsigned int pkts_ret = 0; 6053ee84446SAdrien Mazarguil int ret; 6063ee84446SAdrien Mazarguil 6073ee84446SAdrien Mazarguil if (unlikely(!rxq->sp)) 6083ee84446SAdrien Mazarguil return mlx5_rx_burst(dpdk_rxq, pkts, pkts_n); 6093ee84446SAdrien Mazarguil if (unlikely(elts == NULL)) /* See RTE_DEV_CMD_SET_MTU. */ 6103ee84446SAdrien Mazarguil return 0; 6113ee84446SAdrien Mazarguil for (i = 0; (i != pkts_n); ++i) { 6123ee84446SAdrien Mazarguil struct rxq_elt_sp *elt = &(*elts)[elts_head]; 6133ee84446SAdrien Mazarguil unsigned int len; 6143ee84446SAdrien Mazarguil unsigned int pkt_buf_len; 6153ee84446SAdrien Mazarguil struct rte_mbuf *pkt_buf = NULL; /* Buffer returned in pkts. */ 6163ee84446SAdrien Mazarguil struct rte_mbuf **pkt_buf_next = &pkt_buf; 6173ee84446SAdrien Mazarguil unsigned int seg_headroom = RTE_PKTMBUF_HEADROOM; 6183ee84446SAdrien Mazarguil unsigned int j = 0; 6193ee84446SAdrien Mazarguil uint32_t flags; 6203ee84446SAdrien Mazarguil 6213ee84446SAdrien Mazarguil /* Sanity checks. */ 6223ee84446SAdrien Mazarguil assert(elts_head < rxq->elts_n); 6233ee84446SAdrien Mazarguil assert(rxq->elts_head < rxq->elts_n); 6243ee84446SAdrien Mazarguil ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL, 6253ee84446SAdrien Mazarguil &flags); 6263ee84446SAdrien Mazarguil if (unlikely(ret < 0)) { 6273ee84446SAdrien Mazarguil struct ibv_wc wc; 6283ee84446SAdrien Mazarguil int wcs_n; 6293ee84446SAdrien Mazarguil 6303ee84446SAdrien Mazarguil DEBUG("rxq=%p, poll_length() failed (ret=%d)", 6313ee84446SAdrien Mazarguil (void *)rxq, ret); 6323ee84446SAdrien Mazarguil /* ibv_poll_cq() must be used in case of failure. */ 6333ee84446SAdrien Mazarguil wcs_n = ibv_poll_cq(rxq->cq, 1, &wc); 6343ee84446SAdrien Mazarguil if (unlikely(wcs_n == 0)) 6353ee84446SAdrien Mazarguil break; 6363ee84446SAdrien Mazarguil if (unlikely(wcs_n < 0)) { 6373ee84446SAdrien Mazarguil DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)", 6383ee84446SAdrien Mazarguil (void *)rxq, wcs_n); 6393ee84446SAdrien Mazarguil break; 6403ee84446SAdrien Mazarguil } 6413ee84446SAdrien Mazarguil assert(wcs_n == 1); 6423ee84446SAdrien Mazarguil if (unlikely(wc.status != IBV_WC_SUCCESS)) { 6433ee84446SAdrien Mazarguil /* Whatever, just repost the offending WR. */ 6443ee84446SAdrien Mazarguil DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work" 6453ee84446SAdrien Mazarguil " completion status (%d): %s", 6463ee84446SAdrien Mazarguil (void *)rxq, wc.wr_id, wc.status, 6473ee84446SAdrien Mazarguil ibv_wc_status_str(wc.status)); 64887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 64987011737SAdrien Mazarguil /* Increment dropped packets counter. */ 65087011737SAdrien Mazarguil ++rxq->stats.idropped; 65187011737SAdrien Mazarguil #endif 6523ee84446SAdrien Mazarguil goto repost; 6533ee84446SAdrien Mazarguil } 6543ee84446SAdrien Mazarguil ret = wc.byte_len; 6553ee84446SAdrien Mazarguil } 6563ee84446SAdrien Mazarguil if (ret == 0) 6573ee84446SAdrien Mazarguil break; 6583ee84446SAdrien Mazarguil len = ret; 6593ee84446SAdrien Mazarguil pkt_buf_len = len; 6603ee84446SAdrien Mazarguil /* 6613ee84446SAdrien Mazarguil * Replace spent segments with new ones, concatenate and 6623ee84446SAdrien Mazarguil * return them as pkt_buf. 6633ee84446SAdrien Mazarguil */ 6643ee84446SAdrien Mazarguil while (1) { 6653ee84446SAdrien Mazarguil struct ibv_sge *sge = &elt->sges[j]; 6663ee84446SAdrien Mazarguil struct rte_mbuf *seg = elt->bufs[j]; 6673ee84446SAdrien Mazarguil struct rte_mbuf *rep; 6683ee84446SAdrien Mazarguil unsigned int seg_tailroom; 6693ee84446SAdrien Mazarguil 670aa7f63abSAdrien Mazarguil assert(seg != NULL); 6713ee84446SAdrien Mazarguil /* 6723ee84446SAdrien Mazarguil * Fetch initial bytes of packet descriptor into a 6733ee84446SAdrien Mazarguil * cacheline while allocating rep. 6743ee84446SAdrien Mazarguil */ 6753ee84446SAdrien Mazarguil rte_prefetch0(seg); 6763ee84446SAdrien Mazarguil rep = __rte_mbuf_raw_alloc(rxq->mp); 6773ee84446SAdrien Mazarguil if (unlikely(rep == NULL)) { 6783ee84446SAdrien Mazarguil /* 6793ee84446SAdrien Mazarguil * Unable to allocate a replacement mbuf, 6803ee84446SAdrien Mazarguil * repost WR. 6813ee84446SAdrien Mazarguil */ 682aa7f63abSAdrien Mazarguil DEBUG("rxq=%p: can't allocate a new mbuf", 683aa7f63abSAdrien Mazarguil (void *)rxq); 6843ee84446SAdrien Mazarguil if (pkt_buf != NULL) { 6853ee84446SAdrien Mazarguil *pkt_buf_next = NULL; 6863ee84446SAdrien Mazarguil rte_pktmbuf_free(pkt_buf); 6873ee84446SAdrien Mazarguil } 6883ee84446SAdrien Mazarguil /* Increment out of memory counters. */ 68987011737SAdrien Mazarguil ++rxq->stats.rx_nombuf; 6903ee84446SAdrien Mazarguil ++rxq->priv->dev->data->rx_mbuf_alloc_failed; 6913ee84446SAdrien Mazarguil goto repost; 6923ee84446SAdrien Mazarguil } 6933ee84446SAdrien Mazarguil #ifndef NDEBUG 6943ee84446SAdrien Mazarguil /* Poison user-modifiable fields in rep. */ 6953ee84446SAdrien Mazarguil NEXT(rep) = (void *)((uintptr_t)-1); 6963ee84446SAdrien Mazarguil SET_DATA_OFF(rep, 0xdead); 6973ee84446SAdrien Mazarguil DATA_LEN(rep) = 0xd00d; 6983ee84446SAdrien Mazarguil PKT_LEN(rep) = 0xdeadd00d; 6993ee84446SAdrien Mazarguil NB_SEGS(rep) = 0x2a; 7003ee84446SAdrien Mazarguil PORT(rep) = 0x2a; 7013ee84446SAdrien Mazarguil rep->ol_flags = -1; 7023ee84446SAdrien Mazarguil #endif 7033ee84446SAdrien Mazarguil assert(rep->buf_len == seg->buf_len); 7043ee84446SAdrien Mazarguil assert(rep->buf_len == rxq->mb_len); 7053ee84446SAdrien Mazarguil /* Reconfigure sge to use rep instead of seg. */ 7063ee84446SAdrien Mazarguil assert(sge->lkey == rxq->mr->lkey); 7073ee84446SAdrien Mazarguil sge->addr = ((uintptr_t)rep->buf_addr + seg_headroom); 7083ee84446SAdrien Mazarguil elt->bufs[j] = rep; 7093ee84446SAdrien Mazarguil ++j; 7103ee84446SAdrien Mazarguil /* Update pkt_buf if it's the first segment, or link 7113ee84446SAdrien Mazarguil * seg to the previous one and update pkt_buf_next. */ 7123ee84446SAdrien Mazarguil *pkt_buf_next = seg; 7133ee84446SAdrien Mazarguil pkt_buf_next = &NEXT(seg); 7143ee84446SAdrien Mazarguil /* Update seg information. */ 7153ee84446SAdrien Mazarguil seg_tailroom = (seg->buf_len - seg_headroom); 7163ee84446SAdrien Mazarguil assert(sge->length == seg_tailroom); 7173ee84446SAdrien Mazarguil SET_DATA_OFF(seg, seg_headroom); 7183ee84446SAdrien Mazarguil if (likely(len <= seg_tailroom)) { 7193ee84446SAdrien Mazarguil /* Last segment. */ 7203ee84446SAdrien Mazarguil DATA_LEN(seg) = len; 7213ee84446SAdrien Mazarguil PKT_LEN(seg) = len; 7223ee84446SAdrien Mazarguil /* Sanity check. */ 7233ee84446SAdrien Mazarguil assert(rte_pktmbuf_headroom(seg) == 7243ee84446SAdrien Mazarguil seg_headroom); 7253ee84446SAdrien Mazarguil assert(rte_pktmbuf_tailroom(seg) == 7263ee84446SAdrien Mazarguil (seg_tailroom - len)); 7273ee84446SAdrien Mazarguil break; 7283ee84446SAdrien Mazarguil } 7293ee84446SAdrien Mazarguil DATA_LEN(seg) = seg_tailroom; 7303ee84446SAdrien Mazarguil PKT_LEN(seg) = seg_tailroom; 7313ee84446SAdrien Mazarguil /* Sanity check. */ 7323ee84446SAdrien Mazarguil assert(rte_pktmbuf_headroom(seg) == seg_headroom); 7333ee84446SAdrien Mazarguil assert(rte_pktmbuf_tailroom(seg) == 0); 7343ee84446SAdrien Mazarguil /* Fix len and clear headroom for next segments. */ 7353ee84446SAdrien Mazarguil len -= seg_tailroom; 7363ee84446SAdrien Mazarguil seg_headroom = 0; 7373ee84446SAdrien Mazarguil } 7383ee84446SAdrien Mazarguil /* Update head and tail segments. */ 7393ee84446SAdrien Mazarguil *pkt_buf_next = NULL; 7403ee84446SAdrien Mazarguil assert(pkt_buf != NULL); 7413ee84446SAdrien Mazarguil assert(j != 0); 7423ee84446SAdrien Mazarguil NB_SEGS(pkt_buf) = j; 7433ee84446SAdrien Mazarguil PORT(pkt_buf) = rxq->port_id; 7443ee84446SAdrien Mazarguil PKT_LEN(pkt_buf) = pkt_buf_len; 74567fa62bcSAdrien Mazarguil pkt_buf->packet_type = rxq_cq_to_pkt_type(flags); 74667fa62bcSAdrien Mazarguil pkt_buf->ol_flags = rxq_cq_to_ol_flags(rxq, flags); 7473ee84446SAdrien Mazarguil 7483ee84446SAdrien Mazarguil /* Return packet. */ 7493ee84446SAdrien Mazarguil *(pkts++) = pkt_buf; 7503ee84446SAdrien Mazarguil ++pkts_ret; 75187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 75287011737SAdrien Mazarguil /* Increment bytes counter. */ 75387011737SAdrien Mazarguil rxq->stats.ibytes += pkt_buf_len; 75487011737SAdrien Mazarguil #endif 7553ee84446SAdrien Mazarguil repost: 756*ecc1c29dSAdrien Mazarguil ret = rxq->if_wq->recv_sg_list(rxq->wq, 75761bdf1e0SAdrien Mazarguil elt->sges, 75861bdf1e0SAdrien Mazarguil RTE_DIM(elt->sges)); 75961bdf1e0SAdrien Mazarguil if (unlikely(ret)) { 76061bdf1e0SAdrien Mazarguil /* Inability to repost WRs is fatal. */ 76161bdf1e0SAdrien Mazarguil DEBUG("%p: recv_sg_list(): failed (ret=%d)", 76261bdf1e0SAdrien Mazarguil (void *)rxq->priv, 76361bdf1e0SAdrien Mazarguil ret); 76461bdf1e0SAdrien Mazarguil abort(); 76561bdf1e0SAdrien Mazarguil } 7663ee84446SAdrien Mazarguil if (++elts_head >= elts_n) 7673ee84446SAdrien Mazarguil elts_head = 0; 7683ee84446SAdrien Mazarguil continue; 7693ee84446SAdrien Mazarguil } 7703ee84446SAdrien Mazarguil if (unlikely(i == 0)) 7713ee84446SAdrien Mazarguil return 0; 7723ee84446SAdrien Mazarguil rxq->elts_head = elts_head; 77387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 77487011737SAdrien Mazarguil /* Increment packets counter. */ 77587011737SAdrien Mazarguil rxq->stats.ipackets += pkts_ret; 77687011737SAdrien Mazarguil #endif 7773ee84446SAdrien Mazarguil return pkts_ret; 7783ee84446SAdrien Mazarguil } 7793ee84446SAdrien Mazarguil 7803ee84446SAdrien Mazarguil /** 7812e22920bSAdrien Mazarguil * DPDK callback for RX. 7822e22920bSAdrien Mazarguil * 7833ee84446SAdrien Mazarguil * The following function is the same as mlx5_rx_burst_sp(), except it doesn't 7843ee84446SAdrien Mazarguil * manage scattered packets. Improves performance when MRU is lower than the 7853ee84446SAdrien Mazarguil * size of the first segment. 7863ee84446SAdrien Mazarguil * 7872e22920bSAdrien Mazarguil * @param dpdk_rxq 7882e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 7892e22920bSAdrien Mazarguil * @param[out] pkts 7902e22920bSAdrien Mazarguil * Array to store received packets. 7912e22920bSAdrien Mazarguil * @param pkts_n 7922e22920bSAdrien Mazarguil * Maximum number of packets in array. 7932e22920bSAdrien Mazarguil * 7942e22920bSAdrien Mazarguil * @return 7952e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 7962e22920bSAdrien Mazarguil */ 7972e22920bSAdrien Mazarguil uint16_t 7982e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 7992e22920bSAdrien Mazarguil { 8002e22920bSAdrien Mazarguil struct rxq *rxq = (struct rxq *)dpdk_rxq; 8012e22920bSAdrien Mazarguil struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts.no_sp; 8022e22920bSAdrien Mazarguil const unsigned int elts_n = rxq->elts_n; 8032e22920bSAdrien Mazarguil unsigned int elts_head = rxq->elts_head; 8042e22920bSAdrien Mazarguil struct ibv_sge sges[pkts_n]; 8052e22920bSAdrien Mazarguil unsigned int i; 8062e22920bSAdrien Mazarguil unsigned int pkts_ret = 0; 8072e22920bSAdrien Mazarguil int ret; 8082e22920bSAdrien Mazarguil 8093ee84446SAdrien Mazarguil if (unlikely(rxq->sp)) 8103ee84446SAdrien Mazarguil return mlx5_rx_burst_sp(dpdk_rxq, pkts, pkts_n); 8112e22920bSAdrien Mazarguil for (i = 0; (i != pkts_n); ++i) { 8122e22920bSAdrien Mazarguil struct rxq_elt *elt = &(*elts)[elts_head]; 8132e22920bSAdrien Mazarguil unsigned int len; 814aa7f63abSAdrien Mazarguil struct rte_mbuf *seg = elt->buf; 8152e22920bSAdrien Mazarguil struct rte_mbuf *rep; 8162e22920bSAdrien Mazarguil uint32_t flags; 8172e22920bSAdrien Mazarguil 8182e22920bSAdrien Mazarguil /* Sanity checks. */ 819aa7f63abSAdrien Mazarguil assert(seg != NULL); 8202e22920bSAdrien Mazarguil assert(elts_head < rxq->elts_n); 8212e22920bSAdrien Mazarguil assert(rxq->elts_head < rxq->elts_n); 8222e22920bSAdrien Mazarguil /* 8232e22920bSAdrien Mazarguil * Fetch initial bytes of packet descriptor into a 8242e22920bSAdrien Mazarguil * cacheline while allocating rep. 8252e22920bSAdrien Mazarguil */ 8262e22920bSAdrien Mazarguil rte_prefetch0(seg); 8272e22920bSAdrien Mazarguil rte_prefetch0(&seg->cacheline1); 8282e22920bSAdrien Mazarguil ret = rxq->if_cq->poll_length_flags(rxq->cq, NULL, NULL, 8292e22920bSAdrien Mazarguil &flags); 8302e22920bSAdrien Mazarguil if (unlikely(ret < 0)) { 8312e22920bSAdrien Mazarguil struct ibv_wc wc; 8322e22920bSAdrien Mazarguil int wcs_n; 8332e22920bSAdrien Mazarguil 8342e22920bSAdrien Mazarguil DEBUG("rxq=%p, poll_length() failed (ret=%d)", 8352e22920bSAdrien Mazarguil (void *)rxq, ret); 8362e22920bSAdrien Mazarguil /* ibv_poll_cq() must be used in case of failure. */ 8372e22920bSAdrien Mazarguil wcs_n = ibv_poll_cq(rxq->cq, 1, &wc); 8382e22920bSAdrien Mazarguil if (unlikely(wcs_n == 0)) 8392e22920bSAdrien Mazarguil break; 8402e22920bSAdrien Mazarguil if (unlikely(wcs_n < 0)) { 8412e22920bSAdrien Mazarguil DEBUG("rxq=%p, ibv_poll_cq() failed (wcs_n=%d)", 8422e22920bSAdrien Mazarguil (void *)rxq, wcs_n); 8432e22920bSAdrien Mazarguil break; 8442e22920bSAdrien Mazarguil } 8452e22920bSAdrien Mazarguil assert(wcs_n == 1); 8462e22920bSAdrien Mazarguil if (unlikely(wc.status != IBV_WC_SUCCESS)) { 8472e22920bSAdrien Mazarguil /* Whatever, just repost the offending WR. */ 8482e22920bSAdrien Mazarguil DEBUG("rxq=%p, wr_id=%" PRIu64 ": bad work" 8492e22920bSAdrien Mazarguil " completion status (%d): %s", 8502e22920bSAdrien Mazarguil (void *)rxq, wc.wr_id, wc.status, 8512e22920bSAdrien Mazarguil ibv_wc_status_str(wc.status)); 85287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 85387011737SAdrien Mazarguil /* Increment dropped packets counter. */ 85487011737SAdrien Mazarguil ++rxq->stats.idropped; 85587011737SAdrien Mazarguil #endif 8562e22920bSAdrien Mazarguil /* Add SGE to array for repost. */ 8572e22920bSAdrien Mazarguil sges[i] = elt->sge; 8582e22920bSAdrien Mazarguil goto repost; 8592e22920bSAdrien Mazarguil } 8602e22920bSAdrien Mazarguil ret = wc.byte_len; 8612e22920bSAdrien Mazarguil } 8622e22920bSAdrien Mazarguil if (ret == 0) 8632e22920bSAdrien Mazarguil break; 8642e22920bSAdrien Mazarguil len = ret; 8652e22920bSAdrien Mazarguil rep = __rte_mbuf_raw_alloc(rxq->mp); 8662e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 8672e22920bSAdrien Mazarguil /* 8682e22920bSAdrien Mazarguil * Unable to allocate a replacement mbuf, 8692e22920bSAdrien Mazarguil * repost WR. 8702e22920bSAdrien Mazarguil */ 871aa7f63abSAdrien Mazarguil DEBUG("rxq=%p: can't allocate a new mbuf", 872aa7f63abSAdrien Mazarguil (void *)rxq); 8732e22920bSAdrien Mazarguil /* Increment out of memory counters. */ 87487011737SAdrien Mazarguil ++rxq->stats.rx_nombuf; 8752e22920bSAdrien Mazarguil ++rxq->priv->dev->data->rx_mbuf_alloc_failed; 8762e22920bSAdrien Mazarguil goto repost; 8772e22920bSAdrien Mazarguil } 8782e22920bSAdrien Mazarguil 8792e22920bSAdrien Mazarguil /* Reconfigure sge to use rep instead of seg. */ 8802e22920bSAdrien Mazarguil elt->sge.addr = (uintptr_t)rep->buf_addr + RTE_PKTMBUF_HEADROOM; 8812e22920bSAdrien Mazarguil assert(elt->sge.lkey == rxq->mr->lkey); 882aa7f63abSAdrien Mazarguil elt->buf = rep; 8832e22920bSAdrien Mazarguil 8842e22920bSAdrien Mazarguil /* Add SGE to array for repost. */ 8852e22920bSAdrien Mazarguil sges[i] = elt->sge; 8862e22920bSAdrien Mazarguil 8872e22920bSAdrien Mazarguil /* Update seg information. */ 8882e22920bSAdrien Mazarguil SET_DATA_OFF(seg, RTE_PKTMBUF_HEADROOM); 8892e22920bSAdrien Mazarguil NB_SEGS(seg) = 1; 8902e22920bSAdrien Mazarguil PORT(seg) = rxq->port_id; 8912e22920bSAdrien Mazarguil NEXT(seg) = NULL; 8922e22920bSAdrien Mazarguil PKT_LEN(seg) = len; 8932e22920bSAdrien Mazarguil DATA_LEN(seg) = len; 89467fa62bcSAdrien Mazarguil seg->packet_type = rxq_cq_to_pkt_type(flags); 89567fa62bcSAdrien Mazarguil seg->ol_flags = rxq_cq_to_ol_flags(rxq, flags); 8962e22920bSAdrien Mazarguil 8972e22920bSAdrien Mazarguil /* Return packet. */ 8982e22920bSAdrien Mazarguil *(pkts++) = seg; 8992e22920bSAdrien Mazarguil ++pkts_ret; 90087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 90187011737SAdrien Mazarguil /* Increment bytes counter. */ 90287011737SAdrien Mazarguil rxq->stats.ibytes += len; 90387011737SAdrien Mazarguil #endif 9042e22920bSAdrien Mazarguil repost: 9052e22920bSAdrien Mazarguil if (++elts_head >= elts_n) 9062e22920bSAdrien Mazarguil elts_head = 0; 9072e22920bSAdrien Mazarguil continue; 9082e22920bSAdrien Mazarguil } 9092e22920bSAdrien Mazarguil if (unlikely(i == 0)) 9102e22920bSAdrien Mazarguil return 0; 9112e22920bSAdrien Mazarguil /* Repost WRs. */ 9122e22920bSAdrien Mazarguil #ifdef DEBUG_RECV 9132e22920bSAdrien Mazarguil DEBUG("%p: reposting %u WRs", (void *)rxq, i); 9142e22920bSAdrien Mazarguil #endif 915*ecc1c29dSAdrien Mazarguil ret = rxq->if_wq->recv_burst(rxq->wq, sges, i); 9162e22920bSAdrien Mazarguil if (unlikely(ret)) { 9172e22920bSAdrien Mazarguil /* Inability to repost WRs is fatal. */ 9182e22920bSAdrien Mazarguil DEBUG("%p: recv_burst(): failed (ret=%d)", 9192e22920bSAdrien Mazarguil (void *)rxq->priv, 9202e22920bSAdrien Mazarguil ret); 9212e22920bSAdrien Mazarguil abort(); 9222e22920bSAdrien Mazarguil } 9232e22920bSAdrien Mazarguil rxq->elts_head = elts_head; 92487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 92587011737SAdrien Mazarguil /* Increment packets counter. */ 92687011737SAdrien Mazarguil rxq->stats.ipackets += pkts_ret; 92787011737SAdrien Mazarguil #endif 9282e22920bSAdrien Mazarguil return pkts_ret; 9292e22920bSAdrien Mazarguil } 9302e22920bSAdrien Mazarguil 9312e22920bSAdrien Mazarguil /** 9322e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 9332e22920bSAdrien Mazarguil * 9342e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 9352e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 9362e22920bSAdrien Mazarguil * 9372e22920bSAdrien Mazarguil * @param dpdk_txq 9382e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 9392e22920bSAdrien Mazarguil * @param[in] pkts 9402e22920bSAdrien Mazarguil * Packets to transmit. 9412e22920bSAdrien Mazarguil * @param pkts_n 9422e22920bSAdrien Mazarguil * Number of packets in array. 9432e22920bSAdrien Mazarguil * 9442e22920bSAdrien Mazarguil * @return 9452e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 9462e22920bSAdrien Mazarguil */ 9472e22920bSAdrien Mazarguil uint16_t 9482e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 9492e22920bSAdrien Mazarguil { 9502e22920bSAdrien Mazarguil (void)dpdk_txq; 9512e22920bSAdrien Mazarguil (void)pkts; 9522e22920bSAdrien Mazarguil (void)pkts_n; 9532e22920bSAdrien Mazarguil return 0; 9542e22920bSAdrien Mazarguil } 9552e22920bSAdrien Mazarguil 9562e22920bSAdrien Mazarguil /** 9572e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 9582e22920bSAdrien Mazarguil * 9592e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 9602e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 9612e22920bSAdrien Mazarguil * 9622e22920bSAdrien Mazarguil * @param dpdk_rxq 9632e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 9642e22920bSAdrien Mazarguil * @param[out] pkts 9652e22920bSAdrien Mazarguil * Array to store received packets. 9662e22920bSAdrien Mazarguil * @param pkts_n 9672e22920bSAdrien Mazarguil * Maximum number of packets in array. 9682e22920bSAdrien Mazarguil * 9692e22920bSAdrien Mazarguil * @return 9702e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 9712e22920bSAdrien Mazarguil */ 9722e22920bSAdrien Mazarguil uint16_t 9732e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 9742e22920bSAdrien Mazarguil { 9752e22920bSAdrien Mazarguil (void)dpdk_rxq; 9762e22920bSAdrien Mazarguil (void)pkts; 9772e22920bSAdrien Mazarguil (void)pkts_n; 9782e22920bSAdrien Mazarguil return 0; 9792e22920bSAdrien Mazarguil } 980