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 42fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic" 432e22920bSAdrien Mazarguil #endif 442e22920bSAdrien Mazarguil #include <infiniband/verbs.h> 456218063bSNélio Laranjeiro #include <infiniband/mlx5_hw.h> 466218063bSNélio Laranjeiro #include <infiniband/arch.h> 472e22920bSAdrien Mazarguil #ifdef PEDANTIC 48fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 492e22920bSAdrien Mazarguil #endif 502e22920bSAdrien Mazarguil 512e22920bSAdrien Mazarguil /* DPDK headers don't like -pedantic. */ 522e22920bSAdrien Mazarguil #ifdef PEDANTIC 53fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic" 542e22920bSAdrien Mazarguil #endif 552e22920bSAdrien Mazarguil #include <rte_mbuf.h> 562e22920bSAdrien Mazarguil #include <rte_mempool.h> 572e22920bSAdrien Mazarguil #include <rte_prefetch.h> 582e22920bSAdrien Mazarguil #include <rte_common.h> 592e22920bSAdrien Mazarguil #include <rte_branch_prediction.h> 606218063bSNélio Laranjeiro #include <rte_ether.h> 612e22920bSAdrien Mazarguil #ifdef PEDANTIC 62fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 632e22920bSAdrien Mazarguil #endif 642e22920bSAdrien Mazarguil 652e22920bSAdrien Mazarguil #include "mlx5.h" 662e22920bSAdrien Mazarguil #include "mlx5_utils.h" 672e22920bSAdrien Mazarguil #include "mlx5_rxtx.h" 68f3db9489SYaacov Hazan #include "mlx5_autoconf.h" 692e22920bSAdrien Mazarguil #include "mlx5_defs.h" 706218063bSNélio Laranjeiro #include "mlx5_prm.h" 716218063bSNélio Laranjeiro 72ff1807a3SNélio Laranjeiro static inline int 73ff1807a3SNélio Laranjeiro check_cqe(volatile struct mlx5_cqe *cqe, 74ff1807a3SNélio Laranjeiro unsigned int cqes_n, const uint16_t ci) 75ff1807a3SNélio Laranjeiro __attribute__((always_inline)); 76ff1807a3SNélio Laranjeiro 7761b09ae4SNélio Laranjeiro static inline void 7861b09ae4SNélio Laranjeiro txq_complete(struct txq *txq) __attribute__((always_inline)); 7961b09ae4SNélio Laranjeiro 80ff1807a3SNélio Laranjeiro static inline uint32_t 81ff1807a3SNélio Laranjeiro txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 82ff1807a3SNélio Laranjeiro __attribute__((always_inline)); 83ff1807a3SNélio Laranjeiro 84ff1807a3SNélio Laranjeiro static inline void 8530807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe) 8630807f62SNélio Laranjeiro __attribute__((always_inline)); 87ff1807a3SNélio Laranjeiro 88ff1807a3SNélio Laranjeiro static inline uint32_t 89ff1807a3SNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 90ff1807a3SNélio Laranjeiro __attribute__((always_inline)); 91ff1807a3SNélio Laranjeiro 92ff1807a3SNélio Laranjeiro static inline int 93ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 94ff1807a3SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 95ff1807a3SNélio Laranjeiro __attribute__((always_inline)); 96ff1807a3SNélio Laranjeiro 97ff1807a3SNélio Laranjeiro static inline uint32_t 98ff1807a3SNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe) 99ff1807a3SNélio Laranjeiro __attribute__((always_inline)); 100ff1807a3SNélio Laranjeiro 10199c12dccSNélio Laranjeiro #ifndef NDEBUG 10299c12dccSNélio Laranjeiro 10399c12dccSNélio Laranjeiro /** 10499c12dccSNélio Laranjeiro * Verify or set magic value in CQE. 10599c12dccSNélio Laranjeiro * 10699c12dccSNélio Laranjeiro * @param cqe 10799c12dccSNélio Laranjeiro * Pointer to CQE. 10899c12dccSNélio Laranjeiro * 10999c12dccSNélio Laranjeiro * @return 11099c12dccSNélio Laranjeiro * 0 the first time. 11199c12dccSNélio Laranjeiro */ 11299c12dccSNélio Laranjeiro static inline int 11397267b8eSNelio Laranjeiro check_cqe_seen(volatile struct mlx5_cqe *cqe) 11499c12dccSNélio Laranjeiro { 11599c12dccSNélio Laranjeiro static const uint8_t magic[] = "seen"; 116ea3bc3b1SNélio Laranjeiro volatile uint8_t (*buf)[sizeof(cqe->rsvd0)] = &cqe->rsvd0; 11799c12dccSNélio Laranjeiro int ret = 1; 11899c12dccSNélio Laranjeiro unsigned int i; 11999c12dccSNélio Laranjeiro 12099c12dccSNélio Laranjeiro for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i) 12199c12dccSNélio Laranjeiro if (!ret || (*buf)[i] != magic[i]) { 12299c12dccSNélio Laranjeiro ret = 0; 12399c12dccSNélio Laranjeiro (*buf)[i] = magic[i]; 12499c12dccSNélio Laranjeiro } 12599c12dccSNélio Laranjeiro return ret; 12699c12dccSNélio Laranjeiro } 12799c12dccSNélio Laranjeiro 12899c12dccSNélio Laranjeiro #endif /* NDEBUG */ 1296218063bSNélio Laranjeiro 13099c12dccSNélio Laranjeiro /** 13199c12dccSNélio Laranjeiro * Check whether CQE is valid. 13299c12dccSNélio Laranjeiro * 13399c12dccSNélio Laranjeiro * @param cqe 13499c12dccSNélio Laranjeiro * Pointer to CQE. 13599c12dccSNélio Laranjeiro * @param cqes_n 13699c12dccSNélio Laranjeiro * Size of completion queue. 13799c12dccSNélio Laranjeiro * @param ci 13899c12dccSNélio Laranjeiro * Consumer index. 13999c12dccSNélio Laranjeiro * 14099c12dccSNélio Laranjeiro * @return 14199c12dccSNélio Laranjeiro * 0 on success, 1 on failure. 14299c12dccSNélio Laranjeiro */ 14399c12dccSNélio Laranjeiro static inline int 14497267b8eSNelio Laranjeiro check_cqe(volatile struct mlx5_cqe *cqe, 14599c12dccSNélio Laranjeiro unsigned int cqes_n, const uint16_t ci) 1466218063bSNélio Laranjeiro { 14799c12dccSNélio Laranjeiro uint16_t idx = ci & cqes_n; 14899c12dccSNélio Laranjeiro uint8_t op_own = cqe->op_own; 14999c12dccSNélio Laranjeiro uint8_t op_owner = MLX5_CQE_OWNER(op_own); 15099c12dccSNélio Laranjeiro uint8_t op_code = MLX5_CQE_OPCODE(op_own); 1516218063bSNélio Laranjeiro 15299c12dccSNélio Laranjeiro if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID))) 15399c12dccSNélio Laranjeiro return 1; /* No CQE. */ 15499c12dccSNélio Laranjeiro #ifndef NDEBUG 15599c12dccSNélio Laranjeiro if ((op_code == MLX5_CQE_RESP_ERR) || 15699c12dccSNélio Laranjeiro (op_code == MLX5_CQE_REQ_ERR)) { 15799c12dccSNélio Laranjeiro volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe; 15899c12dccSNélio Laranjeiro uint8_t syndrome = err_cqe->syndrome; 15999c12dccSNélio Laranjeiro 16099c12dccSNélio Laranjeiro if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) || 16199c12dccSNélio Laranjeiro (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR)) 16299c12dccSNélio Laranjeiro return 0; 16397267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 16499c12dccSNélio Laranjeiro ERROR("unexpected CQE error %u (0x%02x)" 16599c12dccSNélio Laranjeiro " syndrome 0x%02x", 16699c12dccSNélio Laranjeiro op_code, op_code, syndrome); 16799c12dccSNélio Laranjeiro return 1; 16899c12dccSNélio Laranjeiro } else if ((op_code != MLX5_CQE_RESP_SEND) && 16999c12dccSNélio Laranjeiro (op_code != MLX5_CQE_REQ)) { 17097267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 17199c12dccSNélio Laranjeiro ERROR("unexpected CQE opcode %u (0x%02x)", 17299c12dccSNélio Laranjeiro op_code, op_code); 17399c12dccSNélio Laranjeiro return 1; 1746218063bSNélio Laranjeiro } 17599c12dccSNélio Laranjeiro #endif /* NDEBUG */ 17699c12dccSNélio Laranjeiro return 0; 1776218063bSNélio Laranjeiro } 1782e22920bSAdrien Mazarguil 179fdcb0f53SNélio Laranjeiro /** 180fdcb0f53SNélio Laranjeiro * Return the address of the WQE. 181fdcb0f53SNélio Laranjeiro * 182fdcb0f53SNélio Laranjeiro * @param txq 183fdcb0f53SNélio Laranjeiro * Pointer to TX queue structure. 184fdcb0f53SNélio Laranjeiro * @param wqe_ci 185fdcb0f53SNélio Laranjeiro * WQE consumer index. 186fdcb0f53SNélio Laranjeiro * 187fdcb0f53SNélio Laranjeiro * @return 188fdcb0f53SNélio Laranjeiro * WQE address. 189fdcb0f53SNélio Laranjeiro */ 190fdcb0f53SNélio Laranjeiro static inline uintptr_t * 191fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(struct txq *txq, uint16_t ci) 192fdcb0f53SNélio Laranjeiro { 193fdcb0f53SNélio Laranjeiro ci &= ((1 << txq->wqe_n) - 1); 194fdcb0f53SNélio Laranjeiro return (uintptr_t *)((uintptr_t)txq->wqes + ci * MLX5_WQE_SIZE); 195fdcb0f53SNélio Laranjeiro } 196fdcb0f53SNélio Laranjeiro 1972e22920bSAdrien Mazarguil /** 1982e22920bSAdrien Mazarguil * Manage TX completions. 1992e22920bSAdrien Mazarguil * 2002e22920bSAdrien Mazarguil * When sending a burst, mlx5_tx_burst() posts several WRs. 2012e22920bSAdrien Mazarguil * 2022e22920bSAdrien Mazarguil * @param txq 2032e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2042e22920bSAdrien Mazarguil */ 205a6ca35aaSNélio Laranjeiro static inline void 2062e22920bSAdrien Mazarguil txq_complete(struct txq *txq) 2072e22920bSAdrien Mazarguil { 208b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 209e2f116eeSNélio Laranjeiro const unsigned int cqe_n = 1 << txq->cqe_n; 21099c12dccSNélio Laranjeiro const unsigned int cqe_cnt = cqe_n - 1; 2111d88ba17SNélio Laranjeiro uint16_t elts_free = txq->elts_tail; 2121d88ba17SNélio Laranjeiro uint16_t elts_tail; 2131d88ba17SNélio Laranjeiro uint16_t cq_ci = txq->cq_ci; 21497267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = NULL; 215fdcb0f53SNélio Laranjeiro volatile struct mlx5_wqe_ctrl *ctrl; 2162e22920bSAdrien Mazarguil 21799c12dccSNélio Laranjeiro do { 21897267b8eSNelio Laranjeiro volatile struct mlx5_cqe *tmp; 2191d88ba17SNélio Laranjeiro 22097267b8eSNelio Laranjeiro tmp = &(*txq->cqes)[cq_ci & cqe_cnt]; 22197267b8eSNelio Laranjeiro if (check_cqe(tmp, cqe_n, cq_ci)) 2221d88ba17SNélio Laranjeiro break; 223c305090bSAdrien Mazarguil cqe = tmp; 22499c12dccSNélio Laranjeiro #ifndef NDEBUG 22599c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) { 22697267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 22799c12dccSNélio Laranjeiro ERROR("unexpected compressed CQE, TX stopped"); 22899c12dccSNélio Laranjeiro return; 2292e22920bSAdrien Mazarguil } 23099c12dccSNélio Laranjeiro if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) || 23199c12dccSNélio Laranjeiro (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) { 23297267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 23399c12dccSNélio Laranjeiro ERROR("unexpected error CQE, TX stopped"); 23499c12dccSNélio Laranjeiro return; 23599c12dccSNélio Laranjeiro } 23699c12dccSNélio Laranjeiro #endif /* NDEBUG */ 23799c12dccSNélio Laranjeiro ++cq_ci; 23899c12dccSNélio Laranjeiro } while (1); 239c305090bSAdrien Mazarguil if (unlikely(cqe == NULL)) 2401d88ba17SNélio Laranjeiro return; 241fdcb0f53SNélio Laranjeiro ctrl = (volatile struct mlx5_wqe_ctrl *) 242fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, ntohs(cqe->wqe_counter)); 243fdcb0f53SNélio Laranjeiro elts_tail = ctrl->ctrl3; 244a821d09dSNélio Laranjeiro assert(elts_tail < (1 << txq->wqe_n)); 2451d88ba17SNélio Laranjeiro /* Free buffers. */ 246c305090bSAdrien Mazarguil while (elts_free != elts_tail) { 2471d88ba17SNélio Laranjeiro struct rte_mbuf *elt = (*txq->elts)[elts_free]; 248a859e8a9SNelio Laranjeiro unsigned int elts_free_next = 2491d88ba17SNélio Laranjeiro (elts_free + 1) & (elts_n - 1); 2501d88ba17SNélio Laranjeiro struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next]; 251a859e8a9SNelio Laranjeiro 252b185e63fSAdrien Mazarguil #ifndef NDEBUG 253b185e63fSAdrien Mazarguil /* Poisoning. */ 2541d88ba17SNélio Laranjeiro memset(&(*txq->elts)[elts_free], 2551d88ba17SNélio Laranjeiro 0x66, 2561d88ba17SNélio Laranjeiro sizeof((*txq->elts)[elts_free])); 257b185e63fSAdrien Mazarguil #endif 2581d88ba17SNélio Laranjeiro RTE_MBUF_PREFETCH_TO_FREE(elt_next); 2591d88ba17SNélio Laranjeiro /* Only one segment needs to be freed. */ 2601d88ba17SNélio Laranjeiro rte_pktmbuf_free_seg(elt); 261a859e8a9SNelio Laranjeiro elts_free = elts_free_next; 262c305090bSAdrien Mazarguil } 2631d88ba17SNélio Laranjeiro txq->cq_ci = cq_ci; 2642e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 2651d88ba17SNélio Laranjeiro /* Update the consumer index. */ 2661d88ba17SNélio Laranjeiro rte_wmb(); 2671d88ba17SNélio Laranjeiro *txq->cq_db = htonl(cq_ci); 2682e22920bSAdrien Mazarguil } 2692e22920bSAdrien Mazarguil 2702e22920bSAdrien Mazarguil /** 2718340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 2728340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 2738340392eSAdrien Mazarguil * 2748340392eSAdrien Mazarguil * @param buf 2758340392eSAdrien Mazarguil * Pointer to mbuf. 2768340392eSAdrien Mazarguil * 2778340392eSAdrien Mazarguil * @return 2788340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 2798340392eSAdrien Mazarguil */ 2808340392eSAdrien Mazarguil static struct rte_mempool * 2818340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 2828340392eSAdrien Mazarguil { 2838340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 2848340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 2858340392eSAdrien Mazarguil return buf->pool; 2868340392eSAdrien Mazarguil } 2878340392eSAdrien Mazarguil 2888340392eSAdrien Mazarguil /** 2892e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 2902e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 2912e22920bSAdrien Mazarguil * remove an entry first. 2922e22920bSAdrien Mazarguil * 2932e22920bSAdrien Mazarguil * @param txq 2942e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2952e22920bSAdrien Mazarguil * @param[in] mp 2962e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 2972e22920bSAdrien Mazarguil * 2982e22920bSAdrien Mazarguil * @return 2992e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 3002e22920bSAdrien Mazarguil */ 301491770faSNélio Laranjeiro static inline uint32_t 302d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 3032e22920bSAdrien Mazarguil { 3042e22920bSAdrien Mazarguil unsigned int i; 305491770faSNélio Laranjeiro uint32_t lkey = (uint32_t)-1; 3062e22920bSAdrien Mazarguil 3072e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 3082e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 3092e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 3102e22920bSAdrien Mazarguil break; 3112e22920bSAdrien Mazarguil } 3122e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 3132e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 3141d88ba17SNélio Laranjeiro assert(htonl(txq->mp2mr[i].mr->lkey) == 3151d88ba17SNélio Laranjeiro txq->mp2mr[i].lkey); 316491770faSNélio Laranjeiro lkey = txq->mp2mr[i].lkey; 317491770faSNélio Laranjeiro break; 3182e22920bSAdrien Mazarguil } 3192e22920bSAdrien Mazarguil } 320491770faSNélio Laranjeiro if (unlikely(lkey == (uint32_t)-1)) 321491770faSNélio Laranjeiro lkey = txq_mp2mr_reg(txq, mp, i); 322491770faSNélio Laranjeiro return lkey; 3230a3b350dSOlga Shern } 3240a3b350dSOlga Shern 325e192ef80SYaacov Hazan /** 3261d88ba17SNélio Laranjeiro * Ring TX queue doorbell. 3271d88ba17SNélio Laranjeiro * 3281d88ba17SNélio Laranjeiro * @param txq 3291d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 33030807f62SNélio Laranjeiro * @param wqe 33130807f62SNélio Laranjeiro * Pointer to the last WQE posted in the NIC. 3321d88ba17SNélio Laranjeiro */ 3331d88ba17SNélio Laranjeiro static inline void 33430807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe) 3351d88ba17SNélio Laranjeiro { 33630807f62SNélio Laranjeiro uint64_t *dst = (uint64_t *)((uintptr_t)txq->bf_reg); 33730807f62SNélio Laranjeiro volatile uint64_t *src = ((volatile uint64_t *)wqe); 33830807f62SNélio Laranjeiro 3391d88ba17SNélio Laranjeiro rte_wmb(); 3401d88ba17SNélio Laranjeiro *txq->qp_db = htonl(txq->wqe_ci); 3411d88ba17SNélio Laranjeiro /* Ensure ordering between DB record and BF copy. */ 3421d88ba17SNélio Laranjeiro rte_wmb(); 34330807f62SNélio Laranjeiro *dst = *src; 3441d88ba17SNélio Laranjeiro } 345e192ef80SYaacov Hazan 3461d88ba17SNélio Laranjeiro /** 3472e22920bSAdrien Mazarguil * DPDK callback for TX. 3482e22920bSAdrien Mazarguil * 3492e22920bSAdrien Mazarguil * @param dpdk_txq 3502e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 3512e22920bSAdrien Mazarguil * @param[in] pkts 3522e22920bSAdrien Mazarguil * Packets to transmit. 3532e22920bSAdrien Mazarguil * @param pkts_n 3542e22920bSAdrien Mazarguil * Number of packets in array. 3552e22920bSAdrien Mazarguil * 3562e22920bSAdrien Mazarguil * @return 3572e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 3582e22920bSAdrien Mazarguil */ 3592e22920bSAdrien Mazarguil uint16_t 3602e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 3612e22920bSAdrien Mazarguil { 3622e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 3631d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 364b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 365c3d62cc9SAdrien Mazarguil unsigned int i = 0; 366a5bf6af9SAdrien Mazarguil unsigned int j = 0; 3672e22920bSAdrien Mazarguil unsigned int max; 368c305090bSAdrien Mazarguil unsigned int comp; 3699a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 3706579c27cSNélio Laranjeiro unsigned int segs_n = 0; 3716579c27cSNélio Laranjeiro struct rte_mbuf *buf = NULL; 3726579c27cSNélio Laranjeiro uint8_t *raw; 3732e22920bSAdrien Mazarguil 3741d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 3751d88ba17SNélio Laranjeiro return 0; 3765e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 377c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 3781d88ba17SNélio Laranjeiro /* Start processing. */ 3792e22920bSAdrien Mazarguil txq_complete(txq); 3804f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 3812e22920bSAdrien Mazarguil if (max > elts_n) 3822e22920bSAdrien Mazarguil max -= elts_n; 383c3d62cc9SAdrien Mazarguil do { 3849a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 385573f54afSNélio Laranjeiro uint32_t length; 3868688b2f8SNélio Laranjeiro unsigned int ds = 0; 3876579c27cSNélio Laranjeiro uintptr_t addr; 3889a7fa9f7SNélio Laranjeiro uint64_t naddr; 389b8fe952eSNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE; 390eef822ddSNélio Laranjeiro uint16_t ehdr; 3919a7fa9f7SNélio Laranjeiro uint8_t cs_flags = 0; 3926579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 3936579c27cSNélio Laranjeiro uint32_t total_length = 0; 3946579c27cSNélio Laranjeiro #endif 3952e22920bSAdrien Mazarguil 3966579c27cSNélio Laranjeiro /* first_seg */ 3976579c27cSNélio Laranjeiro buf = *(pkts++); 3986579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 399c3d62cc9SAdrien Mazarguil /* 400c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 401c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 402c3d62cc9SAdrien Mazarguil */ 403a5bf6af9SAdrien Mazarguil assert(segs_n); 404a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 405c3d62cc9SAdrien Mazarguil break; 406a5bf6af9SAdrien Mazarguil max -= segs_n; 4076579c27cSNélio Laranjeiro --segs_n; 4086579c27cSNélio Laranjeiro if (!segs_n) 409c3d62cc9SAdrien Mazarguil --pkts_n; 4109a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 411fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 412fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 4136579c27cSNélio Laranjeiro if (pkts_n > 1) 414c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 4156579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 4162e22920bSAdrien Mazarguil length = DATA_LEN(buf); 417eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 418eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 4196579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 4206579c27cSNélio Laranjeiro total_length = length; 4216579c27cSNélio Laranjeiro #endif 4226579c27cSNélio Laranjeiro assert(length >= MLX5_WQE_DWORD_SIZE); 4232e22920bSAdrien Mazarguil /* Update element. */ 4241d88ba17SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 4256579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 4265e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 4276579c27cSNélio Laranjeiro if (pkts_n > 1) { 4286579c27cSNélio Laranjeiro volatile void *pkt_addr; 4296579c27cSNélio Laranjeiro 4306579c27cSNélio Laranjeiro pkt_addr = rte_pktmbuf_mtod(*pkts, volatile void *); 4316579c27cSNélio Laranjeiro rte_prefetch0(pkt_addr); 4326579c27cSNélio Laranjeiro } 4331d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 4341d88ba17SNélio Laranjeiro if (buf->ol_flags & 4351d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 4369a7fa9f7SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 4371d88ba17SNélio Laranjeiro } 438b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 439b8fe952eSNélio Laranjeiro /* 440b8fe952eSNélio Laranjeiro * Start by copying the Ethernet header minus the first two 441b8fe952eSNélio Laranjeiro * bytes which will be appended at the end of the Ethernet 442b8fe952eSNélio Laranjeiro * segment. 443b8fe952eSNélio Laranjeiro */ 444b8fe952eSNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 16); 4456579c27cSNélio Laranjeiro length -= MLX5_WQE_DWORD_SIZE; 4466579c27cSNélio Laranjeiro addr += MLX5_WQE_DWORD_SIZE; 4476579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 4486579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 4496579c27cSNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | buf->vlan_tci); 4506579c27cSNélio Laranjeiro 451b8fe952eSNélio Laranjeiro memcpy((uint8_t *)(raw + MLX5_WQE_DWORD_SIZE - 2 - 4526579c27cSNélio Laranjeiro sizeof(vlan)), 4536579c27cSNélio Laranjeiro &vlan, sizeof(vlan)); 4546579c27cSNélio Laranjeiro addr -= sizeof(vlan); 4556579c27cSNélio Laranjeiro length += sizeof(vlan); 4566579c27cSNélio Laranjeiro } 4576579c27cSNélio Laranjeiro /* Inline if enough room. */ 4586579c27cSNélio Laranjeiro if (txq->max_inline != 0) { 459fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 460fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 461fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 4626579c27cSNélio Laranjeiro uint16_t max_inline = 4636579c27cSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 4646579c27cSNélio Laranjeiro uint16_t room; 4656579c27cSNélio Laranjeiro 466b8fe952eSNélio Laranjeiro /* 467b8fe952eSNélio Laranjeiro * raw starts two bytes before the boundary to 468b8fe952eSNélio Laranjeiro * continue the above copy of packet data. 469b8fe952eSNélio Laranjeiro */ 470b8fe952eSNélio Laranjeiro raw += MLX5_WQE_DWORD_SIZE - 2; 4716579c27cSNélio Laranjeiro room = end - (uintptr_t)raw; 4726579c27cSNélio Laranjeiro if (room > max_inline) { 4736579c27cSNélio Laranjeiro uintptr_t addr_end = (addr + max_inline) & 4746579c27cSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 4756579c27cSNélio Laranjeiro uint16_t copy_b = ((addr_end - addr) > length) ? 4766579c27cSNélio Laranjeiro length : 4776579c27cSNélio Laranjeiro (addr_end - addr); 4786579c27cSNélio Laranjeiro 4796579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 4806579c27cSNélio Laranjeiro addr += copy_b; 4816579c27cSNélio Laranjeiro length -= copy_b; 4826579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 4836579c27cSNélio Laranjeiro /* Sanity check. */ 4846579c27cSNélio Laranjeiro assert(addr <= addr_end); 4856579c27cSNélio Laranjeiro } 4866579c27cSNélio Laranjeiro /* 487786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 4886579c27cSNélio Laranjeiro * the size of the inline part of the packet. 4896579c27cSNélio Laranjeiro */ 4906579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 4916579c27cSNélio Laranjeiro if (length > 0) { 4929a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 4936579c27cSNélio Laranjeiro ((uintptr_t)wqe + 4946579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 4956579c27cSNélio Laranjeiro if ((uintptr_t)dseg >= end) 4969a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 497fdcb0f53SNélio Laranjeiro txq->wqes; 4986579c27cSNélio Laranjeiro goto use_dseg; 4996579c27cSNélio Laranjeiro } else if (!segs_n) { 5006579c27cSNélio Laranjeiro goto next_pkt; 5016579c27cSNélio Laranjeiro } else { 502786b5c2dSShahaf Shuler /* dseg will be advance as part of next_seg */ 503786b5c2dSShahaf Shuler dseg = (volatile rte_v128u32_t *) 504786b5c2dSShahaf Shuler ((uintptr_t)wqe + 505786b5c2dSShahaf Shuler ((ds - 1) * MLX5_WQE_DWORD_SIZE)); 5066579c27cSNélio Laranjeiro goto next_seg; 5076579c27cSNélio Laranjeiro } 5086579c27cSNélio Laranjeiro } else { 5096579c27cSNélio Laranjeiro /* 5106579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 5116579c27cSNélio Laranjeiro * Ethernet Header as been stored. 5126579c27cSNélio Laranjeiro */ 5139a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 5146579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 5156579c27cSNélio Laranjeiro ds = 3; 5166579c27cSNélio Laranjeiro use_dseg: 5176579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 5189a7fa9f7SNélio Laranjeiro naddr = htonll(addr); 5199a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 5209a7fa9f7SNélio Laranjeiro htonl(length), 5219a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 5229a7fa9f7SNélio Laranjeiro naddr, 5239a7fa9f7SNélio Laranjeiro naddr >> 32, 5246579c27cSNélio Laranjeiro }; 5256579c27cSNélio Laranjeiro ++ds; 5266579c27cSNélio Laranjeiro if (!segs_n) 5276579c27cSNélio Laranjeiro goto next_pkt; 5286579c27cSNélio Laranjeiro } 5296579c27cSNélio Laranjeiro next_seg: 5306579c27cSNélio Laranjeiro assert(buf); 5316579c27cSNélio Laranjeiro assert(ds); 5326579c27cSNélio Laranjeiro assert(wqe); 533a5bf6af9SAdrien Mazarguil /* 534a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 535a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 536a5bf6af9SAdrien Mazarguil * of data segment size. 537a5bf6af9SAdrien Mazarguil */ 5388688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 5396579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 5406579c27cSNélio Laranjeiro unsigned int n = (txq->wqe_ci + ((ds + 3) / 4)) & 5416579c27cSNélio Laranjeiro ((1 << txq->wqe_n) - 1); 5426579c27cSNélio Laranjeiro 5439a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 544fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, n); 545fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, n + 1)); 5466579c27cSNélio Laranjeiro } else { 547a5bf6af9SAdrien Mazarguil ++dseg; 5486579c27cSNélio Laranjeiro } 549a5bf6af9SAdrien Mazarguil ++ds; 550a5bf6af9SAdrien Mazarguil buf = buf->next; 551a5bf6af9SAdrien Mazarguil assert(buf); 5526579c27cSNélio Laranjeiro length = DATA_LEN(buf); 553a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 5546579c27cSNélio Laranjeiro total_length += length; 555a5bf6af9SAdrien Mazarguil #endif 5566579c27cSNélio Laranjeiro /* Store segment information. */ 5579a7fa9f7SNélio Laranjeiro naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)); 5589a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 5599a7fa9f7SNélio Laranjeiro htonl(length), 5609a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 5619a7fa9f7SNélio Laranjeiro naddr, 5629a7fa9f7SNélio Laranjeiro naddr >> 32, 5636579c27cSNélio Laranjeiro }; 5646579c27cSNélio Laranjeiro (*txq->elts)[elts_head] = buf; 5656579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 566a5bf6af9SAdrien Mazarguil ++j; 5676579c27cSNélio Laranjeiro --segs_n; 5686579c27cSNélio Laranjeiro if (segs_n) 5696579c27cSNélio Laranjeiro goto next_seg; 5706579c27cSNélio Laranjeiro else 5716579c27cSNélio Laranjeiro --pkts_n; 5726579c27cSNélio Laranjeiro next_pkt: 5736579c27cSNélio Laranjeiro ++i; 574b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 5759a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 5769a7fa9f7SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 5779a7fa9f7SNélio Laranjeiro htonl(txq->qp_num_8s | ds), 5789a7fa9f7SNélio Laranjeiro 0, 5799a7fa9f7SNélio Laranjeiro 0, 5809a7fa9f7SNélio Laranjeiro }; 5819a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 5829a7fa9f7SNélio Laranjeiro 0, 5839a7fa9f7SNélio Laranjeiro cs_flags, 5849a7fa9f7SNélio Laranjeiro 0, 585eef822ddSNélio Laranjeiro (ehdr << 16) | htons(pkt_inline_sz), 5869a7fa9f7SNélio Laranjeiro }; 5876579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 58887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 589573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 5906579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 59187011737SAdrien Mazarguil #endif 592c3d62cc9SAdrien Mazarguil } while (pkts_n); 5932e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 5942e22920bSAdrien Mazarguil if (unlikely(i == 0)) 5952e22920bSAdrien Mazarguil return 0; 596c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 597a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + i + j; 598c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 5999a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_ctrl *w = 6009a7fa9f7SNélio Laranjeiro (volatile struct mlx5_wqe_ctrl *)wqe; 6019a7fa9f7SNélio Laranjeiro 602c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 6039a7fa9f7SNélio Laranjeiro w->ctrl2 = htonl(8); 604c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 6059a7fa9f7SNélio Laranjeiro w->ctrl3 = elts_head; 606c305090bSAdrien Mazarguil txq->elts_comp = 0; 607c305090bSAdrien Mazarguil } else { 608c305090bSAdrien Mazarguil txq->elts_comp = comp; 609c305090bSAdrien Mazarguil } 61087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 61187011737SAdrien Mazarguil /* Increment sent packets counter. */ 61287011737SAdrien Mazarguil txq->stats.opackets += i; 61387011737SAdrien Mazarguil #endif 6142e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 61530807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)wqe); 6162e22920bSAdrien Mazarguil txq->elts_head = elts_head; 6172e22920bSAdrien Mazarguil return i; 6182e22920bSAdrien Mazarguil } 6192e22920bSAdrien Mazarguil 6202e22920bSAdrien Mazarguil /** 621230189d9SNélio Laranjeiro * Open a MPW session. 622230189d9SNélio Laranjeiro * 623230189d9SNélio Laranjeiro * @param txq 624230189d9SNélio Laranjeiro * Pointer to TX queue structure. 625230189d9SNélio Laranjeiro * @param mpw 626230189d9SNélio Laranjeiro * Pointer to MPW session structure. 627230189d9SNélio Laranjeiro * @param length 628230189d9SNélio Laranjeiro * Packet length. 629230189d9SNélio Laranjeiro */ 630230189d9SNélio Laranjeiro static inline void 631230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 632230189d9SNélio Laranjeiro { 633a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 634230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 635230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 636fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 637230189d9SNélio Laranjeiro 638230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 639230189d9SNélio Laranjeiro mpw->pkts_n = 0; 640230189d9SNélio Laranjeiro mpw->len = length; 641230189d9SNélio Laranjeiro mpw->total_len = 0; 642fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 6438688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 6448688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 6458688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 6468688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 6478688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 6488688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 649c904ae25SNélio Laranjeiro (txq->wqe_ci << 8) | MLX5_OPCODE_TSO); 6508688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 6518688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 6528688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 6538688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 6548688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 6558688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 656230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 657230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 658230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 659230189d9SNélio Laranjeiro } 660230189d9SNélio Laranjeiro 661230189d9SNélio Laranjeiro /** 662230189d9SNélio Laranjeiro * Close a MPW session. 663230189d9SNélio Laranjeiro * 664230189d9SNélio Laranjeiro * @param txq 665230189d9SNélio Laranjeiro * Pointer to TX queue structure. 666230189d9SNélio Laranjeiro * @param mpw 667230189d9SNélio Laranjeiro * Pointer to MPW session structure. 668230189d9SNélio Laranjeiro */ 669230189d9SNélio Laranjeiro static inline void 670230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 671230189d9SNélio Laranjeiro { 672230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 673230189d9SNélio Laranjeiro 674230189d9SNélio Laranjeiro /* 675230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 676230189d9SNélio Laranjeiro * count as 2. 677230189d9SNélio Laranjeiro */ 6788688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num)); 679230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 680230189d9SNélio Laranjeiro if (num < 3) 681230189d9SNélio Laranjeiro ++txq->wqe_ci; 682230189d9SNélio Laranjeiro else 683230189d9SNélio Laranjeiro txq->wqe_ci += 2; 684fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 685fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 686230189d9SNélio Laranjeiro } 687230189d9SNélio Laranjeiro 688230189d9SNélio Laranjeiro /** 689230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 690230189d9SNélio Laranjeiro * 691230189d9SNélio Laranjeiro * @param dpdk_txq 692230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 693230189d9SNélio Laranjeiro * @param[in] pkts 694230189d9SNélio Laranjeiro * Packets to transmit. 695230189d9SNélio Laranjeiro * @param pkts_n 696230189d9SNélio Laranjeiro * Number of packets in array. 697230189d9SNélio Laranjeiro * 698230189d9SNélio Laranjeiro * @return 699230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 700230189d9SNélio Laranjeiro */ 701230189d9SNélio Laranjeiro uint16_t 702230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 703230189d9SNélio Laranjeiro { 704230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 705230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 706b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 707c3d62cc9SAdrien Mazarguil unsigned int i = 0; 708a5bf6af9SAdrien Mazarguil unsigned int j = 0; 709230189d9SNélio Laranjeiro unsigned int max; 710230189d9SNélio Laranjeiro unsigned int comp; 711230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 712230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 713230189d9SNélio Laranjeiro }; 714230189d9SNélio Laranjeiro 715c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 716c3d62cc9SAdrien Mazarguil return 0; 717230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 718fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 719fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 720230189d9SNélio Laranjeiro /* Start processing. */ 721230189d9SNélio Laranjeiro txq_complete(txq); 722230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 723230189d9SNélio Laranjeiro if (max > elts_n) 724230189d9SNélio Laranjeiro max -= elts_n; 725c3d62cc9SAdrien Mazarguil do { 726a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 727c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 728230189d9SNélio Laranjeiro uint32_t length; 729a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 730230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 731230189d9SNélio Laranjeiro 732c3d62cc9SAdrien Mazarguil /* 733c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 734c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 735c3d62cc9SAdrien Mazarguil */ 736a5bf6af9SAdrien Mazarguil assert(segs_n); 737a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 738c3d62cc9SAdrien Mazarguil break; 739a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 740a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 741a5bf6af9SAdrien Mazarguil break; 742a5bf6af9SAdrien Mazarguil max -= segs_n; 743c3d62cc9SAdrien Mazarguil --pkts_n; 744230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 745230189d9SNélio Laranjeiro if (buf->ol_flags & 746230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 747230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 748a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 749a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 750a5bf6af9SAdrien Mazarguil assert(length); 751230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 752230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 753230189d9SNélio Laranjeiro ((mpw.len != length) || 754a5bf6af9SAdrien Mazarguil (segs_n != 1) || 7558688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 756230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 757230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 758230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 7598688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 760230189d9SNélio Laranjeiro } 761a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 762a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 763a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 764a5bf6af9SAdrien Mazarguil length = 0; 765a5bf6af9SAdrien Mazarguil #endif 766a5bf6af9SAdrien Mazarguil do { 767a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 768a5bf6af9SAdrien Mazarguil uintptr_t addr; 769a5bf6af9SAdrien Mazarguil 770a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 771a5bf6af9SAdrien Mazarguil assert(buf); 772a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 773230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 774a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 775230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 776a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 777230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 778230189d9SNélio Laranjeiro .addr = htonll(addr), 779230189d9SNélio Laranjeiro }; 780a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 781a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 782a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 783a5bf6af9SAdrien Mazarguil #endif 784a5bf6af9SAdrien Mazarguil buf = buf->next; 785230189d9SNélio Laranjeiro ++mpw.pkts_n; 786a5bf6af9SAdrien Mazarguil ++j; 787a5bf6af9SAdrien Mazarguil } while (--segs_n); 788a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 789230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 790230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 791230189d9SNélio Laranjeiro elts_head = elts_head_next; 792230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 793230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 794230189d9SNélio Laranjeiro txq->stats.obytes += length; 795230189d9SNélio Laranjeiro #endif 796c3d62cc9SAdrien Mazarguil ++i; 797c3d62cc9SAdrien Mazarguil } while (pkts_n); 798230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 799230189d9SNélio Laranjeiro if (unlikely(i == 0)) 800230189d9SNélio Laranjeiro return 0; 801230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 802a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 803a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 804230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 8058688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 806230189d9SNélio Laranjeiro 807230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 8088688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 809230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 8108688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 811230189d9SNélio Laranjeiro txq->elts_comp = 0; 812230189d9SNélio Laranjeiro } else { 813230189d9SNélio Laranjeiro txq->elts_comp = comp; 814230189d9SNélio Laranjeiro } 815230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 816230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 817230189d9SNélio Laranjeiro txq->stats.opackets += i; 818230189d9SNélio Laranjeiro #endif 819230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 820230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 821230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 82230807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 823230189d9SNélio Laranjeiro txq->elts_head = elts_head; 824230189d9SNélio Laranjeiro return i; 825230189d9SNélio Laranjeiro } 826230189d9SNélio Laranjeiro 827230189d9SNélio Laranjeiro /** 828230189d9SNélio Laranjeiro * Open a MPW inline session. 829230189d9SNélio Laranjeiro * 830230189d9SNélio Laranjeiro * @param txq 831230189d9SNélio Laranjeiro * Pointer to TX queue structure. 832230189d9SNélio Laranjeiro * @param mpw 833230189d9SNélio Laranjeiro * Pointer to MPW session structure. 834230189d9SNélio Laranjeiro * @param length 835230189d9SNélio Laranjeiro * Packet length. 836230189d9SNélio Laranjeiro */ 837230189d9SNélio Laranjeiro static inline void 838230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 839230189d9SNélio Laranjeiro { 840a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 8418688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 842230189d9SNélio Laranjeiro 843230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 844230189d9SNélio Laranjeiro mpw->pkts_n = 0; 845230189d9SNélio Laranjeiro mpw->len = length; 846230189d9SNélio Laranjeiro mpw->total_len = 0; 847fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 8488688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 849230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 850c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 8518688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 8528688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 8538688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 8548688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 8558688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 8568688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 8578688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 8588688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 8598688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 8608688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 8618688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 862230189d9SNélio Laranjeiro } 863230189d9SNélio Laranjeiro 864230189d9SNélio Laranjeiro /** 865230189d9SNélio Laranjeiro * Close a MPW inline session. 866230189d9SNélio Laranjeiro * 867230189d9SNélio Laranjeiro * @param txq 868230189d9SNélio Laranjeiro * Pointer to TX queue structure. 869230189d9SNélio Laranjeiro * @param mpw 870230189d9SNélio Laranjeiro * Pointer to MPW session structure. 871230189d9SNélio Laranjeiro */ 872230189d9SNélio Laranjeiro static inline void 873230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 874230189d9SNélio Laranjeiro { 875230189d9SNélio Laranjeiro unsigned int size; 8768688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 8778688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 878230189d9SNélio Laranjeiro 8798688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 880230189d9SNélio Laranjeiro /* 881230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 882230189d9SNélio Laranjeiro * count as 2. 883230189d9SNélio Laranjeiro */ 8848688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size)); 885230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 8868688b2f8SNélio Laranjeiro inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 8878688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 888230189d9SNélio Laranjeiro } 889230189d9SNélio Laranjeiro 890230189d9SNélio Laranjeiro /** 891230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 892230189d9SNélio Laranjeiro * 893230189d9SNélio Laranjeiro * @param dpdk_txq 894230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 895230189d9SNélio Laranjeiro * @param[in] pkts 896230189d9SNélio Laranjeiro * Packets to transmit. 897230189d9SNélio Laranjeiro * @param pkts_n 898230189d9SNélio Laranjeiro * Number of packets in array. 899230189d9SNélio Laranjeiro * 900230189d9SNélio Laranjeiro * @return 901230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 902230189d9SNélio Laranjeiro */ 903230189d9SNélio Laranjeiro uint16_t 904230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 905230189d9SNélio Laranjeiro uint16_t pkts_n) 906230189d9SNélio Laranjeiro { 907230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 908230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 909b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 910c3d62cc9SAdrien Mazarguil unsigned int i = 0; 911a5bf6af9SAdrien Mazarguil unsigned int j = 0; 912230189d9SNélio Laranjeiro unsigned int max; 913230189d9SNélio Laranjeiro unsigned int comp; 9140e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 915230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 916230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 917230189d9SNélio Laranjeiro }; 918230189d9SNélio Laranjeiro 919c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 920c3d62cc9SAdrien Mazarguil return 0; 921230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 922fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 923fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 924230189d9SNélio Laranjeiro /* Start processing. */ 925230189d9SNélio Laranjeiro txq_complete(txq); 926230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 927230189d9SNélio Laranjeiro if (max > elts_n) 928230189d9SNélio Laranjeiro max -= elts_n; 929c3d62cc9SAdrien Mazarguil do { 930a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 931c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 932230189d9SNélio Laranjeiro uintptr_t addr; 933230189d9SNélio Laranjeiro uint32_t length; 934a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 935230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 936230189d9SNélio Laranjeiro 937c3d62cc9SAdrien Mazarguil /* 938c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 939c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 940c3d62cc9SAdrien Mazarguil */ 941a5bf6af9SAdrien Mazarguil assert(segs_n); 942a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 943c3d62cc9SAdrien Mazarguil break; 944a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 945a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 946a5bf6af9SAdrien Mazarguil break; 947a5bf6af9SAdrien Mazarguil max -= segs_n; 948c3d62cc9SAdrien Mazarguil --pkts_n; 949230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 950230189d9SNélio Laranjeiro if (buf->ol_flags & 951230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 952230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 953a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 954a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 955230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 956230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 957230189d9SNélio Laranjeiro if ((mpw.len != length) || 958a5bf6af9SAdrien Mazarguil (segs_n != 1) || 9598688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 960230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 961230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 962230189d9SNélio Laranjeiro if ((mpw.len != length) || 963a5bf6af9SAdrien Mazarguil (segs_n != 1) || 964230189d9SNélio Laranjeiro (length > inline_room) || 9658688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 966230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 9670e8679fcSNélio Laranjeiro inline_room = 9680e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 969230189d9SNélio Laranjeiro } 970230189d9SNélio Laranjeiro } 971230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 972a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 973a5bf6af9SAdrien Mazarguil (length > inline_room)) { 974230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 9758688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 976230189d9SNélio Laranjeiro } else { 977230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 9788688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 979230189d9SNélio Laranjeiro } 980230189d9SNélio Laranjeiro } 981a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 982a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 983230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 9840e8679fcSNélio Laranjeiro assert(inline_room == 9850e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 986a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 987a5bf6af9SAdrien Mazarguil length = 0; 988a5bf6af9SAdrien Mazarguil #endif 989a5bf6af9SAdrien Mazarguil do { 990230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 991230189d9SNélio Laranjeiro 992a5bf6af9SAdrien Mazarguil elts_head_next = 993a5bf6af9SAdrien Mazarguil (elts_head + 1) & (elts_n - 1); 994a5bf6af9SAdrien Mazarguil assert(buf); 995a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 996230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 997a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 998230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 999a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 1000230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 1001230189d9SNélio Laranjeiro .addr = htonll(addr), 1002230189d9SNélio Laranjeiro }; 1003a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 1004a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1005a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1006a5bf6af9SAdrien Mazarguil #endif 1007a5bf6af9SAdrien Mazarguil buf = buf->next; 1008230189d9SNélio Laranjeiro ++mpw.pkts_n; 1009a5bf6af9SAdrien Mazarguil ++j; 1010a5bf6af9SAdrien Mazarguil } while (--segs_n); 1011a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1012230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1013230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1014230189d9SNélio Laranjeiro } else { 1015230189d9SNélio Laranjeiro unsigned int max; 1016230189d9SNélio Laranjeiro 1017230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1018230189d9SNélio Laranjeiro assert(length <= inline_room); 1019a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1020a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1021a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1022a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1023230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1024fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1025fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1026fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1027230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1028230189d9SNélio Laranjeiro if (length > max) { 1029230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1030230189d9SNélio Laranjeiro (void *)addr, 1031230189d9SNélio Laranjeiro max); 1032fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1033230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1034230189d9SNélio Laranjeiro (void *)(addr + max), 1035230189d9SNélio Laranjeiro length - max); 1036230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1037230189d9SNélio Laranjeiro } else { 1038230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1039230189d9SNélio Laranjeiro (void *)addr, 1040230189d9SNélio Laranjeiro length); 1041230189d9SNélio Laranjeiro mpw.data.raw += length; 1042230189d9SNélio Laranjeiro } 1043230189d9SNélio Laranjeiro if ((uintptr_t)mpw.data.raw == 1044fdcb0f53SNélio Laranjeiro (uintptr_t)tx_mlx5_wqe(txq, 1 << txq->wqe_n)) 1045fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1046230189d9SNélio Laranjeiro ++mpw.pkts_n; 1047a5bf6af9SAdrien Mazarguil ++j; 1048230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1049230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 10500e8679fcSNélio Laranjeiro inline_room = 10510e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1052230189d9SNélio Laranjeiro } else { 1053230189d9SNélio Laranjeiro inline_room -= length; 1054230189d9SNélio Laranjeiro } 1055230189d9SNélio Laranjeiro } 1056230189d9SNélio Laranjeiro mpw.total_len += length; 1057230189d9SNélio Laranjeiro elts_head = elts_head_next; 1058230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1059230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1060230189d9SNélio Laranjeiro txq->stats.obytes += length; 1061230189d9SNélio Laranjeiro #endif 1062c3d62cc9SAdrien Mazarguil ++i; 1063c3d62cc9SAdrien Mazarguil } while (pkts_n); 1064230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1065230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1066230189d9SNélio Laranjeiro return 0; 1067230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1068a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1069a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1070230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 10718688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1072230189d9SNélio Laranjeiro 1073230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 10748688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1075230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 10768688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1077230189d9SNélio Laranjeiro txq->elts_comp = 0; 1078230189d9SNélio Laranjeiro } else { 1079230189d9SNélio Laranjeiro txq->elts_comp = comp; 1080230189d9SNélio Laranjeiro } 1081230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1082230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1083230189d9SNélio Laranjeiro txq->stats.opackets += i; 1084230189d9SNélio Laranjeiro #endif 1085230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1086230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1087230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1088230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1089230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 109030807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1091230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1092230189d9SNélio Laranjeiro return i; 1093230189d9SNélio Laranjeiro } 1094230189d9SNélio Laranjeiro 1095230189d9SNélio Laranjeiro /** 109667fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 109767fa62bcSAdrien Mazarguil * 10986218063bSNélio Laranjeiro * @param[in] cqe 10996218063bSNélio Laranjeiro * Pointer to CQE. 110067fa62bcSAdrien Mazarguil * 110178a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 110278a38edfSJianfeng Tan * 110367fa62bcSAdrien Mazarguil * @return 110467fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 110567fa62bcSAdrien Mazarguil */ 110667fa62bcSAdrien Mazarguil static inline uint32_t 110797267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 110867fa62bcSAdrien Mazarguil { 110967fa62bcSAdrien Mazarguil uint32_t pkt_type; 11106218063bSNélio Laranjeiro uint8_t flags = cqe->l4_hdr_type_etc; 111167fa62bcSAdrien Mazarguil 111297267b8eSNelio Laranjeiro if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) 111367fa62bcSAdrien Mazarguil pkt_type = 111467fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1115350f4c48SNelio Laranjeiro MLX5_CQE_RX_OUTER_IPV4_PACKET, 1116501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV4_EXT_UNKNOWN) | 111767fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1118350f4c48SNelio Laranjeiro MLX5_CQE_RX_OUTER_IPV6_PACKET, 1119501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) | 112067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1121350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV4_PACKET, 1122501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) | 112367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1124350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV6_PACKET, 1125501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN); 112667fa62bcSAdrien Mazarguil else 112767fa62bcSAdrien Mazarguil pkt_type = 112867fa62bcSAdrien Mazarguil TRANSPOSE(flags, 11296218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 1130501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) | 113167fa62bcSAdrien Mazarguil TRANSPOSE(flags, 11326218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 1133501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 113467fa62bcSAdrien Mazarguil return pkt_type; 113567fa62bcSAdrien Mazarguil } 113667fa62bcSAdrien Mazarguil 113767fa62bcSAdrien Mazarguil /** 113899c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 113999c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 114099c12dccSNélio Laranjeiro * been processed. 114199c12dccSNélio Laranjeiro * 114299c12dccSNélio Laranjeiro * @param rxq 114399c12dccSNélio Laranjeiro * Pointer to RX queue. 114499c12dccSNélio Laranjeiro * @param cqe 114599c12dccSNélio Laranjeiro * CQE to process. 1146ecf60761SNélio Laranjeiro * @param[out] rss_hash 1147ecf60761SNélio Laranjeiro * Packet RSS Hash result. 114899c12dccSNélio Laranjeiro * 114999c12dccSNélio Laranjeiro * @return 115099c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 115199c12dccSNélio Laranjeiro * with error. 115299c12dccSNélio Laranjeiro */ 115399c12dccSNélio Laranjeiro static inline int 115497267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 1155ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 115699c12dccSNélio Laranjeiro { 115799c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 115899c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 115999c12dccSNélio Laranjeiro int len = 0; 1160*d2e842d0SYongseok Koh uint16_t idx, end; 116199c12dccSNélio Laranjeiro 116299c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 116399c12dccSNélio Laranjeiro if (zip->ai) { 116499c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 116599c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 116697267b8eSNelio Laranjeiro (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt]); 116799c12dccSNélio Laranjeiro 116899c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 1169ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result); 117099c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1171*d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1172*d2e842d0SYongseok Koh idx = zip->ca; 1173*d2e842d0SYongseok Koh end = zip->na; 1174*d2e842d0SYongseok Koh while (idx != end) { 1175*d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1176*d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1177*d2e842d0SYongseok Koh ++idx; 1178*d2e842d0SYongseok Koh } 117999c12dccSNélio Laranjeiro /* 118099c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 118199c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 118299c12dccSNélio Laranjeiro * ring for software use. 118399c12dccSNélio Laranjeiro */ 118499c12dccSNélio Laranjeiro zip->ca = zip->na; 118599c12dccSNélio Laranjeiro zip->na += 8; 118699c12dccSNélio Laranjeiro } 118799c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1188*d2e842d0SYongseok Koh /* Invalidate the rest */ 1189*d2e842d0SYongseok Koh idx = zip->ca; 1190*d2e842d0SYongseok Koh end = zip->cq_ci; 119199c12dccSNélio Laranjeiro 119299c12dccSNélio Laranjeiro while (idx != end) { 119397267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 119499c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 119599c12dccSNélio Laranjeiro ++idx; 119699c12dccSNélio Laranjeiro } 119799c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 119899c12dccSNélio Laranjeiro zip->ai = 0; 119999c12dccSNélio Laranjeiro } 120099c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 120199c12dccSNélio Laranjeiro } else { 120299c12dccSNélio Laranjeiro int ret; 120399c12dccSNélio Laranjeiro int8_t op_own; 120499c12dccSNélio Laranjeiro 120597267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 120699c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 120799c12dccSNélio Laranjeiro return 0; 120899c12dccSNélio Laranjeiro ++rxq->cq_ci; 120999c12dccSNélio Laranjeiro op_own = cqe->op_own; 121099c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 121199c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 121299c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 121399c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 121497267b8eSNelio Laranjeiro cqe_cnt]); 121599c12dccSNélio Laranjeiro 121699c12dccSNélio Laranjeiro /* Fix endianness. */ 121799c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 121899c12dccSNélio Laranjeiro /* 121999c12dccSNélio Laranjeiro * Current mini array position is the one returned by 122099c12dccSNélio Laranjeiro * check_cqe64(). 122199c12dccSNélio Laranjeiro * 122299c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 122399c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 122499c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 122599c12dccSNélio Laranjeiro */ 1226*d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 122799c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 122899c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 122999c12dccSNélio Laranjeiro --rxq->cq_ci; 123099c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 123199c12dccSNélio Laranjeiro /* Get packet size to return. */ 123299c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 1233ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[0].rx_hash_result); 123499c12dccSNélio Laranjeiro zip->ai = 1; 1235*d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1236*d2e842d0SYongseok Koh idx = zip->ca; 1237*d2e842d0SYongseok Koh end = zip->cq_ci; 1238*d2e842d0SYongseok Koh while (idx != end) { 1239*d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1240*d2e842d0SYongseok Koh ++idx; 1241*d2e842d0SYongseok Koh } 124299c12dccSNélio Laranjeiro } else { 124399c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 1244ecf60761SNélio Laranjeiro *rss_hash = ntohl(cqe->rx_hash_res); 124599c12dccSNélio Laranjeiro } 124699c12dccSNélio Laranjeiro /* Error while receiving packet. */ 124799c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 124899c12dccSNélio Laranjeiro return -1; 124999c12dccSNélio Laranjeiro } 125099c12dccSNélio Laranjeiro return len; 125199c12dccSNélio Laranjeiro } 125299c12dccSNélio Laranjeiro 125399c12dccSNélio Laranjeiro /** 125467fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 125567fa62bcSAdrien Mazarguil * 125667fa62bcSAdrien Mazarguil * @param[in] rxq 125767fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 12586218063bSNélio Laranjeiro * @param[in] cqe 12596218063bSNélio Laranjeiro * Pointer to CQE. 126067fa62bcSAdrien Mazarguil * 126167fa62bcSAdrien Mazarguil * @return 126267fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 126367fa62bcSAdrien Mazarguil */ 126467fa62bcSAdrien Mazarguil static inline uint32_t 126597267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe) 126667fa62bcSAdrien Mazarguil { 126767fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 12686218063bSNélio Laranjeiro uint8_t l3_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L3_HDR_TYPE_MASK; 12696218063bSNélio Laranjeiro uint8_t l4_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L4_HDR_TYPE_MASK; 127067fa62bcSAdrien Mazarguil 12716218063bSNélio Laranjeiro if ((l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV4) || 12726218063bSNélio Laranjeiro (l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV6)) 127383e9d9a3SNelio Laranjeiro ol_flags |= TRANSPOSE(cqe->hds_ip_ext, 127483e9d9a3SNelio Laranjeiro MLX5_CQE_L3_OK, 127583e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD); 12766218063bSNélio Laranjeiro if ((l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP) || 12776218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_EMP_ACK) || 12786218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_ACK) || 12796218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_UDP)) 128083e9d9a3SNelio Laranjeiro ol_flags |= TRANSPOSE(cqe->hds_ip_ext, 128183e9d9a3SNelio Laranjeiro MLX5_CQE_L4_OK, 128283e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 128397267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 128467fa62bcSAdrien Mazarguil ol_flags |= 128583e9d9a3SNelio Laranjeiro TRANSPOSE(cqe->l4_hdr_type_etc, 1286350f4c48SNelio Laranjeiro MLX5_CQE_RX_OUTER_IP_CSUM_OK, 128783e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 128883e9d9a3SNelio Laranjeiro TRANSPOSE(cqe->l4_hdr_type_etc, 1289350f4c48SNelio Laranjeiro MLX5_CQE_RX_OUTER_TCP_UDP_CSUM_OK, 129083e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 129167fa62bcSAdrien Mazarguil return ol_flags; 129267fa62bcSAdrien Mazarguil } 129367fa62bcSAdrien Mazarguil 129467fa62bcSAdrien Mazarguil /** 12952e22920bSAdrien Mazarguil * DPDK callback for RX. 12962e22920bSAdrien Mazarguil * 12972e22920bSAdrien Mazarguil * @param dpdk_rxq 12982e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 12992e22920bSAdrien Mazarguil * @param[out] pkts 13002e22920bSAdrien Mazarguil * Array to store received packets. 13012e22920bSAdrien Mazarguil * @param pkts_n 13022e22920bSAdrien Mazarguil * Maximum number of packets in array. 13032e22920bSAdrien Mazarguil * 13042e22920bSAdrien Mazarguil * @return 13052e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 13062e22920bSAdrien Mazarguil */ 13072e22920bSAdrien Mazarguil uint16_t 13082e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 13092e22920bSAdrien Mazarguil { 13106218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 1311b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1312e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 13139964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 13149964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 13159964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 131697267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 131797267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 13189964b965SNélio Laranjeiro unsigned int i = 0; 13199964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 1320ecf60761SNélio Laranjeiro int len; /* keep its value across iterations. */ 13212e22920bSAdrien Mazarguil 13229964b965SNélio Laranjeiro while (pkts_n) { 13239964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 13249964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 13259964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1326ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 13279964b965SNélio Laranjeiro 13289964b965SNélio Laranjeiro if (pkt) 13299964b965SNélio Laranjeiro NEXT(seg) = rep; 13309964b965SNélio Laranjeiro seg = rep; 13319964b965SNélio Laranjeiro rte_prefetch0(seg); 13326218063bSNélio Laranjeiro rte_prefetch0(cqe); 13339964b965SNélio Laranjeiro rte_prefetch0(wqe); 1334fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 13352e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 133615a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 133715a756b6SSagi Grimberg if (!pkt) { 133815a756b6SSagi Grimberg /* 133915a756b6SSagi Grimberg * no buffers before we even started, 134015a756b6SSagi Grimberg * bail out silently. 134115a756b6SSagi Grimberg */ 134215a756b6SSagi Grimberg break; 134315a756b6SSagi Grimberg } 1344a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1345a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1346fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 13479964b965SNélio Laranjeiro rte_mbuf_refcnt_set(pkt, 0); 13489964b965SNélio Laranjeiro __rte_mbuf_raw_free(pkt); 1349fe5fe382SNélio Laranjeiro pkt = rep; 13509964b965SNélio Laranjeiro } 13516218063bSNélio Laranjeiro break; 13522e22920bSAdrien Mazarguil } 13539964b965SNélio Laranjeiro if (!pkt) { 135497267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1355ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1356ecf60761SNélio Laranjeiro &rss_hash_res); 1357ecf60761SNélio Laranjeiro if (!len) { 13586218063bSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 13596218063bSNélio Laranjeiro __rte_mbuf_raw_free(rep); 13606218063bSNélio Laranjeiro break; 13616218063bSNélio Laranjeiro } 136299c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 136399c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 136499c12dccSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 136599c12dccSNélio Laranjeiro __rte_mbuf_raw_free(rep); 136699c12dccSNélio Laranjeiro ++rxq->stats.idropped; 136799c12dccSNélio Laranjeiro goto skip; 136899c12dccSNélio Laranjeiro } 13699964b965SNélio Laranjeiro pkt = seg; 13709964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 13719964b965SNélio Laranjeiro /* Update packet information. */ 13720ac64846SMaxime Leroy pkt->packet_type = 0; 13730ac64846SMaxime Leroy pkt->ol_flags = 0; 137436ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1375ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1376ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1377ecf60761SNélio Laranjeiro } 1378ea3bc3b1SNélio Laranjeiro if (rxq->mark && 1379ea3bc3b1SNélio Laranjeiro ((cqe->sop_drop_qpn != 1380ea3bc3b1SNélio Laranjeiro htonl(MLX5_FLOW_MARK_INVALID)) || 1381ea3bc3b1SNélio Laranjeiro (cqe->sop_drop_qpn != 1382ea3bc3b1SNélio Laranjeiro htonl(MLX5_FLOW_MARK_DEFAULT)))) { 1383ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1384ea3bc3b1SNélio Laranjeiro mlx5_flow_mark_get(cqe->sop_drop_qpn); 1385ea3bc3b1SNélio Laranjeiro pkt->ol_flags &= ~PKT_RX_RSS_HASH; 1386ea3bc3b1SNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR | PKT_RX_FDIR_ID; 1387ea3bc3b1SNélio Laranjeiro } 13886218063bSNélio Laranjeiro if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip | 13896218063bSNélio Laranjeiro rxq->crc_present) { 13906218063bSNélio Laranjeiro if (rxq->csum) { 13919964b965SNélio Laranjeiro pkt->packet_type = 13929964b965SNélio Laranjeiro rxq_cq_to_pkt_type(cqe); 1393ecf60761SNélio Laranjeiro pkt->ol_flags |= 13949964b965SNélio Laranjeiro rxq_cq_to_ol_flags(rxq, cqe); 13956218063bSNélio Laranjeiro } 13969964b965SNélio Laranjeiro if (cqe->l4_hdr_type_etc & 13979964b965SNélio Laranjeiro MLX5_CQE_VLAN_STRIPPED) { 13986218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1399b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 14006218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 1401f3db9489SYaacov Hazan } 14026218063bSNélio Laranjeiro if (rxq->crc_present) 14036218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 1404081f7eaeSNelio Laranjeiro } 14056218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 14069964b965SNélio Laranjeiro } 14079964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 14089964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 14099964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 14109964b965SNélio Laranjeiro NB_SEGS(rep) = NB_SEGS(seg); 14119964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 14129964b965SNélio Laranjeiro NEXT(rep) = NULL; 14139964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 14149964b965SNélio Laranjeiro /* 14159964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 14169964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 14179964b965SNélio Laranjeiro * changes. 14189964b965SNélio Laranjeiro */ 14199964b965SNélio Laranjeiro wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t)); 14209964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 14219964b965SNélio Laranjeiro len -= DATA_LEN(seg); 14229964b965SNélio Laranjeiro ++NB_SEGS(pkt); 14239964b965SNélio Laranjeiro ++rq_ci; 14249964b965SNélio Laranjeiro continue; 14259964b965SNélio Laranjeiro } 14269964b965SNélio Laranjeiro DATA_LEN(seg) = len; 142787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 142887011737SAdrien Mazarguil /* Increment bytes counter. */ 14299964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 143087011737SAdrien Mazarguil #endif 14316218063bSNélio Laranjeiro /* Return packet. */ 14326218063bSNélio Laranjeiro *(pkts++) = pkt; 14339964b965SNélio Laranjeiro pkt = NULL; 14349964b965SNélio Laranjeiro --pkts_n; 14359964b965SNélio Laranjeiro ++i; 143699c12dccSNélio Laranjeiro skip: 14379964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 14389964b965SNélio Laranjeiro rq_ci >>= sges_n; 14396218063bSNélio Laranjeiro ++rq_ci; 14409964b965SNélio Laranjeiro rq_ci <<= sges_n; 14412e22920bSAdrien Mazarguil } 14429964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 14432e22920bSAdrien Mazarguil return 0; 14446218063bSNélio Laranjeiro /* Update the consumer index. */ 14459964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 14466218063bSNélio Laranjeiro rte_wmb(); 14476218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 14486218063bSNélio Laranjeiro rte_wmb(); 14496218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 145087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 145187011737SAdrien Mazarguil /* Increment packets counter. */ 14529964b965SNélio Laranjeiro rxq->stats.ipackets += i; 145387011737SAdrien Mazarguil #endif 14549964b965SNélio Laranjeiro return i; 14552e22920bSAdrien Mazarguil } 14562e22920bSAdrien Mazarguil 14572e22920bSAdrien Mazarguil /** 14582e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 14592e22920bSAdrien Mazarguil * 14602e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 14612e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 14622e22920bSAdrien Mazarguil * 14632e22920bSAdrien Mazarguil * @param dpdk_txq 14642e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 14652e22920bSAdrien Mazarguil * @param[in] pkts 14662e22920bSAdrien Mazarguil * Packets to transmit. 14672e22920bSAdrien Mazarguil * @param pkts_n 14682e22920bSAdrien Mazarguil * Number of packets in array. 14692e22920bSAdrien Mazarguil * 14702e22920bSAdrien Mazarguil * @return 14712e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 14722e22920bSAdrien Mazarguil */ 14732e22920bSAdrien Mazarguil uint16_t 14742e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 14752e22920bSAdrien Mazarguil { 14762e22920bSAdrien Mazarguil (void)dpdk_txq; 14772e22920bSAdrien Mazarguil (void)pkts; 14782e22920bSAdrien Mazarguil (void)pkts_n; 14792e22920bSAdrien Mazarguil return 0; 14802e22920bSAdrien Mazarguil } 14812e22920bSAdrien Mazarguil 14822e22920bSAdrien Mazarguil /** 14832e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 14842e22920bSAdrien Mazarguil * 14852e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 14862e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 14872e22920bSAdrien Mazarguil * 14882e22920bSAdrien Mazarguil * @param dpdk_rxq 14892e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 14902e22920bSAdrien Mazarguil * @param[out] pkts 14912e22920bSAdrien Mazarguil * Array to store received packets. 14922e22920bSAdrien Mazarguil * @param pkts_n 14932e22920bSAdrien Mazarguil * Maximum number of packets in array. 14942e22920bSAdrien Mazarguil * 14952e22920bSAdrien Mazarguil * @return 14962e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 14972e22920bSAdrien Mazarguil */ 14982e22920bSAdrien Mazarguil uint16_t 14992e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 15002e22920bSAdrien Mazarguil { 15012e22920bSAdrien Mazarguil (void)dpdk_rxq; 15022e22920bSAdrien Mazarguil (void)pkts; 15032e22920bSAdrien Mazarguil (void)pkts_n; 15042e22920bSAdrien Mazarguil return 0; 15052e22920bSAdrien Mazarguil } 1506