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> 456218063bSNélio Laranjeiro #include <infiniband/mlx5_hw.h> 466218063bSNélio Laranjeiro #include <infiniband/arch.h> 472e22920bSAdrien Mazarguil #ifdef PEDANTIC 482e22920bSAdrien Mazarguil #pragma GCC diagnostic error "-pedantic" 492e22920bSAdrien Mazarguil #endif 502e22920bSAdrien Mazarguil 512e22920bSAdrien Mazarguil /* DPDK headers don't like -pedantic. */ 522e22920bSAdrien Mazarguil #ifdef PEDANTIC 532e22920bSAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic" 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 622e22920bSAdrien Mazarguil #pragma GCC diagnostic error "-pedantic" 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 7299c12dccSNélio Laranjeiro #ifndef NDEBUG 7399c12dccSNélio Laranjeiro 7499c12dccSNélio Laranjeiro /** 7599c12dccSNélio Laranjeiro * Verify or set magic value in CQE. 7699c12dccSNélio Laranjeiro * 7799c12dccSNélio Laranjeiro * @param cqe 7899c12dccSNélio Laranjeiro * Pointer to CQE. 7999c12dccSNélio Laranjeiro * 8099c12dccSNélio Laranjeiro * @return 8199c12dccSNélio Laranjeiro * 0 the first time. 8299c12dccSNélio Laranjeiro */ 8399c12dccSNélio Laranjeiro static inline int 8499c12dccSNélio Laranjeiro check_cqe64_seen(volatile struct mlx5_cqe64 *cqe) 8599c12dccSNélio Laranjeiro { 8699c12dccSNélio Laranjeiro static const uint8_t magic[] = "seen"; 8799c12dccSNélio Laranjeiro volatile uint8_t (*buf)[sizeof(cqe->rsvd40)] = &cqe->rsvd40; 8899c12dccSNélio Laranjeiro int ret = 1; 8999c12dccSNélio Laranjeiro unsigned int i; 9099c12dccSNélio Laranjeiro 9199c12dccSNélio Laranjeiro for (i = 0; i < sizeof(magic) && i < sizeof(*buf); ++i) 9299c12dccSNélio Laranjeiro if (!ret || (*buf)[i] != magic[i]) { 9399c12dccSNélio Laranjeiro ret = 0; 9499c12dccSNélio Laranjeiro (*buf)[i] = magic[i]; 9599c12dccSNélio Laranjeiro } 9699c12dccSNélio Laranjeiro return ret; 9799c12dccSNélio Laranjeiro } 9899c12dccSNélio Laranjeiro 9999c12dccSNélio Laranjeiro #endif /* NDEBUG */ 1006218063bSNélio Laranjeiro 1016218063bSNélio Laranjeiro static inline int 10299c12dccSNélio Laranjeiro check_cqe64(volatile struct mlx5_cqe64 *cqe, 10399c12dccSNélio Laranjeiro unsigned int cqes_n, const uint16_t ci) 10499c12dccSNélio Laranjeiro __attribute__((always_inline)); 1056218063bSNélio Laranjeiro 10699c12dccSNélio Laranjeiro /** 10799c12dccSNélio Laranjeiro * Check whether CQE is valid. 10899c12dccSNélio Laranjeiro * 10999c12dccSNélio Laranjeiro * @param cqe 11099c12dccSNélio Laranjeiro * Pointer to CQE. 11199c12dccSNélio Laranjeiro * @param cqes_n 11299c12dccSNélio Laranjeiro * Size of completion queue. 11399c12dccSNélio Laranjeiro * @param ci 11499c12dccSNélio Laranjeiro * Consumer index. 11599c12dccSNélio Laranjeiro * 11699c12dccSNélio Laranjeiro * @return 11799c12dccSNélio Laranjeiro * 0 on success, 1 on failure. 11899c12dccSNélio Laranjeiro */ 11999c12dccSNélio Laranjeiro static inline int 12099c12dccSNélio Laranjeiro check_cqe64(volatile struct mlx5_cqe64 *cqe, 12199c12dccSNélio Laranjeiro unsigned int cqes_n, const uint16_t ci) 1226218063bSNélio Laranjeiro { 12399c12dccSNélio Laranjeiro uint16_t idx = ci & cqes_n; 12499c12dccSNélio Laranjeiro uint8_t op_own = cqe->op_own; 12599c12dccSNélio Laranjeiro uint8_t op_owner = MLX5_CQE_OWNER(op_own); 12699c12dccSNélio Laranjeiro uint8_t op_code = MLX5_CQE_OPCODE(op_own); 1276218063bSNélio Laranjeiro 12899c12dccSNélio Laranjeiro if (unlikely((op_owner != (!!(idx))) || (op_code == MLX5_CQE_INVALID))) 12999c12dccSNélio Laranjeiro return 1; /* No CQE. */ 13099c12dccSNélio Laranjeiro #ifndef NDEBUG 13199c12dccSNélio Laranjeiro if ((op_code == MLX5_CQE_RESP_ERR) || 13299c12dccSNélio Laranjeiro (op_code == MLX5_CQE_REQ_ERR)) { 13399c12dccSNélio Laranjeiro volatile struct mlx5_err_cqe *err_cqe = (volatile void *)cqe; 13499c12dccSNélio Laranjeiro uint8_t syndrome = err_cqe->syndrome; 13599c12dccSNélio Laranjeiro 13699c12dccSNélio Laranjeiro if ((syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR) || 13799c12dccSNélio Laranjeiro (syndrome == MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR)) 13899c12dccSNélio Laranjeiro return 0; 13999c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 14099c12dccSNélio Laranjeiro ERROR("unexpected CQE error %u (0x%02x)" 14199c12dccSNélio Laranjeiro " syndrome 0x%02x", 14299c12dccSNélio Laranjeiro op_code, op_code, syndrome); 14399c12dccSNélio Laranjeiro return 1; 14499c12dccSNélio Laranjeiro } else if ((op_code != MLX5_CQE_RESP_SEND) && 14599c12dccSNélio Laranjeiro (op_code != MLX5_CQE_REQ)) { 14699c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 14799c12dccSNélio Laranjeiro ERROR("unexpected CQE opcode %u (0x%02x)", 14899c12dccSNélio Laranjeiro op_code, op_code); 14999c12dccSNélio Laranjeiro return 1; 1506218063bSNélio Laranjeiro } 15199c12dccSNélio Laranjeiro #endif /* NDEBUG */ 15299c12dccSNélio Laranjeiro return 0; 1536218063bSNélio Laranjeiro } 1542e22920bSAdrien Mazarguil 1552e22920bSAdrien Mazarguil /** 1562e22920bSAdrien Mazarguil * Manage TX completions. 1572e22920bSAdrien Mazarguil * 1582e22920bSAdrien Mazarguil * When sending a burst, mlx5_tx_burst() posts several WRs. 1592e22920bSAdrien Mazarguil * 1602e22920bSAdrien Mazarguil * @param txq 1612e22920bSAdrien Mazarguil * Pointer to TX queue structure. 1622e22920bSAdrien Mazarguil */ 1631d88ba17SNélio Laranjeiro static void 1642e22920bSAdrien Mazarguil txq_complete(struct txq *txq) 1652e22920bSAdrien Mazarguil { 1662e22920bSAdrien Mazarguil const unsigned int elts_n = txq->elts_n; 1671d88ba17SNélio Laranjeiro const unsigned int cqe_n = txq->cqe_n; 16899c12dccSNélio Laranjeiro const unsigned int cqe_cnt = cqe_n - 1; 1691d88ba17SNélio Laranjeiro uint16_t elts_free = txq->elts_tail; 1701d88ba17SNélio Laranjeiro uint16_t elts_tail; 1711d88ba17SNélio Laranjeiro uint16_t cq_ci = txq->cq_ci; 172c305090bSAdrien Mazarguil volatile struct mlx5_cqe64 *cqe = NULL; 173c305090bSAdrien Mazarguil volatile union mlx5_wqe *wqe; 1742e22920bSAdrien Mazarguil 17599c12dccSNélio Laranjeiro do { 176c305090bSAdrien Mazarguil volatile struct mlx5_cqe64 *tmp; 1771d88ba17SNélio Laranjeiro 178c305090bSAdrien Mazarguil tmp = &(*txq->cqes)[cq_ci & cqe_cnt].cqe64; 179c305090bSAdrien Mazarguil if (check_cqe64(tmp, cqe_n, cq_ci)) 1801d88ba17SNélio Laranjeiro break; 181c305090bSAdrien Mazarguil cqe = tmp; 18299c12dccSNélio Laranjeiro #ifndef NDEBUG 18399c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) { 18499c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 18599c12dccSNélio Laranjeiro ERROR("unexpected compressed CQE, TX stopped"); 18699c12dccSNélio Laranjeiro return; 1872e22920bSAdrien Mazarguil } 18899c12dccSNélio Laranjeiro if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) || 18999c12dccSNélio Laranjeiro (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) { 19099c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 19199c12dccSNélio Laranjeiro ERROR("unexpected error CQE, TX stopped"); 19299c12dccSNélio Laranjeiro return; 19399c12dccSNélio Laranjeiro } 19499c12dccSNélio Laranjeiro #endif /* NDEBUG */ 19599c12dccSNélio Laranjeiro ++cq_ci; 19699c12dccSNélio Laranjeiro } while (1); 197c305090bSAdrien Mazarguil if (unlikely(cqe == NULL)) 1981d88ba17SNélio Laranjeiro return; 199c305090bSAdrien Mazarguil wqe = &(*txq->wqes)[htons(cqe->wqe_counter) & (txq->wqe_n - 1)]; 200c305090bSAdrien Mazarguil elts_tail = wqe->wqe.ctrl.data[3]; 201c305090bSAdrien Mazarguil assert(elts_tail < txq->wqe_n); 2021d88ba17SNélio Laranjeiro /* Free buffers. */ 203c305090bSAdrien Mazarguil while (elts_free != elts_tail) { 2041d88ba17SNélio Laranjeiro struct rte_mbuf *elt = (*txq->elts)[elts_free]; 205a859e8a9SNelio Laranjeiro unsigned int elts_free_next = 2061d88ba17SNélio Laranjeiro (elts_free + 1) & (elts_n - 1); 2071d88ba17SNélio Laranjeiro struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next]; 208a859e8a9SNelio Laranjeiro 209b185e63fSAdrien Mazarguil #ifndef NDEBUG 210b185e63fSAdrien Mazarguil /* Poisoning. */ 2111d88ba17SNélio Laranjeiro memset(&(*txq->elts)[elts_free], 2121d88ba17SNélio Laranjeiro 0x66, 2131d88ba17SNélio Laranjeiro sizeof((*txq->elts)[elts_free])); 214b185e63fSAdrien Mazarguil #endif 2151d88ba17SNélio Laranjeiro RTE_MBUF_PREFETCH_TO_FREE(elt_next); 2161d88ba17SNélio Laranjeiro /* Only one segment needs to be freed. */ 2171d88ba17SNélio Laranjeiro rte_pktmbuf_free_seg(elt); 218a859e8a9SNelio Laranjeiro elts_free = elts_free_next; 219c305090bSAdrien Mazarguil } 2201d88ba17SNélio Laranjeiro txq->cq_ci = cq_ci; 2212e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 2221d88ba17SNélio Laranjeiro /* Update the consumer index. */ 2231d88ba17SNélio Laranjeiro rte_wmb(); 2241d88ba17SNélio Laranjeiro *txq->cq_db = htonl(cq_ci); 2252e22920bSAdrien Mazarguil } 2262e22920bSAdrien Mazarguil 2272e22920bSAdrien Mazarguil /** 2288340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 2298340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 2308340392eSAdrien Mazarguil * 2318340392eSAdrien Mazarguil * @param buf 2328340392eSAdrien Mazarguil * Pointer to mbuf. 2338340392eSAdrien Mazarguil * 2348340392eSAdrien Mazarguil * @return 2358340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 2368340392eSAdrien Mazarguil */ 2378340392eSAdrien Mazarguil static struct rte_mempool * 2388340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 2398340392eSAdrien Mazarguil { 2408340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 2418340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 2428340392eSAdrien Mazarguil return buf->pool; 2438340392eSAdrien Mazarguil } 2448340392eSAdrien Mazarguil 245491770faSNélio Laranjeiro static inline uint32_t 246491770faSNélio Laranjeiro txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 247491770faSNélio Laranjeiro __attribute__((always_inline)); 248491770faSNélio Laranjeiro 2498340392eSAdrien Mazarguil /** 2502e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 2512e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 2522e22920bSAdrien Mazarguil * remove an entry first. 2532e22920bSAdrien Mazarguil * 2542e22920bSAdrien Mazarguil * @param txq 2552e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2562e22920bSAdrien Mazarguil * @param[in] mp 2572e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 2582e22920bSAdrien Mazarguil * 2592e22920bSAdrien Mazarguil * @return 2602e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 2612e22920bSAdrien Mazarguil */ 262491770faSNélio Laranjeiro static inline uint32_t 263d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 2642e22920bSAdrien Mazarguil { 2652e22920bSAdrien Mazarguil unsigned int i; 266491770faSNélio Laranjeiro uint32_t lkey = (uint32_t)-1; 2672e22920bSAdrien Mazarguil 2682e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 2692e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 2702e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 2712e22920bSAdrien Mazarguil break; 2722e22920bSAdrien Mazarguil } 2732e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 2742e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 2751d88ba17SNélio Laranjeiro assert(htonl(txq->mp2mr[i].mr->lkey) == 2761d88ba17SNélio Laranjeiro txq->mp2mr[i].lkey); 277491770faSNélio Laranjeiro lkey = txq->mp2mr[i].lkey; 278491770faSNélio Laranjeiro break; 2792e22920bSAdrien Mazarguil } 2802e22920bSAdrien Mazarguil } 281491770faSNélio Laranjeiro if (unlikely(lkey == (uint32_t)-1)) 282491770faSNélio Laranjeiro lkey = txq_mp2mr_reg(txq, mp, i); 283491770faSNélio Laranjeiro return lkey; 2840a3b350dSOlga Shern } 2850a3b350dSOlga Shern 286e192ef80SYaacov Hazan /** 2871d88ba17SNélio Laranjeiro * Write a regular WQE. 288e192ef80SYaacov Hazan * 2891d88ba17SNélio Laranjeiro * @param txq 2901d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 2911d88ba17SNélio Laranjeiro * @param wqe 2921d88ba17SNélio Laranjeiro * Pointer to the WQE to fill. 2931d88ba17SNélio Laranjeiro * @param addr 2941d88ba17SNélio Laranjeiro * Buffer data address. 2951d88ba17SNélio Laranjeiro * @param length 2961d88ba17SNélio Laranjeiro * Packet length. 2971d88ba17SNélio Laranjeiro * @param lkey 2981d88ba17SNélio Laranjeiro * Memory region lkey. 299e192ef80SYaacov Hazan */ 3001d88ba17SNélio Laranjeiro static inline void 3011d88ba17SNélio Laranjeiro mlx5_wqe_write(struct txq *txq, volatile union mlx5_wqe *wqe, 3021d88ba17SNélio Laranjeiro uintptr_t addr, uint32_t length, uint32_t lkey) 303e192ef80SYaacov Hazan { 3041d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND); 3051d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[1] = htonl((txq->qp_num_8s) | 4); 3061d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[3] = 0; 3071d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd0 = 0; 3081d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd1 = 0; 3091d88ba17SNélio Laranjeiro wqe->inl.eseg.mss = 0; 3101d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd2 = 0; 3111d88ba17SNélio Laranjeiro wqe->wqe.eseg.inline_hdr_sz = htons(MLX5_ETH_INLINE_HEADER_SIZE); 3121d88ba17SNélio Laranjeiro /* Copy the first 16 bytes into inline header. */ 3131d88ba17SNélio Laranjeiro rte_memcpy((uint8_t *)(uintptr_t)wqe->wqe.eseg.inline_hdr_start, 3141d88ba17SNélio Laranjeiro (uint8_t *)(uintptr_t)addr, 3151d88ba17SNélio Laranjeiro MLX5_ETH_INLINE_HEADER_SIZE); 3161d88ba17SNélio Laranjeiro addr += MLX5_ETH_INLINE_HEADER_SIZE; 3171d88ba17SNélio Laranjeiro length -= MLX5_ETH_INLINE_HEADER_SIZE; 3181d88ba17SNélio Laranjeiro /* Store remaining data in data segment. */ 3191d88ba17SNélio Laranjeiro wqe->wqe.dseg.byte_count = htonl(length); 3201d88ba17SNélio Laranjeiro wqe->wqe.dseg.lkey = lkey; 3211d88ba17SNélio Laranjeiro wqe->wqe.dseg.addr = htonll(addr); 3221d88ba17SNélio Laranjeiro /* Increment consumer index. */ 3231d88ba17SNélio Laranjeiro ++txq->wqe_ci; 3241d88ba17SNélio Laranjeiro } 325e192ef80SYaacov Hazan 3261d88ba17SNélio Laranjeiro /** 3271d88ba17SNélio Laranjeiro * Write a regular WQE with VLAN. 3281d88ba17SNélio Laranjeiro * 3291d88ba17SNélio Laranjeiro * @param txq 3301d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 3311d88ba17SNélio Laranjeiro * @param wqe 3321d88ba17SNélio Laranjeiro * Pointer to the WQE to fill. 3331d88ba17SNélio Laranjeiro * @param addr 3341d88ba17SNélio Laranjeiro * Buffer data address. 3351d88ba17SNélio Laranjeiro * @param length 3361d88ba17SNélio Laranjeiro * Packet length. 3371d88ba17SNélio Laranjeiro * @param lkey 3381d88ba17SNélio Laranjeiro * Memory region lkey. 3391d88ba17SNélio Laranjeiro * @param vlan_tci 3401d88ba17SNélio Laranjeiro * VLAN field to insert in packet. 3411d88ba17SNélio Laranjeiro */ 3421d88ba17SNélio Laranjeiro static inline void 3431d88ba17SNélio Laranjeiro mlx5_wqe_write_vlan(struct txq *txq, volatile union mlx5_wqe *wqe, 3441d88ba17SNélio Laranjeiro uintptr_t addr, uint32_t length, uint32_t lkey, 3451d88ba17SNélio Laranjeiro uint16_t vlan_tci) 3461d88ba17SNélio Laranjeiro { 3471d88ba17SNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | vlan_tci); 348e192ef80SYaacov Hazan 3491d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND); 3501d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[1] = htonl((txq->qp_num_8s) | 4); 3511d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[3] = 0; 3521d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd0 = 0; 3531d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd1 = 0; 3541d88ba17SNélio Laranjeiro wqe->inl.eseg.mss = 0; 3551d88ba17SNélio Laranjeiro wqe->inl.eseg.rsvd2 = 0; 3561d88ba17SNélio Laranjeiro wqe->wqe.eseg.inline_hdr_sz = htons(MLX5_ETH_VLAN_INLINE_HEADER_SIZE); 3571d88ba17SNélio Laranjeiro /* 3581d88ba17SNélio Laranjeiro * Copy 12 bytes of source & destination MAC address. 3591d88ba17SNélio Laranjeiro * Copy 4 bytes of VLAN. 3601d88ba17SNélio Laranjeiro * Copy 2 bytes of Ether type. 3611d88ba17SNélio Laranjeiro */ 3621d88ba17SNélio Laranjeiro rte_memcpy((uint8_t *)(uintptr_t)wqe->wqe.eseg.inline_hdr_start, 3631d88ba17SNélio Laranjeiro (uint8_t *)(uintptr_t)addr, 12); 3641d88ba17SNélio Laranjeiro rte_memcpy((uint8_t *)((uintptr_t)wqe->wqe.eseg.inline_hdr_start + 12), 3651d88ba17SNélio Laranjeiro &vlan, sizeof(vlan)); 3661d88ba17SNélio Laranjeiro rte_memcpy((uint8_t *)((uintptr_t)wqe->wqe.eseg.inline_hdr_start + 16), 3671d88ba17SNélio Laranjeiro (uint8_t *)((uintptr_t)addr + 12), 2); 3681d88ba17SNélio Laranjeiro addr += MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan); 3691d88ba17SNélio Laranjeiro length -= MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan); 3701d88ba17SNélio Laranjeiro /* Store remaining data in data segment. */ 3711d88ba17SNélio Laranjeiro wqe->wqe.dseg.byte_count = htonl(length); 3721d88ba17SNélio Laranjeiro wqe->wqe.dseg.lkey = lkey; 3731d88ba17SNélio Laranjeiro wqe->wqe.dseg.addr = htonll(addr); 3741d88ba17SNélio Laranjeiro /* Increment consumer index. */ 3751d88ba17SNélio Laranjeiro ++txq->wqe_ci; 3761d88ba17SNélio Laranjeiro } 377e192ef80SYaacov Hazan 3781d88ba17SNélio Laranjeiro /** 3792a66cf37SYaacov Hazan * Write a inline WQE. 3802a66cf37SYaacov Hazan * 3812a66cf37SYaacov Hazan * @param txq 3822a66cf37SYaacov Hazan * Pointer to TX queue structure. 3832a66cf37SYaacov Hazan * @param wqe 3842a66cf37SYaacov Hazan * Pointer to the WQE to fill. 3852a66cf37SYaacov Hazan * @param addr 3862a66cf37SYaacov Hazan * Buffer data address. 3872a66cf37SYaacov Hazan * @param length 3882a66cf37SYaacov Hazan * Packet length. 3892a66cf37SYaacov Hazan * @param lkey 3902a66cf37SYaacov Hazan * Memory region lkey. 3912a66cf37SYaacov Hazan */ 3922a66cf37SYaacov Hazan static inline void 3932a66cf37SYaacov Hazan mlx5_wqe_write_inline(struct txq *txq, volatile union mlx5_wqe *wqe, 3942a66cf37SYaacov Hazan uintptr_t addr, uint32_t length) 3952a66cf37SYaacov Hazan { 3962a66cf37SYaacov Hazan uint32_t size; 3972a66cf37SYaacov Hazan uint16_t wqe_cnt = txq->wqe_n - 1; 3982a66cf37SYaacov Hazan uint16_t wqe_ci = txq->wqe_ci + 1; 3992a66cf37SYaacov Hazan 4002a66cf37SYaacov Hazan /* Copy the first 16 bytes into inline header. */ 4012a66cf37SYaacov Hazan rte_memcpy((void *)(uintptr_t)wqe->inl.eseg.inline_hdr_start, 4022a66cf37SYaacov Hazan (void *)(uintptr_t)addr, 4032a66cf37SYaacov Hazan MLX5_ETH_INLINE_HEADER_SIZE); 4042a66cf37SYaacov Hazan addr += MLX5_ETH_INLINE_HEADER_SIZE; 4052a66cf37SYaacov Hazan length -= MLX5_ETH_INLINE_HEADER_SIZE; 4062a66cf37SYaacov Hazan size = 3 + ((4 + length + 15) / 16); 4072a66cf37SYaacov Hazan wqe->inl.byte_cnt = htonl(length | MLX5_INLINE_SEG); 4082a66cf37SYaacov Hazan rte_memcpy((void *)(uintptr_t)&wqe->inl.data[0], 4092a66cf37SYaacov Hazan (void *)addr, MLX5_WQE64_INL_DATA); 4102a66cf37SYaacov Hazan addr += MLX5_WQE64_INL_DATA; 4112a66cf37SYaacov Hazan length -= MLX5_WQE64_INL_DATA; 4122a66cf37SYaacov Hazan while (length) { 4132a66cf37SYaacov Hazan volatile union mlx5_wqe *wqe_next = 4142a66cf37SYaacov Hazan &(*txq->wqes)[wqe_ci & wqe_cnt]; 4152a66cf37SYaacov Hazan uint32_t copy_bytes = (length > sizeof(*wqe)) ? 4162a66cf37SYaacov Hazan sizeof(*wqe) : 4172a66cf37SYaacov Hazan length; 4182a66cf37SYaacov Hazan 4192a66cf37SYaacov Hazan rte_mov64((uint8_t *)(uintptr_t)&wqe_next->data[0], 4202a66cf37SYaacov Hazan (uint8_t *)addr); 4212a66cf37SYaacov Hazan addr += copy_bytes; 4222a66cf37SYaacov Hazan length -= copy_bytes; 4232a66cf37SYaacov Hazan ++wqe_ci; 4242a66cf37SYaacov Hazan } 4252a66cf37SYaacov Hazan assert(size < 64); 4262a66cf37SYaacov Hazan wqe->inl.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND); 4272a66cf37SYaacov Hazan wqe->inl.ctrl.data[1] = htonl(txq->qp_num_8s | size); 4282a66cf37SYaacov Hazan wqe->inl.ctrl.data[3] = 0; 4292a66cf37SYaacov Hazan wqe->inl.eseg.rsvd0 = 0; 4302a66cf37SYaacov Hazan wqe->inl.eseg.rsvd1 = 0; 4312a66cf37SYaacov Hazan wqe->inl.eseg.mss = 0; 4322a66cf37SYaacov Hazan wqe->inl.eseg.rsvd2 = 0; 4332a66cf37SYaacov Hazan wqe->inl.eseg.inline_hdr_sz = htons(MLX5_ETH_INLINE_HEADER_SIZE); 4342a66cf37SYaacov Hazan /* Increment consumer index. */ 4352a66cf37SYaacov Hazan txq->wqe_ci = wqe_ci; 4362a66cf37SYaacov Hazan } 4372a66cf37SYaacov Hazan 4382a66cf37SYaacov Hazan /** 4392a66cf37SYaacov Hazan * Write a inline WQE with VLAN. 4402a66cf37SYaacov Hazan * 4412a66cf37SYaacov Hazan * @param txq 4422a66cf37SYaacov Hazan * Pointer to TX queue structure. 4432a66cf37SYaacov Hazan * @param wqe 4442a66cf37SYaacov Hazan * Pointer to the WQE to fill. 4452a66cf37SYaacov Hazan * @param addr 4462a66cf37SYaacov Hazan * Buffer data address. 4472a66cf37SYaacov Hazan * @param length 4482a66cf37SYaacov Hazan * Packet length. 4492a66cf37SYaacov Hazan * @param lkey 4502a66cf37SYaacov Hazan * Memory region lkey. 4512a66cf37SYaacov Hazan * @param vlan_tci 4522a66cf37SYaacov Hazan * VLAN field to insert in packet. 4532a66cf37SYaacov Hazan */ 4542a66cf37SYaacov Hazan static inline void 4552a66cf37SYaacov Hazan mlx5_wqe_write_inline_vlan(struct txq *txq, volatile union mlx5_wqe *wqe, 4562a66cf37SYaacov Hazan uintptr_t addr, uint32_t length, uint16_t vlan_tci) 4572a66cf37SYaacov Hazan { 4582a66cf37SYaacov Hazan uint32_t size; 4592a66cf37SYaacov Hazan uint32_t wqe_cnt = txq->wqe_n - 1; 4602a66cf37SYaacov Hazan uint16_t wqe_ci = txq->wqe_ci + 1; 4612a66cf37SYaacov Hazan uint32_t vlan = htonl(0x81000000 | vlan_tci); 4622a66cf37SYaacov Hazan 4632a66cf37SYaacov Hazan /* 4642a66cf37SYaacov Hazan * Copy 12 bytes of source & destination MAC address. 4652a66cf37SYaacov Hazan * Copy 4 bytes of VLAN. 4662a66cf37SYaacov Hazan * Copy 2 bytes of Ether type. 4672a66cf37SYaacov Hazan */ 4682a66cf37SYaacov Hazan rte_memcpy((uint8_t *)(uintptr_t)wqe->inl.eseg.inline_hdr_start, 4692a66cf37SYaacov Hazan (uint8_t *)addr, 12); 4702a66cf37SYaacov Hazan rte_memcpy((uint8_t *)(uintptr_t)wqe->inl.eseg.inline_hdr_start + 12, 4712a66cf37SYaacov Hazan &vlan, sizeof(vlan)); 4722a66cf37SYaacov Hazan rte_memcpy((uint8_t *)(uintptr_t)wqe->inl.eseg.inline_hdr_start + 16, 4732a66cf37SYaacov Hazan ((uint8_t *)addr + 12), 2); 4742a66cf37SYaacov Hazan addr += MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan); 4752a66cf37SYaacov Hazan length -= MLX5_ETH_VLAN_INLINE_HEADER_SIZE - sizeof(vlan); 4762a66cf37SYaacov Hazan size = (sizeof(wqe->inl.ctrl.ctrl) + 4772a66cf37SYaacov Hazan sizeof(wqe->inl.eseg) + 4782a66cf37SYaacov Hazan sizeof(wqe->inl.byte_cnt) + 4792a66cf37SYaacov Hazan length + 15) / 16; 4802a66cf37SYaacov Hazan wqe->inl.byte_cnt = htonl(length | MLX5_INLINE_SEG); 4812a66cf37SYaacov Hazan rte_memcpy((void *)(uintptr_t)&wqe->inl.data[0], 4822a66cf37SYaacov Hazan (void *)addr, MLX5_WQE64_INL_DATA); 4832a66cf37SYaacov Hazan addr += MLX5_WQE64_INL_DATA; 4842a66cf37SYaacov Hazan length -= MLX5_WQE64_INL_DATA; 4852a66cf37SYaacov Hazan while (length) { 4862a66cf37SYaacov Hazan volatile union mlx5_wqe *wqe_next = 4872a66cf37SYaacov Hazan &(*txq->wqes)[wqe_ci & wqe_cnt]; 4882a66cf37SYaacov Hazan uint32_t copy_bytes = (length > sizeof(*wqe)) ? 4892a66cf37SYaacov Hazan sizeof(*wqe) : 4902a66cf37SYaacov Hazan length; 4912a66cf37SYaacov Hazan 4922a66cf37SYaacov Hazan rte_mov64((uint8_t *)(uintptr_t)&wqe_next->data[0], 4932a66cf37SYaacov Hazan (uint8_t *)addr); 4942a66cf37SYaacov Hazan addr += copy_bytes; 4952a66cf37SYaacov Hazan length -= copy_bytes; 4962a66cf37SYaacov Hazan ++wqe_ci; 4972a66cf37SYaacov Hazan } 4982a66cf37SYaacov Hazan assert(size < 64); 4992a66cf37SYaacov Hazan wqe->inl.ctrl.data[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND); 5002a66cf37SYaacov Hazan wqe->inl.ctrl.data[1] = htonl(txq->qp_num_8s | size); 5012a66cf37SYaacov Hazan wqe->inl.ctrl.data[3] = 0; 5022a66cf37SYaacov Hazan wqe->inl.eseg.rsvd0 = 0; 5032a66cf37SYaacov Hazan wqe->inl.eseg.rsvd1 = 0; 5042a66cf37SYaacov Hazan wqe->inl.eseg.mss = 0; 5052a66cf37SYaacov Hazan wqe->inl.eseg.rsvd2 = 0; 5062a66cf37SYaacov Hazan wqe->inl.eseg.inline_hdr_sz = htons(MLX5_ETH_VLAN_INLINE_HEADER_SIZE); 5072a66cf37SYaacov Hazan /* Increment consumer index. */ 5082a66cf37SYaacov Hazan txq->wqe_ci = wqe_ci; 5092a66cf37SYaacov Hazan } 5102a66cf37SYaacov Hazan 5112a66cf37SYaacov Hazan /** 5121d88ba17SNélio Laranjeiro * Ring TX queue doorbell. 5131d88ba17SNélio Laranjeiro * 5141d88ba17SNélio Laranjeiro * @param txq 5151d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 5161d88ba17SNélio Laranjeiro */ 5171d88ba17SNélio Laranjeiro static inline void 5181d88ba17SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq) 5191d88ba17SNélio Laranjeiro { 5201d88ba17SNélio Laranjeiro uint8_t *dst = (uint8_t *)((uintptr_t)txq->bf_reg + txq->bf_offset); 5211d88ba17SNélio Laranjeiro uint32_t data[4] = { 5221d88ba17SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 5231d88ba17SNélio Laranjeiro htonl(txq->qp_num_8s), 5241d88ba17SNélio Laranjeiro 0, 5251d88ba17SNélio Laranjeiro 0, 5261d88ba17SNélio Laranjeiro }; 5271d88ba17SNélio Laranjeiro rte_wmb(); 5281d88ba17SNélio Laranjeiro *txq->qp_db = htonl(txq->wqe_ci); 5291d88ba17SNélio Laranjeiro /* Ensure ordering between DB record and BF copy. */ 5301d88ba17SNélio Laranjeiro rte_wmb(); 5311d88ba17SNélio Laranjeiro rte_mov16(dst, (uint8_t *)data); 5321d88ba17SNélio Laranjeiro txq->bf_offset ^= txq->bf_buf_size; 5331d88ba17SNélio Laranjeiro } 534e192ef80SYaacov Hazan 5351d88ba17SNélio Laranjeiro /** 5361d88ba17SNélio Laranjeiro * Prefetch a CQE. 5371d88ba17SNélio Laranjeiro * 5381d88ba17SNélio Laranjeiro * @param txq 5391d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 5401d88ba17SNélio Laranjeiro * @param cqe_ci 5411d88ba17SNélio Laranjeiro * CQE consumer index. 5421d88ba17SNélio Laranjeiro */ 5431d88ba17SNélio Laranjeiro static inline void 5441d88ba17SNélio Laranjeiro tx_prefetch_cqe(struct txq *txq, uint16_t ci) 5451d88ba17SNélio Laranjeiro { 5461d88ba17SNélio Laranjeiro volatile struct mlx5_cqe64 *cqe; 5471d88ba17SNélio Laranjeiro 5481d88ba17SNélio Laranjeiro cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64; 5491d88ba17SNélio Laranjeiro rte_prefetch0(cqe); 550e192ef80SYaacov Hazan } 551e192ef80SYaacov Hazan 5522e22920bSAdrien Mazarguil /** 5532a66cf37SYaacov Hazan * Prefetch a WQE. 5542a66cf37SYaacov Hazan * 5552a66cf37SYaacov Hazan * @param txq 5562a66cf37SYaacov Hazan * Pointer to TX queue structure. 5572a66cf37SYaacov Hazan * @param wqe_ci 5582a66cf37SYaacov Hazan * WQE consumer index. 5592a66cf37SYaacov Hazan */ 5602a66cf37SYaacov Hazan static inline void 5612a66cf37SYaacov Hazan tx_prefetch_wqe(struct txq *txq, uint16_t ci) 5622a66cf37SYaacov Hazan { 5632a66cf37SYaacov Hazan volatile union mlx5_wqe *wqe; 5642a66cf37SYaacov Hazan 5652a66cf37SYaacov Hazan wqe = &(*txq->wqes)[ci & (txq->wqe_n - 1)]; 5662a66cf37SYaacov Hazan rte_prefetch0(wqe); 5672a66cf37SYaacov Hazan } 5682a66cf37SYaacov Hazan 5692a66cf37SYaacov Hazan /** 5702e22920bSAdrien Mazarguil * DPDK callback for TX. 5712e22920bSAdrien Mazarguil * 5722e22920bSAdrien Mazarguil * @param dpdk_txq 5732e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 5742e22920bSAdrien Mazarguil * @param[in] pkts 5752e22920bSAdrien Mazarguil * Packets to transmit. 5762e22920bSAdrien Mazarguil * @param pkts_n 5772e22920bSAdrien Mazarguil * Number of packets in array. 5782e22920bSAdrien Mazarguil * 5792e22920bSAdrien Mazarguil * @return 5802e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 5812e22920bSAdrien Mazarguil */ 5822e22920bSAdrien Mazarguil uint16_t 5832e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 5842e22920bSAdrien Mazarguil { 5852e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 5861d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 5872e22920bSAdrien Mazarguil const unsigned int elts_n = txq->elts_n; 588*c3d62cc9SAdrien Mazarguil unsigned int i = 0; 5892e22920bSAdrien Mazarguil unsigned int max; 590c305090bSAdrien Mazarguil unsigned int comp; 5911d88ba17SNélio Laranjeiro volatile union mlx5_wqe *wqe; 5922e22920bSAdrien Mazarguil 5931d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 5941d88ba17SNélio Laranjeiro return 0; 5955e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 5961d88ba17SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 5971d88ba17SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci + 1); 598*c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 5991d88ba17SNélio Laranjeiro /* Start processing. */ 6002e22920bSAdrien Mazarguil txq_complete(txq); 6014f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 6022e22920bSAdrien Mazarguil if (max > elts_n) 6032e22920bSAdrien Mazarguil max -= elts_n; 604*c3d62cc9SAdrien Mazarguil do { 605*c3d62cc9SAdrien Mazarguil struct rte_mbuf *buf; 606*c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 607573f54afSNélio Laranjeiro uintptr_t addr; 608573f54afSNélio Laranjeiro uint32_t length; 609573f54afSNélio Laranjeiro uint32_t lkey; 6102e22920bSAdrien Mazarguil 611*c3d62cc9SAdrien Mazarguil /* 612*c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 613*c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 614*c3d62cc9SAdrien Mazarguil */ 615*c3d62cc9SAdrien Mazarguil if (max < 1 + 1) 616*c3d62cc9SAdrien Mazarguil break; 617*c3d62cc9SAdrien Mazarguil --max; 618*c3d62cc9SAdrien Mazarguil --pkts_n; 619*c3d62cc9SAdrien Mazarguil buf = *(pkts++); 620*c3d62cc9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 6211d88ba17SNélio Laranjeiro wqe = &(*txq->wqes)[txq->wqe_ci & (txq->wqe_n - 1)]; 6221d88ba17SNélio Laranjeiro rte_prefetch0(wqe); 623*c3d62cc9SAdrien Mazarguil if (pkts_n) 624*c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 6252e22920bSAdrien Mazarguil /* Retrieve buffer information. */ 6262e22920bSAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 6272e22920bSAdrien Mazarguil length = DATA_LEN(buf); 6282e22920bSAdrien Mazarguil /* Update element. */ 6291d88ba17SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 6305e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 631*c3d62cc9SAdrien Mazarguil if (pkts_n) 632*c3d62cc9SAdrien Mazarguil rte_prefetch0(rte_pktmbuf_mtod(*pkts, 6331d88ba17SNélio Laranjeiro volatile void *)); 6340431c40fSNélio Laranjeiro /* Retrieve Memory Region key for this memory pool. */ 635d970e992SNelio Laranjeiro lkey = txq_mp2mr(txq, txq_mb2mp(buf)); 6361d88ba17SNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) 6371d88ba17SNélio Laranjeiro mlx5_wqe_write_vlan(txq, wqe, addr, length, lkey, 6381d88ba17SNélio Laranjeiro buf->vlan_tci); 639e192ef80SYaacov Hazan else 6401d88ba17SNélio Laranjeiro mlx5_wqe_write(txq, wqe, addr, length, lkey); 6411d88ba17SNélio Laranjeiro wqe->wqe.ctrl.data[2] = 0; 6421d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 6431d88ba17SNélio Laranjeiro if (buf->ol_flags & 6441d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 6451d88ba17SNélio Laranjeiro wqe->wqe.eseg.cs_flags = 6461d88ba17SNélio Laranjeiro MLX5_ETH_WQE_L3_CSUM | 6471d88ba17SNélio Laranjeiro MLX5_ETH_WQE_L4_CSUM; 6481d88ba17SNélio Laranjeiro } else { 6491d88ba17SNélio Laranjeiro wqe->wqe.eseg.cs_flags = 0; 6501d88ba17SNélio Laranjeiro } 65187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 652573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 653573f54afSNélio Laranjeiro txq->stats.obytes += length; 65487011737SAdrien Mazarguil #endif 6552e22920bSAdrien Mazarguil elts_head = elts_head_next; 656*c3d62cc9SAdrien Mazarguil ++i; 657*c3d62cc9SAdrien Mazarguil } while (pkts_n); 6582e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 6592e22920bSAdrien Mazarguil if (unlikely(i == 0)) 6602e22920bSAdrien Mazarguil return 0; 661c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 662c305090bSAdrien Mazarguil comp = txq->elts_comp + i; 663c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 664c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 665c305090bSAdrien Mazarguil wqe->wqe.ctrl.data[2] = htonl(8); 666c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 667c305090bSAdrien Mazarguil wqe->wqe.ctrl.data[3] = elts_head; 668c305090bSAdrien Mazarguil txq->elts_comp = 0; 669c305090bSAdrien Mazarguil } else { 670c305090bSAdrien Mazarguil txq->elts_comp = comp; 671c305090bSAdrien Mazarguil } 67287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 67387011737SAdrien Mazarguil /* Increment sent packets counter. */ 67487011737SAdrien Mazarguil txq->stats.opackets += i; 67587011737SAdrien Mazarguil #endif 6762e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 6771d88ba17SNélio Laranjeiro mlx5_tx_dbrec(txq); 6782e22920bSAdrien Mazarguil txq->elts_head = elts_head; 6792e22920bSAdrien Mazarguil return i; 6802e22920bSAdrien Mazarguil } 6812e22920bSAdrien Mazarguil 6822e22920bSAdrien Mazarguil /** 6832a66cf37SYaacov Hazan * DPDK callback for TX with inline support. 6842a66cf37SYaacov Hazan * 6852a66cf37SYaacov Hazan * @param dpdk_txq 6862a66cf37SYaacov Hazan * Generic pointer to TX queue structure. 6872a66cf37SYaacov Hazan * @param[in] pkts 6882a66cf37SYaacov Hazan * Packets to transmit. 6892a66cf37SYaacov Hazan * @param pkts_n 6902a66cf37SYaacov Hazan * Number of packets in array. 6912a66cf37SYaacov Hazan * 6922a66cf37SYaacov Hazan * @return 6932a66cf37SYaacov Hazan * Number of packets successfully transmitted (<= pkts_n). 6942a66cf37SYaacov Hazan */ 6952a66cf37SYaacov Hazan uint16_t 6962a66cf37SYaacov Hazan mlx5_tx_burst_inline(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 6972a66cf37SYaacov Hazan { 6982a66cf37SYaacov Hazan struct txq *txq = (struct txq *)dpdk_txq; 6992a66cf37SYaacov Hazan uint16_t elts_head = txq->elts_head; 7002a66cf37SYaacov Hazan const unsigned int elts_n = txq->elts_n; 701*c3d62cc9SAdrien Mazarguil unsigned int i = 0; 7022a66cf37SYaacov Hazan unsigned int max; 7032a66cf37SYaacov Hazan unsigned int comp; 7042a66cf37SYaacov Hazan volatile union mlx5_wqe *wqe; 7052a66cf37SYaacov Hazan unsigned int max_inline = txq->max_inline; 7062a66cf37SYaacov Hazan 7072a66cf37SYaacov Hazan if (unlikely(!pkts_n)) 7082a66cf37SYaacov Hazan return 0; 7092a66cf37SYaacov Hazan /* Prefetch first packet cacheline. */ 7102a66cf37SYaacov Hazan tx_prefetch_cqe(txq, txq->cq_ci); 7112a66cf37SYaacov Hazan tx_prefetch_cqe(txq, txq->cq_ci + 1); 712*c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 7132a66cf37SYaacov Hazan /* Start processing. */ 7142a66cf37SYaacov Hazan txq_complete(txq); 7152a66cf37SYaacov Hazan max = (elts_n - (elts_head - txq->elts_tail)); 7162a66cf37SYaacov Hazan if (max > elts_n) 7172a66cf37SYaacov Hazan max -= elts_n; 718*c3d62cc9SAdrien Mazarguil do { 719*c3d62cc9SAdrien Mazarguil struct rte_mbuf *buf; 720*c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 7212a66cf37SYaacov Hazan uintptr_t addr; 7222a66cf37SYaacov Hazan uint32_t length; 7232a66cf37SYaacov Hazan uint32_t lkey; 7242a66cf37SYaacov Hazan 725*c3d62cc9SAdrien Mazarguil /* 726*c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 727*c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 728*c3d62cc9SAdrien Mazarguil */ 729*c3d62cc9SAdrien Mazarguil if (max < 1 + 1) 730*c3d62cc9SAdrien Mazarguil break; 731*c3d62cc9SAdrien Mazarguil --max; 732*c3d62cc9SAdrien Mazarguil --pkts_n; 733*c3d62cc9SAdrien Mazarguil buf = *(pkts++); 734*c3d62cc9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 7352a66cf37SYaacov Hazan wqe = &(*txq->wqes)[txq->wqe_ci & (txq->wqe_n - 1)]; 7362a66cf37SYaacov Hazan tx_prefetch_wqe(txq, txq->wqe_ci); 7372a66cf37SYaacov Hazan tx_prefetch_wqe(txq, txq->wqe_ci + 1); 738*c3d62cc9SAdrien Mazarguil if (pkts_n) 739*c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 7402a66cf37SYaacov Hazan /* Should we enable HW CKSUM offload */ 7412a66cf37SYaacov Hazan if (buf->ol_flags & 7422a66cf37SYaacov Hazan (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 7432a66cf37SYaacov Hazan wqe->inl.eseg.cs_flags = 7442a66cf37SYaacov Hazan MLX5_ETH_WQE_L3_CSUM | 7452a66cf37SYaacov Hazan MLX5_ETH_WQE_L4_CSUM; 7462a66cf37SYaacov Hazan } else { 7472a66cf37SYaacov Hazan wqe->inl.eseg.cs_flags = 0; 7482a66cf37SYaacov Hazan } 7492a66cf37SYaacov Hazan /* Retrieve buffer information. */ 7502a66cf37SYaacov Hazan addr = rte_pktmbuf_mtod(buf, uintptr_t); 7512a66cf37SYaacov Hazan length = DATA_LEN(buf); 7522a66cf37SYaacov Hazan /* Update element. */ 7532a66cf37SYaacov Hazan (*txq->elts)[elts_head] = buf; 7542a66cf37SYaacov Hazan /* Prefetch next buffer data. */ 755*c3d62cc9SAdrien Mazarguil if (pkts_n) 756*c3d62cc9SAdrien Mazarguil rte_prefetch0(rte_pktmbuf_mtod(*pkts, 7572a66cf37SYaacov Hazan volatile void *)); 7582a66cf37SYaacov Hazan if (length <= max_inline) { 7592a66cf37SYaacov Hazan if (buf->ol_flags & PKT_TX_VLAN_PKT) 7602a66cf37SYaacov Hazan mlx5_wqe_write_inline_vlan(txq, wqe, 7612a66cf37SYaacov Hazan addr, length, 7622a66cf37SYaacov Hazan buf->vlan_tci); 7632a66cf37SYaacov Hazan else 7642a66cf37SYaacov Hazan mlx5_wqe_write_inline(txq, wqe, addr, length); 7652a66cf37SYaacov Hazan } else { 7662a66cf37SYaacov Hazan /* Retrieve Memory Region key for this memory pool. */ 7672a66cf37SYaacov Hazan lkey = txq_mp2mr(txq, txq_mb2mp(buf)); 7682a66cf37SYaacov Hazan if (buf->ol_flags & PKT_TX_VLAN_PKT) 7692a66cf37SYaacov Hazan mlx5_wqe_write_vlan(txq, wqe, addr, length, 7702a66cf37SYaacov Hazan lkey, buf->vlan_tci); 7712a66cf37SYaacov Hazan else 7722a66cf37SYaacov Hazan mlx5_wqe_write(txq, wqe, addr, length, lkey); 7732a66cf37SYaacov Hazan } 7742a66cf37SYaacov Hazan wqe->inl.ctrl.data[2] = 0; 7752a66cf37SYaacov Hazan elts_head = elts_head_next; 7762a66cf37SYaacov Hazan #ifdef MLX5_PMD_SOFT_COUNTERS 7772a66cf37SYaacov Hazan /* Increment sent bytes counter. */ 7782a66cf37SYaacov Hazan txq->stats.obytes += length; 7792a66cf37SYaacov Hazan #endif 780*c3d62cc9SAdrien Mazarguil ++i; 781*c3d62cc9SAdrien Mazarguil } while (pkts_n); 7822a66cf37SYaacov Hazan /* Take a shortcut if nothing must be sent. */ 7832a66cf37SYaacov Hazan if (unlikely(i == 0)) 7842a66cf37SYaacov Hazan return 0; 7852a66cf37SYaacov Hazan /* Check whether completion threshold has been reached. */ 7862a66cf37SYaacov Hazan comp = txq->elts_comp + i; 7872a66cf37SYaacov Hazan if (comp >= MLX5_TX_COMP_THRESH) { 7882a66cf37SYaacov Hazan /* Request completion on last WQE. */ 7892a66cf37SYaacov Hazan wqe->inl.ctrl.data[2] = htonl(8); 7902a66cf37SYaacov Hazan /* Save elts_head in unused "immediate" field of WQE. */ 7912a66cf37SYaacov Hazan wqe->inl.ctrl.data[3] = elts_head; 7922a66cf37SYaacov Hazan txq->elts_comp = 0; 7932a66cf37SYaacov Hazan } else { 7942a66cf37SYaacov Hazan txq->elts_comp = comp; 7952a66cf37SYaacov Hazan } 7962a66cf37SYaacov Hazan #ifdef MLX5_PMD_SOFT_COUNTERS 7972a66cf37SYaacov Hazan /* Increment sent packets counter. */ 7982a66cf37SYaacov Hazan txq->stats.opackets += i; 7992a66cf37SYaacov Hazan #endif 8002a66cf37SYaacov Hazan /* Ring QP doorbell. */ 8012a66cf37SYaacov Hazan mlx5_tx_dbrec(txq); 8022a66cf37SYaacov Hazan txq->elts_head = elts_head; 8032a66cf37SYaacov Hazan return i; 8042a66cf37SYaacov Hazan } 8052a66cf37SYaacov Hazan 8062a66cf37SYaacov Hazan /** 807230189d9SNélio Laranjeiro * Open a MPW session. 808230189d9SNélio Laranjeiro * 809230189d9SNélio Laranjeiro * @param txq 810230189d9SNélio Laranjeiro * Pointer to TX queue structure. 811230189d9SNélio Laranjeiro * @param mpw 812230189d9SNélio Laranjeiro * Pointer to MPW session structure. 813230189d9SNélio Laranjeiro * @param length 814230189d9SNélio Laranjeiro * Packet length. 815230189d9SNélio Laranjeiro */ 816230189d9SNélio Laranjeiro static inline void 817230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 818230189d9SNélio Laranjeiro { 819230189d9SNélio Laranjeiro uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1); 820230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 821230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 822230189d9SNélio Laranjeiro (uintptr_t)&(*txq->wqes)[(idx + 1) & (txq->wqe_n - 1)]; 823230189d9SNélio Laranjeiro 824230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 825230189d9SNélio Laranjeiro mpw->pkts_n = 0; 826230189d9SNélio Laranjeiro mpw->len = length; 827230189d9SNélio Laranjeiro mpw->total_len = 0; 828230189d9SNélio Laranjeiro mpw->wqe = &(*txq->wqes)[idx]; 829230189d9SNélio Laranjeiro mpw->wqe->mpw.eseg.mss = htons(length); 830230189d9SNélio Laranjeiro mpw->wqe->mpw.eseg.inline_hdr_sz = 0; 831230189d9SNélio Laranjeiro mpw->wqe->mpw.eseg.rsvd0 = 0; 832230189d9SNélio Laranjeiro mpw->wqe->mpw.eseg.rsvd1 = 0; 833230189d9SNélio Laranjeiro mpw->wqe->mpw.eseg.rsvd2 = 0; 834230189d9SNélio Laranjeiro mpw->wqe->mpw.ctrl.data[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 835230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 836230189d9SNélio Laranjeiro MLX5_OPCODE_LSO_MPW); 837230189d9SNélio Laranjeiro mpw->wqe->mpw.ctrl.data[2] = 0; 838230189d9SNélio Laranjeiro mpw->wqe->mpw.ctrl.data[3] = 0; 839230189d9SNélio Laranjeiro mpw->data.dseg[0] = &mpw->wqe->mpw.dseg[0]; 840230189d9SNélio Laranjeiro mpw->data.dseg[1] = &mpw->wqe->mpw.dseg[1]; 841230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 842230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 843230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 844230189d9SNélio Laranjeiro } 845230189d9SNélio Laranjeiro 846230189d9SNélio Laranjeiro /** 847230189d9SNélio Laranjeiro * Close a MPW session. 848230189d9SNélio Laranjeiro * 849230189d9SNélio Laranjeiro * @param txq 850230189d9SNélio Laranjeiro * Pointer to TX queue structure. 851230189d9SNélio Laranjeiro * @param mpw 852230189d9SNélio Laranjeiro * Pointer to MPW session structure. 853230189d9SNélio Laranjeiro */ 854230189d9SNélio Laranjeiro static inline void 855230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 856230189d9SNélio Laranjeiro { 857230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 858230189d9SNélio Laranjeiro 859230189d9SNélio Laranjeiro /* 860230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 861230189d9SNélio Laranjeiro * count as 2. 862230189d9SNélio Laranjeiro */ 863230189d9SNélio Laranjeiro mpw->wqe->mpw.ctrl.data[1] = htonl(txq->qp_num_8s | (2 + num)); 864230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 865230189d9SNélio Laranjeiro if (num < 3) 866230189d9SNélio Laranjeiro ++txq->wqe_ci; 867230189d9SNélio Laranjeiro else 868230189d9SNélio Laranjeiro txq->wqe_ci += 2; 869230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 870230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 871230189d9SNélio Laranjeiro } 872230189d9SNélio Laranjeiro 873230189d9SNélio Laranjeiro /** 874230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 875230189d9SNélio Laranjeiro * 876230189d9SNélio Laranjeiro * @param dpdk_txq 877230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 878230189d9SNélio Laranjeiro * @param[in] pkts 879230189d9SNélio Laranjeiro * Packets to transmit. 880230189d9SNélio Laranjeiro * @param pkts_n 881230189d9SNélio Laranjeiro * Number of packets in array. 882230189d9SNélio Laranjeiro * 883230189d9SNélio Laranjeiro * @return 884230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 885230189d9SNélio Laranjeiro */ 886230189d9SNélio Laranjeiro uint16_t 887230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 888230189d9SNélio Laranjeiro { 889230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 890230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 891230189d9SNélio Laranjeiro const unsigned int elts_n = txq->elts_n; 892*c3d62cc9SAdrien Mazarguil unsigned int i = 0; 893230189d9SNélio Laranjeiro unsigned int max; 894230189d9SNélio Laranjeiro unsigned int comp; 895230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 896230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 897230189d9SNélio Laranjeiro }; 898230189d9SNélio Laranjeiro 899*c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 900*c3d62cc9SAdrien Mazarguil return 0; 901230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 902230189d9SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 903230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 904230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 905230189d9SNélio Laranjeiro /* Start processing. */ 906230189d9SNélio Laranjeiro txq_complete(txq); 907230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 908230189d9SNélio Laranjeiro if (max > elts_n) 909230189d9SNélio Laranjeiro max -= elts_n; 910*c3d62cc9SAdrien Mazarguil do { 911*c3d62cc9SAdrien Mazarguil struct rte_mbuf *buf; 912230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 913*c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 914230189d9SNélio Laranjeiro uintptr_t addr; 915230189d9SNélio Laranjeiro uint32_t length; 916230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 917230189d9SNélio Laranjeiro 918*c3d62cc9SAdrien Mazarguil /* 919*c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 920*c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 921*c3d62cc9SAdrien Mazarguil */ 922*c3d62cc9SAdrien Mazarguil if (max < 1 + 1) 923*c3d62cc9SAdrien Mazarguil break; 924*c3d62cc9SAdrien Mazarguil --max; 925*c3d62cc9SAdrien Mazarguil --pkts_n; 926*c3d62cc9SAdrien Mazarguil buf = *(pkts++); 927*c3d62cc9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 928230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 929230189d9SNélio Laranjeiro if (buf->ol_flags & 930230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 931230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 932230189d9SNélio Laranjeiro /* Retrieve buffer information. */ 933230189d9SNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 934230189d9SNélio Laranjeiro length = DATA_LEN(buf); 935230189d9SNélio Laranjeiro /* Update element. */ 936230189d9SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 937230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 938230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 939230189d9SNélio Laranjeiro ((mpw.len != length) || 940230189d9SNélio Laranjeiro (mpw.wqe->mpw.eseg.cs_flags != cs_flags))) 941230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 942230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 943230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 944230189d9SNélio Laranjeiro mpw.wqe->mpw.eseg.cs_flags = cs_flags; 945230189d9SNélio Laranjeiro } 946230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 947230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 948230189d9SNélio Laranjeiro .byte_count = htonl(length), 949230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 950230189d9SNélio Laranjeiro .addr = htonll(addr), 951230189d9SNélio Laranjeiro }; 952230189d9SNélio Laranjeiro ++mpw.pkts_n; 953230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 954230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 955230189d9SNélio Laranjeiro elts_head = elts_head_next; 956230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 957230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 958230189d9SNélio Laranjeiro txq->stats.obytes += length; 959230189d9SNélio Laranjeiro #endif 960*c3d62cc9SAdrien Mazarguil ++i; 961*c3d62cc9SAdrien Mazarguil } while (pkts_n); 962230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 963230189d9SNélio Laranjeiro if (unlikely(i == 0)) 964230189d9SNélio Laranjeiro return 0; 965230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 966230189d9SNélio Laranjeiro comp = txq->elts_comp + i; 967230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 968230189d9SNélio Laranjeiro volatile union mlx5_wqe *wqe = mpw.wqe; 969230189d9SNélio Laranjeiro 970230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 971230189d9SNélio Laranjeiro wqe->mpw.ctrl.data[2] = htonl(8); 972230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 973230189d9SNélio Laranjeiro wqe->mpw.ctrl.data[3] = elts_head; 974230189d9SNélio Laranjeiro txq->elts_comp = 0; 975230189d9SNélio Laranjeiro } else { 976230189d9SNélio Laranjeiro txq->elts_comp = comp; 977230189d9SNélio Laranjeiro } 978230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 979230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 980230189d9SNélio Laranjeiro txq->stats.opackets += i; 981230189d9SNélio Laranjeiro #endif 982230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 983230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 984230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 985230189d9SNélio Laranjeiro mlx5_tx_dbrec(txq); 986230189d9SNélio Laranjeiro txq->elts_head = elts_head; 987230189d9SNélio Laranjeiro return i; 988230189d9SNélio Laranjeiro } 989230189d9SNélio Laranjeiro 990230189d9SNélio Laranjeiro /** 991230189d9SNélio Laranjeiro * Open a MPW inline session. 992230189d9SNélio Laranjeiro * 993230189d9SNélio Laranjeiro * @param txq 994230189d9SNélio Laranjeiro * Pointer to TX queue structure. 995230189d9SNélio Laranjeiro * @param mpw 996230189d9SNélio Laranjeiro * Pointer to MPW session structure. 997230189d9SNélio Laranjeiro * @param length 998230189d9SNélio Laranjeiro * Packet length. 999230189d9SNélio Laranjeiro */ 1000230189d9SNélio Laranjeiro static inline void 1001230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 1002230189d9SNélio Laranjeiro { 1003230189d9SNélio Laranjeiro uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1); 1004230189d9SNélio Laranjeiro 1005230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 1006230189d9SNélio Laranjeiro mpw->pkts_n = 0; 1007230189d9SNélio Laranjeiro mpw->len = length; 1008230189d9SNélio Laranjeiro mpw->total_len = 0; 1009230189d9SNélio Laranjeiro mpw->wqe = &(*txq->wqes)[idx]; 1010230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.ctrl.data[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 1011230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 1012230189d9SNélio Laranjeiro MLX5_OPCODE_LSO_MPW); 1013230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.ctrl.data[2] = 0; 1014230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.ctrl.data[3] = 0; 1015230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.mss = htons(length); 1016230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.inline_hdr_sz = 0; 1017230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.cs_flags = 0; 1018230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.rsvd0 = 0; 1019230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.rsvd1 = 0; 1020230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.eseg.rsvd2 = 0; 1021230189d9SNélio Laranjeiro mpw->data.raw = &mpw->wqe->mpw_inl.data[0]; 1022230189d9SNélio Laranjeiro } 1023230189d9SNélio Laranjeiro 1024230189d9SNélio Laranjeiro /** 1025230189d9SNélio Laranjeiro * Close a MPW inline session. 1026230189d9SNélio Laranjeiro * 1027230189d9SNélio Laranjeiro * @param txq 1028230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1029230189d9SNélio Laranjeiro * @param mpw 1030230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1031230189d9SNélio Laranjeiro */ 1032230189d9SNélio Laranjeiro static inline void 1033230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 1034230189d9SNélio Laranjeiro { 1035230189d9SNélio Laranjeiro unsigned int size; 1036230189d9SNélio Laranjeiro 1037230189d9SNélio Laranjeiro size = sizeof(*mpw->wqe) - MLX5_MWQE64_INL_DATA + mpw->total_len; 1038230189d9SNélio Laranjeiro /* 1039230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1040230189d9SNélio Laranjeiro * count as 2. 1041230189d9SNélio Laranjeiro */ 1042230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.ctrl.data[1] = 1043230189d9SNélio Laranjeiro htonl(txq->qp_num_8s | ((size + 15) / 16)); 1044230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 1045230189d9SNélio Laranjeiro mpw->wqe->mpw_inl.byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 1046230189d9SNélio Laranjeiro txq->wqe_ci += (size + (sizeof(*mpw->wqe) - 1)) / sizeof(*mpw->wqe); 1047230189d9SNélio Laranjeiro } 1048230189d9SNélio Laranjeiro 1049230189d9SNélio Laranjeiro /** 1050230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1051230189d9SNélio Laranjeiro * 1052230189d9SNélio Laranjeiro * @param dpdk_txq 1053230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1054230189d9SNélio Laranjeiro * @param[in] pkts 1055230189d9SNélio Laranjeiro * Packets to transmit. 1056230189d9SNélio Laranjeiro * @param pkts_n 1057230189d9SNélio Laranjeiro * Number of packets in array. 1058230189d9SNélio Laranjeiro * 1059230189d9SNélio Laranjeiro * @return 1060230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1061230189d9SNélio Laranjeiro */ 1062230189d9SNélio Laranjeiro uint16_t 1063230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1064230189d9SNélio Laranjeiro uint16_t pkts_n) 1065230189d9SNélio Laranjeiro { 1066230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 1067230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 1068230189d9SNélio Laranjeiro const unsigned int elts_n = txq->elts_n; 1069*c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1070230189d9SNélio Laranjeiro unsigned int max; 1071230189d9SNélio Laranjeiro unsigned int comp; 1072230189d9SNélio Laranjeiro unsigned int inline_room = txq->max_inline; 1073230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1074230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1075230189d9SNélio Laranjeiro }; 1076230189d9SNélio Laranjeiro 1077*c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1078*c3d62cc9SAdrien Mazarguil return 0; 1079230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1080230189d9SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 1081230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 1082230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 1083230189d9SNélio Laranjeiro /* Start processing. */ 1084230189d9SNélio Laranjeiro txq_complete(txq); 1085230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 1086230189d9SNélio Laranjeiro if (max > elts_n) 1087230189d9SNélio Laranjeiro max -= elts_n; 1088*c3d62cc9SAdrien Mazarguil do { 1089*c3d62cc9SAdrien Mazarguil struct rte_mbuf *buf; 1090*c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 1091230189d9SNélio Laranjeiro uintptr_t addr; 1092230189d9SNélio Laranjeiro uint32_t length; 1093230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 1094230189d9SNélio Laranjeiro 1095*c3d62cc9SAdrien Mazarguil /* 1096*c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1097*c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1098*c3d62cc9SAdrien Mazarguil */ 1099*c3d62cc9SAdrien Mazarguil if (max < 1 + 1) 1100*c3d62cc9SAdrien Mazarguil break; 1101*c3d62cc9SAdrien Mazarguil --max; 1102*c3d62cc9SAdrien Mazarguil --pkts_n; 1103*c3d62cc9SAdrien Mazarguil buf = *(pkts++); 1104*c3d62cc9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1105230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 1106230189d9SNélio Laranjeiro if (buf->ol_flags & 1107230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 1108230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 1109230189d9SNélio Laranjeiro /* Retrieve buffer information. */ 1110230189d9SNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 1111230189d9SNélio Laranjeiro length = DATA_LEN(buf); 1112230189d9SNélio Laranjeiro /* Update element. */ 1113230189d9SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 1114230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1115230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1116230189d9SNélio Laranjeiro if ((mpw.len != length) || 1117230189d9SNélio Laranjeiro (mpw.wqe->mpw.eseg.cs_flags != cs_flags)) 1118230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1119230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1120230189d9SNélio Laranjeiro if ((mpw.len != length) || 1121230189d9SNélio Laranjeiro (length > inline_room) || 1122230189d9SNélio Laranjeiro (mpw.wqe->mpw_inl.eseg.cs_flags != cs_flags)) { 1123230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1124230189d9SNélio Laranjeiro inline_room = txq->max_inline; 1125230189d9SNélio Laranjeiro } 1126230189d9SNélio Laranjeiro } 1127230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1128230189d9SNélio Laranjeiro if (length > inline_room) { 1129230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 1130230189d9SNélio Laranjeiro mpw.wqe->mpw.eseg.cs_flags = cs_flags; 1131230189d9SNélio Laranjeiro } else { 1132230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 1133230189d9SNélio Laranjeiro mpw.wqe->mpw_inl.eseg.cs_flags = cs_flags; 1134230189d9SNélio Laranjeiro } 1135230189d9SNélio Laranjeiro } 1136230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1137230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1138230189d9SNélio Laranjeiro 1139230189d9SNélio Laranjeiro assert(inline_room == txq->max_inline); 1140230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1141230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 1142230189d9SNélio Laranjeiro .byte_count = htonl(length), 1143230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 1144230189d9SNélio Laranjeiro .addr = htonll(addr), 1145230189d9SNélio Laranjeiro }; 1146230189d9SNélio Laranjeiro ++mpw.pkts_n; 1147230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1148230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1149230189d9SNélio Laranjeiro } else { 1150230189d9SNélio Laranjeiro unsigned int max; 1151230189d9SNélio Laranjeiro 1152230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1153230189d9SNélio Laranjeiro assert(length <= inline_room); 1154230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1155230189d9SNélio Laranjeiro max = ((uintptr_t)&(*txq->wqes)[txq->wqe_n] - 1156230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1157230189d9SNélio Laranjeiro if (length > max) { 1158230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1159230189d9SNélio Laranjeiro (void *)addr, 1160230189d9SNélio Laranjeiro max); 1161230189d9SNélio Laranjeiro mpw.data.raw = 1162230189d9SNélio Laranjeiro (volatile void *)&(*txq->wqes)[0]; 1163230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1164230189d9SNélio Laranjeiro (void *)(addr + max), 1165230189d9SNélio Laranjeiro length - max); 1166230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1167230189d9SNélio Laranjeiro } else { 1168230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1169230189d9SNélio Laranjeiro (void *)addr, 1170230189d9SNélio Laranjeiro length); 1171230189d9SNélio Laranjeiro mpw.data.raw += length; 1172230189d9SNélio Laranjeiro } 1173230189d9SNélio Laranjeiro if ((uintptr_t)mpw.data.raw == 1174230189d9SNélio Laranjeiro (uintptr_t)&(*txq->wqes)[txq->wqe_n]) 1175230189d9SNélio Laranjeiro mpw.data.raw = 1176230189d9SNélio Laranjeiro (volatile void *)&(*txq->wqes)[0]; 1177230189d9SNélio Laranjeiro ++mpw.pkts_n; 1178230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1179230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1180230189d9SNélio Laranjeiro inline_room = txq->max_inline; 1181230189d9SNélio Laranjeiro } else { 1182230189d9SNélio Laranjeiro inline_room -= length; 1183230189d9SNélio Laranjeiro } 1184230189d9SNélio Laranjeiro } 1185230189d9SNélio Laranjeiro mpw.total_len += length; 1186230189d9SNélio Laranjeiro elts_head = elts_head_next; 1187230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1188230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1189230189d9SNélio Laranjeiro txq->stats.obytes += length; 1190230189d9SNélio Laranjeiro #endif 1191*c3d62cc9SAdrien Mazarguil ++i; 1192*c3d62cc9SAdrien Mazarguil } while (pkts_n); 1193230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1194230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1195230189d9SNélio Laranjeiro return 0; 1196230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1197230189d9SNélio Laranjeiro comp = txq->elts_comp + i; 1198230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 1199230189d9SNélio Laranjeiro volatile union mlx5_wqe *wqe = mpw.wqe; 1200230189d9SNélio Laranjeiro 1201230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 1202230189d9SNélio Laranjeiro wqe->mpw_inl.ctrl.data[2] = htonl(8); 1203230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 1204230189d9SNélio Laranjeiro wqe->mpw_inl.ctrl.data[3] = elts_head; 1205230189d9SNélio Laranjeiro txq->elts_comp = 0; 1206230189d9SNélio Laranjeiro } else { 1207230189d9SNélio Laranjeiro txq->elts_comp = comp; 1208230189d9SNélio Laranjeiro } 1209230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1210230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1211230189d9SNélio Laranjeiro txq->stats.opackets += i; 1212230189d9SNélio Laranjeiro #endif 1213230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1214230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1215230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1216230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1217230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1218230189d9SNélio Laranjeiro mlx5_tx_dbrec(txq); 1219230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1220230189d9SNélio Laranjeiro return i; 1221230189d9SNélio Laranjeiro } 1222230189d9SNélio Laranjeiro 1223230189d9SNélio Laranjeiro /** 122467fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 122567fa62bcSAdrien Mazarguil * 12266218063bSNélio Laranjeiro * @param[in] cqe 12276218063bSNélio Laranjeiro * Pointer to CQE. 122867fa62bcSAdrien Mazarguil * 122978a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 123078a38edfSJianfeng Tan * 123167fa62bcSAdrien Mazarguil * @return 123267fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 123367fa62bcSAdrien Mazarguil */ 123467fa62bcSAdrien Mazarguil static inline uint32_t 12356218063bSNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe64 *cqe) 123667fa62bcSAdrien Mazarguil { 123767fa62bcSAdrien Mazarguil uint32_t pkt_type; 12386218063bSNélio Laranjeiro uint8_t flags = cqe->l4_hdr_type_etc; 12396218063bSNélio Laranjeiro uint8_t info = cqe->rsvd0[0]; 124067fa62bcSAdrien Mazarguil 12416218063bSNélio Laranjeiro if (info & IBV_EXP_CQ_RX_TUNNEL_PACKET) 124267fa62bcSAdrien Mazarguil pkt_type = 124367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 124467fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV4_PACKET, 124567fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 124667fa62bcSAdrien Mazarguil TRANSPOSE(flags, 124767fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV6_PACKET, 124867fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6) | 124967fa62bcSAdrien Mazarguil TRANSPOSE(flags, 125067fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 125167fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV4) | 125267fa62bcSAdrien Mazarguil TRANSPOSE(flags, 125367fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 125467fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV6); 125567fa62bcSAdrien Mazarguil else 125667fa62bcSAdrien Mazarguil pkt_type = 125767fa62bcSAdrien Mazarguil TRANSPOSE(flags, 12586218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 12596218063bSNélio Laranjeiro RTE_PTYPE_L3_IPV6) | 126067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 12616218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 12626218063bSNélio Laranjeiro RTE_PTYPE_L3_IPV4); 126367fa62bcSAdrien Mazarguil return pkt_type; 126467fa62bcSAdrien Mazarguil } 126567fa62bcSAdrien Mazarguil 126667fa62bcSAdrien Mazarguil /** 126799c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 126899c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 126999c12dccSNélio Laranjeiro * been processed. 127099c12dccSNélio Laranjeiro * 127199c12dccSNélio Laranjeiro * @param rxq 127299c12dccSNélio Laranjeiro * Pointer to RX queue. 127399c12dccSNélio Laranjeiro * @param cqe 127499c12dccSNélio Laranjeiro * CQE to process. 127599c12dccSNélio Laranjeiro * 127699c12dccSNélio Laranjeiro * @return 127799c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 127899c12dccSNélio Laranjeiro * with error. 127999c12dccSNélio Laranjeiro */ 128099c12dccSNélio Laranjeiro static inline int 128199c12dccSNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe, 128299c12dccSNélio Laranjeiro uint16_t cqe_cnt) 128399c12dccSNélio Laranjeiro { 128499c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 128599c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 128699c12dccSNélio Laranjeiro int len = 0; 128799c12dccSNélio Laranjeiro 128899c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 128999c12dccSNélio Laranjeiro if (zip->ai) { 129099c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 129199c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 129299c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].cqe64); 129399c12dccSNélio Laranjeiro 129499c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 129599c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 129699c12dccSNélio Laranjeiro /* 129799c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 129899c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 129999c12dccSNélio Laranjeiro * ring for software use. 130099c12dccSNélio Laranjeiro */ 130199c12dccSNélio Laranjeiro zip->ca = zip->na; 130299c12dccSNélio Laranjeiro zip->na += 8; 130399c12dccSNélio Laranjeiro } 130499c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 130599c12dccSNélio Laranjeiro uint16_t idx = rxq->cq_ci; 130699c12dccSNélio Laranjeiro uint16_t end = zip->cq_ci; 130799c12dccSNélio Laranjeiro 130899c12dccSNélio Laranjeiro while (idx != end) { 130999c12dccSNélio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].cqe64.op_own = 131099c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 131199c12dccSNélio Laranjeiro ++idx; 131299c12dccSNélio Laranjeiro } 131399c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 131499c12dccSNélio Laranjeiro zip->ai = 0; 131599c12dccSNélio Laranjeiro } 131699c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 131799c12dccSNélio Laranjeiro } else { 131899c12dccSNélio Laranjeiro int ret; 131999c12dccSNélio Laranjeiro int8_t op_own; 132099c12dccSNélio Laranjeiro 132199c12dccSNélio Laranjeiro ret = check_cqe64(cqe, cqe_n, rxq->cq_ci); 132299c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 132399c12dccSNélio Laranjeiro return 0; 132499c12dccSNélio Laranjeiro ++rxq->cq_ci; 132599c12dccSNélio Laranjeiro op_own = cqe->op_own; 132699c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 132799c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 132899c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 132999c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 133099c12dccSNélio Laranjeiro cqe_cnt].cqe64); 133199c12dccSNélio Laranjeiro 133299c12dccSNélio Laranjeiro /* Fix endianness. */ 133399c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 133499c12dccSNélio Laranjeiro /* 133599c12dccSNélio Laranjeiro * Current mini array position is the one returned by 133699c12dccSNélio Laranjeiro * check_cqe64(). 133799c12dccSNélio Laranjeiro * 133899c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 133999c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 134099c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 134199c12dccSNélio Laranjeiro */ 134299c12dccSNélio Laranjeiro zip->ca = rxq->cq_ci & cqe_cnt; 134399c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 134499c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 134599c12dccSNélio Laranjeiro --rxq->cq_ci; 134699c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 134799c12dccSNélio Laranjeiro /* Get packet size to return. */ 134899c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 134999c12dccSNélio Laranjeiro zip->ai = 1; 135099c12dccSNélio Laranjeiro } else { 135199c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 135299c12dccSNélio Laranjeiro } 135399c12dccSNélio Laranjeiro /* Error while receiving packet. */ 135499c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 135599c12dccSNélio Laranjeiro return -1; 135699c12dccSNélio Laranjeiro } 135799c12dccSNélio Laranjeiro return len; 135899c12dccSNélio Laranjeiro } 135999c12dccSNélio Laranjeiro 136099c12dccSNélio Laranjeiro /** 136167fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 136267fa62bcSAdrien Mazarguil * 136367fa62bcSAdrien Mazarguil * @param[in] rxq 136467fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 13656218063bSNélio Laranjeiro * @param[in] cqe 13666218063bSNélio Laranjeiro * Pointer to CQE. 136767fa62bcSAdrien Mazarguil * 136867fa62bcSAdrien Mazarguil * @return 136967fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 137067fa62bcSAdrien Mazarguil */ 137167fa62bcSAdrien Mazarguil static inline uint32_t 13726218063bSNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe) 137367fa62bcSAdrien Mazarguil { 137467fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 13756218063bSNélio Laranjeiro uint8_t l3_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L3_HDR_TYPE_MASK; 13766218063bSNélio Laranjeiro uint8_t l4_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L4_HDR_TYPE_MASK; 13776218063bSNélio Laranjeiro uint8_t info = cqe->rsvd0[0]; 137867fa62bcSAdrien Mazarguil 13796218063bSNélio Laranjeiro if ((l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV4) || 13806218063bSNélio Laranjeiro (l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV6)) 138167fa62bcSAdrien Mazarguil ol_flags |= 13826218063bSNélio Laranjeiro (!(cqe->hds_ip_ext & MLX5_CQE_L3_OK) * 1383d0087d76SYaacov Hazan PKT_RX_IP_CKSUM_BAD); 13846218063bSNélio Laranjeiro if ((l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP) || 13856218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_EMP_ACK) || 13866218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_ACK) || 13876218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_UDP)) 1388d0087d76SYaacov Hazan ol_flags |= 13896218063bSNélio Laranjeiro (!(cqe->hds_ip_ext & MLX5_CQE_L4_OK) * 139067fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 139167fa62bcSAdrien Mazarguil /* 139267fa62bcSAdrien Mazarguil * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place 139367fa62bcSAdrien Mazarguil * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional 139467fa62bcSAdrien Mazarguil * (its value is 0). 139567fa62bcSAdrien Mazarguil */ 13966218063bSNélio Laranjeiro if ((info & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 139767fa62bcSAdrien Mazarguil ol_flags |= 13986218063bSNélio Laranjeiro TRANSPOSE(~cqe->l4_hdr_type_etc, 139967fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK, 140067fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 14016218063bSNélio Laranjeiro TRANSPOSE(~cqe->l4_hdr_type_etc, 140267fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK, 140367fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 140467fa62bcSAdrien Mazarguil return ol_flags; 140567fa62bcSAdrien Mazarguil } 140667fa62bcSAdrien Mazarguil 140767fa62bcSAdrien Mazarguil /** 14082e22920bSAdrien Mazarguil * DPDK callback for RX. 14092e22920bSAdrien Mazarguil * 14102e22920bSAdrien Mazarguil * @param dpdk_rxq 14112e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 14122e22920bSAdrien Mazarguil * @param[out] pkts 14132e22920bSAdrien Mazarguil * Array to store received packets. 14142e22920bSAdrien Mazarguil * @param pkts_n 14152e22920bSAdrien Mazarguil * Maximum number of packets in array. 14162e22920bSAdrien Mazarguil * 14172e22920bSAdrien Mazarguil * @return 14182e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 14192e22920bSAdrien Mazarguil */ 14202e22920bSAdrien Mazarguil uint16_t 14212e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 14222e22920bSAdrien Mazarguil { 14236218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 14242e22920bSAdrien Mazarguil unsigned int pkts_ret = 0; 14256218063bSNélio Laranjeiro unsigned int i; 14266218063bSNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci; 14276218063bSNélio Laranjeiro const unsigned int elts_n = rxq->elts_n; 14286218063bSNélio Laranjeiro const unsigned int wqe_cnt = elts_n - 1; 142999c12dccSNélio Laranjeiro const unsigned int cqe_cnt = rxq->cqe_n - 1; 14302e22920bSAdrien Mazarguil 14312e22920bSAdrien Mazarguil for (i = 0; (i != pkts_n); ++i) { 14326218063bSNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 143399c12dccSNélio Laranjeiro int len; 14342e22920bSAdrien Mazarguil struct rte_mbuf *rep; 14356218063bSNélio Laranjeiro struct rte_mbuf *pkt; 14366218063bSNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 14376218063bSNélio Laranjeiro volatile struct mlx5_cqe64 *cqe = 143899c12dccSNélio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64; 14392e22920bSAdrien Mazarguil 14406218063bSNélio Laranjeiro pkt = (*rxq->elts)[idx]; 14416218063bSNélio Laranjeiro rte_prefetch0(cqe); 1442fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 14432e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 144487011737SAdrien Mazarguil ++rxq->stats.rx_nombuf; 14456218063bSNélio Laranjeiro break; 14462e22920bSAdrien Mazarguil } 14476218063bSNélio Laranjeiro SET_DATA_OFF(rep, RTE_PKTMBUF_HEADROOM); 14486218063bSNélio Laranjeiro NB_SEGS(rep) = 1; 14496218063bSNélio Laranjeiro PORT(rep) = rxq->port_id; 14506218063bSNélio Laranjeiro NEXT(rep) = NULL; 145199c12dccSNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt); 14526218063bSNélio Laranjeiro if (unlikely(len == 0)) { 14536218063bSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 14546218063bSNélio Laranjeiro __rte_mbuf_raw_free(rep); 14556218063bSNélio Laranjeiro break; 14566218063bSNélio Laranjeiro } 145799c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 145899c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 145999c12dccSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 146099c12dccSNélio Laranjeiro __rte_mbuf_raw_free(rep); 146199c12dccSNélio Laranjeiro ++rxq->stats.idropped; 146299c12dccSNélio Laranjeiro --i; 146399c12dccSNélio Laranjeiro goto skip; 146499c12dccSNélio Laranjeiro } 14656218063bSNélio Laranjeiro /* 14666218063bSNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 14676218063bSNélio Laranjeiro * of the buffers are already known, only the buffer address 14686218063bSNélio Laranjeiro * changes. 14696218063bSNélio Laranjeiro */ 14706218063bSNélio Laranjeiro wqe->addr = htonll((uintptr_t)rep->buf_addr + 14716218063bSNélio Laranjeiro RTE_PKTMBUF_HEADROOM); 14726218063bSNélio Laranjeiro (*rxq->elts)[idx] = rep; 14736218063bSNélio Laranjeiro /* Update pkt information. */ 14746218063bSNélio Laranjeiro if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip | 14756218063bSNélio Laranjeiro rxq->crc_present) { 14766218063bSNélio Laranjeiro if (rxq->csum) { 14776218063bSNélio Laranjeiro pkt->packet_type = rxq_cq_to_pkt_type(cqe); 14786218063bSNélio Laranjeiro pkt->ol_flags = rxq_cq_to_ol_flags(rxq, cqe); 14796218063bSNélio Laranjeiro } 14806218063bSNélio Laranjeiro if (cqe->l4_hdr_type_etc & MLX5_CQE_VLAN_STRIPPED) { 14816218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1482b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 14836218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 1484f3db9489SYaacov Hazan } 14856218063bSNélio Laranjeiro if (rxq->crc_present) 14866218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 1487081f7eaeSNelio Laranjeiro } 14886218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 14896218063bSNélio Laranjeiro DATA_LEN(pkt) = len; 149087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 149187011737SAdrien Mazarguil /* Increment bytes counter. */ 149287011737SAdrien Mazarguil rxq->stats.ibytes += len; 149387011737SAdrien Mazarguil #endif 14946218063bSNélio Laranjeiro /* Return packet. */ 14956218063bSNélio Laranjeiro *(pkts++) = pkt; 14966218063bSNélio Laranjeiro ++pkts_ret; 149799c12dccSNélio Laranjeiro skip: 14986218063bSNélio Laranjeiro ++rq_ci; 14992e22920bSAdrien Mazarguil } 15006218063bSNélio Laranjeiro if (unlikely((i == 0) && (rq_ci == rxq->rq_ci))) 15012e22920bSAdrien Mazarguil return 0; 15022e22920bSAdrien Mazarguil /* Repost WRs. */ 15032e22920bSAdrien Mazarguil #ifdef DEBUG_RECV 15042e22920bSAdrien Mazarguil DEBUG("%p: reposting %u WRs", (void *)rxq, i); 15052e22920bSAdrien Mazarguil #endif 15066218063bSNélio Laranjeiro /* Update the consumer index. */ 15076218063bSNélio Laranjeiro rxq->rq_ci = rq_ci; 15086218063bSNélio Laranjeiro rte_wmb(); 15096218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 15106218063bSNélio Laranjeiro rte_wmb(); 15116218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 151287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 151387011737SAdrien Mazarguil /* Increment packets counter. */ 151487011737SAdrien Mazarguil rxq->stats.ipackets += pkts_ret; 151587011737SAdrien Mazarguil #endif 15162e22920bSAdrien Mazarguil return pkts_ret; 15172e22920bSAdrien Mazarguil } 15182e22920bSAdrien Mazarguil 15192e22920bSAdrien Mazarguil /** 15202e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 15212e22920bSAdrien Mazarguil * 15222e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 15232e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 15242e22920bSAdrien Mazarguil * 15252e22920bSAdrien Mazarguil * @param dpdk_txq 15262e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 15272e22920bSAdrien Mazarguil * @param[in] pkts 15282e22920bSAdrien Mazarguil * Packets to transmit. 15292e22920bSAdrien Mazarguil * @param pkts_n 15302e22920bSAdrien Mazarguil * Number of packets in array. 15312e22920bSAdrien Mazarguil * 15322e22920bSAdrien Mazarguil * @return 15332e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 15342e22920bSAdrien Mazarguil */ 15352e22920bSAdrien Mazarguil uint16_t 15362e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 15372e22920bSAdrien Mazarguil { 15382e22920bSAdrien Mazarguil (void)dpdk_txq; 15392e22920bSAdrien Mazarguil (void)pkts; 15402e22920bSAdrien Mazarguil (void)pkts_n; 15412e22920bSAdrien Mazarguil return 0; 15422e22920bSAdrien Mazarguil } 15432e22920bSAdrien Mazarguil 15442e22920bSAdrien Mazarguil /** 15452e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 15462e22920bSAdrien Mazarguil * 15472e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 15482e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 15492e22920bSAdrien Mazarguil * 15502e22920bSAdrien Mazarguil * @param dpdk_rxq 15512e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 15522e22920bSAdrien Mazarguil * @param[out] pkts 15532e22920bSAdrien Mazarguil * Array to store received packets. 15542e22920bSAdrien Mazarguil * @param pkts_n 15552e22920bSAdrien Mazarguil * Maximum number of packets in array. 15562e22920bSAdrien Mazarguil * 15572e22920bSAdrien Mazarguil * @return 15582e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 15592e22920bSAdrien Mazarguil */ 15602e22920bSAdrien Mazarguil uint16_t 15612e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 15622e22920bSAdrien Mazarguil { 15632e22920bSAdrien Mazarguil (void)dpdk_rxq; 15642e22920bSAdrien Mazarguil (void)pkts; 15652e22920bSAdrien Mazarguil (void)pkts_n; 15662e22920bSAdrien Mazarguil return 0; 15672e22920bSAdrien Mazarguil } 1568