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; 241f04f1d51SNélio Laranjeiro txq->wqe_pi = ntohs(cqe->wqe_counter); 242fdcb0f53SNélio Laranjeiro ctrl = (volatile struct mlx5_wqe_ctrl *) 243f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_pi); 244fdcb0f53SNélio Laranjeiro elts_tail = ctrl->ctrl3; 245a821d09dSNélio Laranjeiro assert(elts_tail < (1 << txq->wqe_n)); 2461d88ba17SNélio Laranjeiro /* Free buffers. */ 247c305090bSAdrien Mazarguil while (elts_free != elts_tail) { 2481d88ba17SNélio Laranjeiro struct rte_mbuf *elt = (*txq->elts)[elts_free]; 249a859e8a9SNelio Laranjeiro unsigned int elts_free_next = 2501d88ba17SNélio Laranjeiro (elts_free + 1) & (elts_n - 1); 2511d88ba17SNélio Laranjeiro struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next]; 252a859e8a9SNelio Laranjeiro 253b185e63fSAdrien Mazarguil #ifndef NDEBUG 254b185e63fSAdrien Mazarguil /* Poisoning. */ 2551d88ba17SNélio Laranjeiro memset(&(*txq->elts)[elts_free], 2561d88ba17SNélio Laranjeiro 0x66, 2571d88ba17SNélio Laranjeiro sizeof((*txq->elts)[elts_free])); 258b185e63fSAdrien Mazarguil #endif 2591d88ba17SNélio Laranjeiro RTE_MBUF_PREFETCH_TO_FREE(elt_next); 2601d88ba17SNélio Laranjeiro /* Only one segment needs to be freed. */ 2611d88ba17SNélio Laranjeiro rte_pktmbuf_free_seg(elt); 262a859e8a9SNelio Laranjeiro elts_free = elts_free_next; 263c305090bSAdrien Mazarguil } 2641d88ba17SNélio Laranjeiro txq->cq_ci = cq_ci; 2652e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 2661d88ba17SNélio Laranjeiro /* Update the consumer index. */ 2671d88ba17SNélio Laranjeiro rte_wmb(); 2681d88ba17SNélio Laranjeiro *txq->cq_db = htonl(cq_ci); 2692e22920bSAdrien Mazarguil } 2702e22920bSAdrien Mazarguil 2712e22920bSAdrien Mazarguil /** 2728340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 2738340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 2748340392eSAdrien Mazarguil * 2758340392eSAdrien Mazarguil * @param buf 2768340392eSAdrien Mazarguil * Pointer to mbuf. 2778340392eSAdrien Mazarguil * 2788340392eSAdrien Mazarguil * @return 2798340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 2808340392eSAdrien Mazarguil */ 2818340392eSAdrien Mazarguil static struct rte_mempool * 2828340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 2838340392eSAdrien Mazarguil { 2848340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 2858340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 2868340392eSAdrien Mazarguil return buf->pool; 2878340392eSAdrien Mazarguil } 2888340392eSAdrien Mazarguil 2898340392eSAdrien Mazarguil /** 2902e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 2912e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 2922e22920bSAdrien Mazarguil * remove an entry first. 2932e22920bSAdrien Mazarguil * 2942e22920bSAdrien Mazarguil * @param txq 2952e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2962e22920bSAdrien Mazarguil * @param[in] mp 2972e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 2982e22920bSAdrien Mazarguil * 2992e22920bSAdrien Mazarguil * @return 3002e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 3012e22920bSAdrien Mazarguil */ 302491770faSNélio Laranjeiro static inline uint32_t 303d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 3042e22920bSAdrien Mazarguil { 3052e22920bSAdrien Mazarguil unsigned int i; 306491770faSNélio Laranjeiro uint32_t lkey = (uint32_t)-1; 3072e22920bSAdrien Mazarguil 3082e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 3092e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 3102e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 3112e22920bSAdrien Mazarguil break; 3122e22920bSAdrien Mazarguil } 3132e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 3142e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 3151d88ba17SNélio Laranjeiro assert(htonl(txq->mp2mr[i].mr->lkey) == 3161d88ba17SNélio Laranjeiro txq->mp2mr[i].lkey); 317491770faSNélio Laranjeiro lkey = txq->mp2mr[i].lkey; 318491770faSNélio Laranjeiro break; 3192e22920bSAdrien Mazarguil } 3202e22920bSAdrien Mazarguil } 321491770faSNélio Laranjeiro if (unlikely(lkey == (uint32_t)-1)) 322491770faSNélio Laranjeiro lkey = txq_mp2mr_reg(txq, mp, i); 323491770faSNélio Laranjeiro return lkey; 3240a3b350dSOlga Shern } 3250a3b350dSOlga Shern 326e192ef80SYaacov Hazan /** 3271d88ba17SNélio Laranjeiro * Ring TX queue doorbell. 3281d88ba17SNélio Laranjeiro * 3291d88ba17SNélio Laranjeiro * @param txq 3301d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 33130807f62SNélio Laranjeiro * @param wqe 33230807f62SNélio Laranjeiro * Pointer to the last WQE posted in the NIC. 3331d88ba17SNélio Laranjeiro */ 3341d88ba17SNélio Laranjeiro static inline void 33530807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe) 3361d88ba17SNélio Laranjeiro { 33730807f62SNélio Laranjeiro uint64_t *dst = (uint64_t *)((uintptr_t)txq->bf_reg); 33830807f62SNélio Laranjeiro volatile uint64_t *src = ((volatile uint64_t *)wqe); 33930807f62SNélio Laranjeiro 3401d88ba17SNélio Laranjeiro rte_wmb(); 3411d88ba17SNélio Laranjeiro *txq->qp_db = htonl(txq->wqe_ci); 3421d88ba17SNélio Laranjeiro /* Ensure ordering between DB record and BF copy. */ 3431d88ba17SNélio Laranjeiro rte_wmb(); 34430807f62SNélio Laranjeiro *dst = *src; 3451d88ba17SNélio Laranjeiro } 346e192ef80SYaacov Hazan 3471d88ba17SNélio Laranjeiro /** 3488788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 3498788fec1SOlivier Matz * 3508788fec1SOlivier Matz * @param tx_queue 3518788fec1SOlivier Matz * The tx queue. 3528788fec1SOlivier Matz * @param[in] offset 3538788fec1SOlivier Matz * The index of the descriptor in the ring. 3548788fec1SOlivier Matz * 3558788fec1SOlivier Matz * @return 3568788fec1SOlivier Matz * The status of the tx descriptor. 3578788fec1SOlivier Matz */ 3588788fec1SOlivier Matz int 3598788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 3608788fec1SOlivier Matz { 3618788fec1SOlivier Matz struct txq *txq = tx_queue; 3628788fec1SOlivier Matz const unsigned int elts_n = 1 << txq->elts_n; 3638788fec1SOlivier Matz const unsigned int elts_cnt = elts_n - 1; 3648788fec1SOlivier Matz unsigned int used; 3658788fec1SOlivier Matz 3668788fec1SOlivier Matz txq_complete(txq); 3678788fec1SOlivier Matz used = (txq->elts_head - txq->elts_tail) & elts_cnt; 3688788fec1SOlivier Matz if (offset < used) 3698788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 3708788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 3718788fec1SOlivier Matz } 3728788fec1SOlivier Matz 3738788fec1SOlivier Matz /** 3748788fec1SOlivier Matz * DPDK callback to check the status of a rx descriptor. 3758788fec1SOlivier Matz * 3768788fec1SOlivier Matz * @param rx_queue 3778788fec1SOlivier Matz * The rx queue. 3788788fec1SOlivier Matz * @param[in] offset 3798788fec1SOlivier Matz * The index of the descriptor in the ring. 3808788fec1SOlivier Matz * 3818788fec1SOlivier Matz * @return 3828788fec1SOlivier Matz * The status of the tx descriptor. 3838788fec1SOlivier Matz */ 3848788fec1SOlivier Matz int 3858788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 3868788fec1SOlivier Matz { 3878788fec1SOlivier Matz struct rxq *rxq = rx_queue; 3888788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 3898788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 3908788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 3918788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 3928788fec1SOlivier Matz unsigned int cq_ci; 3938788fec1SOlivier Matz unsigned int used; 3948788fec1SOlivier Matz 3958788fec1SOlivier Matz /* if we are processing a compressed cqe */ 3968788fec1SOlivier Matz if (zip->ai) { 3978788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 3988788fec1SOlivier Matz cq_ci = zip->cq_ci; 3998788fec1SOlivier Matz } else { 4008788fec1SOlivier Matz used = 0; 4018788fec1SOlivier Matz cq_ci = rxq->cq_ci; 4028788fec1SOlivier Matz } 4038788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4048788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 4058788fec1SOlivier Matz int8_t op_own; 4068788fec1SOlivier Matz unsigned int n; 4078788fec1SOlivier Matz 4088788fec1SOlivier Matz op_own = cqe->op_own; 4098788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 4108788fec1SOlivier Matz n = ntohl(cqe->byte_cnt); 4118788fec1SOlivier Matz else 4128788fec1SOlivier Matz n = 1; 4138788fec1SOlivier Matz cq_ci += n; 4148788fec1SOlivier Matz used += n; 4158788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4168788fec1SOlivier Matz } 4178788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 4188788fec1SOlivier Matz if (offset < used) 4198788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 4208788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 4218788fec1SOlivier Matz } 4228788fec1SOlivier Matz 4238788fec1SOlivier Matz /** 4242e22920bSAdrien Mazarguil * DPDK callback for TX. 4252e22920bSAdrien Mazarguil * 4262e22920bSAdrien Mazarguil * @param dpdk_txq 4272e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 4282e22920bSAdrien Mazarguil * @param[in] pkts 4292e22920bSAdrien Mazarguil * Packets to transmit. 4302e22920bSAdrien Mazarguil * @param pkts_n 4312e22920bSAdrien Mazarguil * Number of packets in array. 4322e22920bSAdrien Mazarguil * 4332e22920bSAdrien Mazarguil * @return 4342e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 4352e22920bSAdrien Mazarguil */ 4362e22920bSAdrien Mazarguil uint16_t 4372e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 4382e22920bSAdrien Mazarguil { 4392e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 4401d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 441b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 442c3d62cc9SAdrien Mazarguil unsigned int i = 0; 443a5bf6af9SAdrien Mazarguil unsigned int j = 0; 444*3f13f8c2SShahaf Shuler unsigned int k = 0; 4452e22920bSAdrien Mazarguil unsigned int max; 446f04f1d51SNélio Laranjeiro uint16_t max_wqe; 447c305090bSAdrien Mazarguil unsigned int comp; 4489a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 4496579c27cSNélio Laranjeiro unsigned int segs_n = 0; 4506579c27cSNélio Laranjeiro struct rte_mbuf *buf = NULL; 4516579c27cSNélio Laranjeiro uint8_t *raw; 4522e22920bSAdrien Mazarguil 4531d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 4541d88ba17SNélio Laranjeiro return 0; 4555e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 456c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 4571d88ba17SNélio Laranjeiro /* Start processing. */ 4582e22920bSAdrien Mazarguil txq_complete(txq); 4594f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 4602e22920bSAdrien Mazarguil if (max > elts_n) 4612e22920bSAdrien Mazarguil max -= elts_n; 462f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 463f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 464f04f1d51SNélio Laranjeiro return 0; 465c3d62cc9SAdrien Mazarguil do { 4669a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 467573f54afSNélio Laranjeiro uint32_t length; 4688688b2f8SNélio Laranjeiro unsigned int ds = 0; 4696579c27cSNélio Laranjeiro uintptr_t addr; 4709a7fa9f7SNélio Laranjeiro uint64_t naddr; 4710d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 472*3f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 473eef822ddSNélio Laranjeiro uint16_t ehdr; 4749a7fa9f7SNélio Laranjeiro uint8_t cs_flags = 0; 475*3f13f8c2SShahaf Shuler uint64_t tso = 0; 4766579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 4776579c27cSNélio Laranjeiro uint32_t total_length = 0; 4786579c27cSNélio Laranjeiro #endif 4792e22920bSAdrien Mazarguil 4806579c27cSNélio Laranjeiro /* first_seg */ 4816579c27cSNélio Laranjeiro buf = *(pkts++); 4826579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 483c3d62cc9SAdrien Mazarguil /* 484c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 485c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 486c3d62cc9SAdrien Mazarguil */ 487a5bf6af9SAdrien Mazarguil assert(segs_n); 488a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 489c3d62cc9SAdrien Mazarguil break; 490a5bf6af9SAdrien Mazarguil max -= segs_n; 4916579c27cSNélio Laranjeiro --segs_n; 4926579c27cSNélio Laranjeiro if (!segs_n) 493c3d62cc9SAdrien Mazarguil --pkts_n; 494f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 495f04f1d51SNélio Laranjeiro break; 4969a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 497fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 498fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 4996579c27cSNélio Laranjeiro if (pkts_n > 1) 500c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 5016579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 5022e22920bSAdrien Mazarguil length = DATA_LEN(buf); 503eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 504eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 5056579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 5066579c27cSNélio Laranjeiro total_length = length; 5076579c27cSNélio Laranjeiro #endif 5086579c27cSNélio Laranjeiro assert(length >= MLX5_WQE_DWORD_SIZE); 5092e22920bSAdrien Mazarguil /* Update element. */ 5101d88ba17SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 5116579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 5125e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 5136579c27cSNélio Laranjeiro if (pkts_n > 1) { 5146579c27cSNélio Laranjeiro volatile void *pkt_addr; 5156579c27cSNélio Laranjeiro 5166579c27cSNélio Laranjeiro pkt_addr = rte_pktmbuf_mtod(*pkts, volatile void *); 5176579c27cSNélio Laranjeiro rte_prefetch0(pkt_addr); 5186579c27cSNélio Laranjeiro } 5191d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 5201d88ba17SNélio Laranjeiro if (buf->ol_flags & 5211d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 5229a7fa9f7SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 5231d88ba17SNélio Laranjeiro } 524b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 5256579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 5266579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 5276579c27cSNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | buf->vlan_tci); 5280d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 5296579c27cSNélio Laranjeiro 5300d637a34SNélio Laranjeiro addr += 2; 5310d637a34SNélio Laranjeiro length -= 2; 5320d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 5330d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 5340d637a34SNélio Laranjeiro /* Copy VLAN. */ 5350d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 5360d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 5370d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 5380d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 5390d637a34SNélio Laranjeiro addr += len + 2; 5400d637a34SNélio Laranjeiro length -= (len + 2); 5410d637a34SNélio Laranjeiro } else { 5420d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 5430d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 5440d637a34SNélio Laranjeiro length -= pkt_inline_sz; 5450d637a34SNélio Laranjeiro addr += pkt_inline_sz; 5466579c27cSNélio Laranjeiro } 547*3f13f8c2SShahaf Shuler if (txq->tso_en) { 548*3f13f8c2SShahaf Shuler tso = buf->ol_flags & PKT_TX_TCP_SEG; 549*3f13f8c2SShahaf Shuler if (tso) { 550*3f13f8c2SShahaf Shuler uintptr_t end = (uintptr_t) 551*3f13f8c2SShahaf Shuler (((uintptr_t)txq->wqes) + 552*3f13f8c2SShahaf Shuler (1 << txq->wqe_n) * 553*3f13f8c2SShahaf Shuler MLX5_WQE_SIZE); 554*3f13f8c2SShahaf Shuler unsigned int copy_b; 555*3f13f8c2SShahaf Shuler uint8_t vlan_sz = (buf->ol_flags & 556*3f13f8c2SShahaf Shuler PKT_TX_VLAN_PKT) ? 4 : 0; 557*3f13f8c2SShahaf Shuler 558*3f13f8c2SShahaf Shuler tso_header_sz = buf->l2_len + vlan_sz + 559*3f13f8c2SShahaf Shuler buf->l3_len + buf->l4_len; 560*3f13f8c2SShahaf Shuler 561*3f13f8c2SShahaf Shuler if (unlikely(tso_header_sz > 562*3f13f8c2SShahaf Shuler MLX5_MAX_TSO_HEADER)) 563*3f13f8c2SShahaf Shuler break; 564*3f13f8c2SShahaf Shuler copy_b = tso_header_sz - pkt_inline_sz; 565*3f13f8c2SShahaf Shuler /* First seg must contain all headers. */ 566*3f13f8c2SShahaf Shuler assert(copy_b <= length); 567*3f13f8c2SShahaf Shuler raw += MLX5_WQE_DWORD_SIZE; 568*3f13f8c2SShahaf Shuler if (copy_b && 569*3f13f8c2SShahaf Shuler ((end - (uintptr_t)raw) > copy_b)) { 570*3f13f8c2SShahaf Shuler uint16_t n = (MLX5_WQE_DS(copy_b) - 571*3f13f8c2SShahaf Shuler 1 + 3) / 4; 572*3f13f8c2SShahaf Shuler 573*3f13f8c2SShahaf Shuler if (unlikely(max_wqe < n)) 574*3f13f8c2SShahaf Shuler break; 575*3f13f8c2SShahaf Shuler max_wqe -= n; 576*3f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 577*3f13f8c2SShahaf Shuler (void *)addr, copy_b); 578*3f13f8c2SShahaf Shuler addr += copy_b; 579*3f13f8c2SShahaf Shuler length -= copy_b; 580*3f13f8c2SShahaf Shuler pkt_inline_sz += copy_b; 581*3f13f8c2SShahaf Shuler /* 582*3f13f8c2SShahaf Shuler * Another DWORD will be added 583*3f13f8c2SShahaf Shuler * in the inline part. 584*3f13f8c2SShahaf Shuler */ 585*3f13f8c2SShahaf Shuler raw += MLX5_WQE_DS(copy_b) * 586*3f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE - 587*3f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 588*3f13f8c2SShahaf Shuler } else { 589*3f13f8c2SShahaf Shuler /* NOP WQE. */ 590*3f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 591*3f13f8c2SShahaf Shuler htonl(txq->wqe_ci << 8), 592*3f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | 1), 593*3f13f8c2SShahaf Shuler 0, 594*3f13f8c2SShahaf Shuler 0, 595*3f13f8c2SShahaf Shuler }; 596*3f13f8c2SShahaf Shuler ds = 1; 597*3f13f8c2SShahaf Shuler total_length = 0; 598*3f13f8c2SShahaf Shuler pkts--; 599*3f13f8c2SShahaf Shuler pkts_n++; 600*3f13f8c2SShahaf Shuler elts_head = (elts_head - 1) & 601*3f13f8c2SShahaf Shuler (elts_n - 1); 602*3f13f8c2SShahaf Shuler k++; 603*3f13f8c2SShahaf Shuler goto next_wqe; 604*3f13f8c2SShahaf Shuler } 605*3f13f8c2SShahaf Shuler } 606*3f13f8c2SShahaf Shuler } 6076579c27cSNélio Laranjeiro /* Inline if enough room. */ 608*3f13f8c2SShahaf Shuler if (txq->inline_en || tso) { 609fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 610fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 611fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 6128fcd6c2cSNélio Laranjeiro unsigned int max_inline = txq->max_inline * 6138fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 614*3f13f8c2SShahaf Shuler (pkt_inline_sz - 2); 6156579c27cSNélio Laranjeiro uintptr_t addr_end = (addr + max_inline) & 6166579c27cSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 6178fcd6c2cSNélio Laranjeiro unsigned int copy_b = (addr_end > addr) ? 6188fcd6c2cSNélio Laranjeiro RTE_MIN((addr_end - addr), length) : 6198fcd6c2cSNélio Laranjeiro 0; 6206579c27cSNélio Laranjeiro 6218fcd6c2cSNélio Laranjeiro raw += MLX5_WQE_DWORD_SIZE; 6228fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 623f04f1d51SNélio Laranjeiro /* 624f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 625f04f1d51SNélio Laranjeiro * keep the computation positive, it is 626f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 627f04f1d51SNélio Laranjeiro */ 6288fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 6298fcd6c2cSNélio Laranjeiro 630f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 631f04f1d51SNélio Laranjeiro break; 632f04f1d51SNélio Laranjeiro max_wqe -= n; 633*3f13f8c2SShahaf Shuler if (tso) { 634*3f13f8c2SShahaf Shuler uint32_t inl = 635*3f13f8c2SShahaf Shuler htonl(copy_b | MLX5_INLINE_SEG); 636*3f13f8c2SShahaf Shuler 637*3f13f8c2SShahaf Shuler pkt_inline_sz = 638*3f13f8c2SShahaf Shuler MLX5_WQE_DS(tso_header_sz) * 639*3f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 640*3f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 641*3f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 642*3f13f8c2SShahaf Shuler raw += sizeof(inl); 643*3f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 644*3f13f8c2SShahaf Shuler } 6456579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 6466579c27cSNélio Laranjeiro addr += copy_b; 6476579c27cSNélio Laranjeiro length -= copy_b; 6486579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 6496579c27cSNélio Laranjeiro } 6506579c27cSNélio Laranjeiro /* 651786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 6526579c27cSNélio Laranjeiro * the size of the inline part of the packet. 6536579c27cSNélio Laranjeiro */ 6546579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 6556579c27cSNélio Laranjeiro if (length > 0) { 656f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 657f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 658f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 659f04f1d51SNélio Laranjeiro break; 660f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 661f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 662f04f1d51SNélio Laranjeiro ds / 4); 663f04f1d51SNélio Laranjeiro } else { 6649a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 6656579c27cSNélio Laranjeiro ((uintptr_t)wqe + 6666579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 667f04f1d51SNélio Laranjeiro } 6686579c27cSNélio Laranjeiro goto use_dseg; 6696579c27cSNélio Laranjeiro } else if (!segs_n) { 6706579c27cSNélio Laranjeiro goto next_pkt; 6716579c27cSNélio Laranjeiro } else { 672786b5c2dSShahaf Shuler /* dseg will be advance as part of next_seg */ 673786b5c2dSShahaf Shuler dseg = (volatile rte_v128u32_t *) 674786b5c2dSShahaf Shuler ((uintptr_t)wqe + 675786b5c2dSShahaf Shuler ((ds - 1) * MLX5_WQE_DWORD_SIZE)); 6766579c27cSNélio Laranjeiro goto next_seg; 6776579c27cSNélio Laranjeiro } 6786579c27cSNélio Laranjeiro } else { 6796579c27cSNélio Laranjeiro /* 6806579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 6816579c27cSNélio Laranjeiro * Ethernet Header as been stored. 6826579c27cSNélio Laranjeiro */ 6839a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 6846579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 6856579c27cSNélio Laranjeiro ds = 3; 6866579c27cSNélio Laranjeiro use_dseg: 6876579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 6889a7fa9f7SNélio Laranjeiro naddr = htonll(addr); 6899a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6909a7fa9f7SNélio Laranjeiro htonl(length), 6919a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 6929a7fa9f7SNélio Laranjeiro naddr, 6939a7fa9f7SNélio Laranjeiro naddr >> 32, 6946579c27cSNélio Laranjeiro }; 6956579c27cSNélio Laranjeiro ++ds; 6966579c27cSNélio Laranjeiro if (!segs_n) 6976579c27cSNélio Laranjeiro goto next_pkt; 6986579c27cSNélio Laranjeiro } 6996579c27cSNélio Laranjeiro next_seg: 7006579c27cSNélio Laranjeiro assert(buf); 7016579c27cSNélio Laranjeiro assert(ds); 7026579c27cSNélio Laranjeiro assert(wqe); 703a5bf6af9SAdrien Mazarguil /* 704a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 705a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 706a5bf6af9SAdrien Mazarguil * of data segment size. 707a5bf6af9SAdrien Mazarguil */ 7088688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 7096579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 710f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 711f04f1d51SNélio Laranjeiro break; 7129a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 713f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 714f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 715f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 7166579c27cSNélio Laranjeiro } else { 717a5bf6af9SAdrien Mazarguil ++dseg; 7186579c27cSNélio Laranjeiro } 719a5bf6af9SAdrien Mazarguil ++ds; 720a5bf6af9SAdrien Mazarguil buf = buf->next; 721a5bf6af9SAdrien Mazarguil assert(buf); 7226579c27cSNélio Laranjeiro length = DATA_LEN(buf); 723a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 7246579c27cSNélio Laranjeiro total_length += length; 725a5bf6af9SAdrien Mazarguil #endif 7266579c27cSNélio Laranjeiro /* Store segment information. */ 7279a7fa9f7SNélio Laranjeiro naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)); 7289a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 7299a7fa9f7SNélio Laranjeiro htonl(length), 7309a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 7319a7fa9f7SNélio Laranjeiro naddr, 7329a7fa9f7SNélio Laranjeiro naddr >> 32, 7336579c27cSNélio Laranjeiro }; 7346579c27cSNélio Laranjeiro (*txq->elts)[elts_head] = buf; 7356579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 736a5bf6af9SAdrien Mazarguil ++j; 7376579c27cSNélio Laranjeiro --segs_n; 7386579c27cSNélio Laranjeiro if (segs_n) 7396579c27cSNélio Laranjeiro goto next_seg; 7406579c27cSNélio Laranjeiro else 7416579c27cSNélio Laranjeiro --pkts_n; 7426579c27cSNélio Laranjeiro next_pkt: 7436579c27cSNélio Laranjeiro ++i; 744b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 745*3f13f8c2SShahaf Shuler if (tso) { 746*3f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 747*3f13f8c2SShahaf Shuler htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO), 748*3f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | ds), 749*3f13f8c2SShahaf Shuler 0, 750*3f13f8c2SShahaf Shuler 0, 751*3f13f8c2SShahaf Shuler }; 752*3f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 753*3f13f8c2SShahaf Shuler 0, 754*3f13f8c2SShahaf Shuler cs_flags | (htons(buf->tso_segsz) << 16), 755*3f13f8c2SShahaf Shuler 0, 756*3f13f8c2SShahaf Shuler (ehdr << 16) | htons(tso_header_sz), 757*3f13f8c2SShahaf Shuler }; 758*3f13f8c2SShahaf Shuler } else { 7599a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 7609a7fa9f7SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 7619a7fa9f7SNélio Laranjeiro htonl(txq->qp_num_8s | ds), 7629a7fa9f7SNélio Laranjeiro 0, 7639a7fa9f7SNélio Laranjeiro 0, 7649a7fa9f7SNélio Laranjeiro }; 7659a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 7669a7fa9f7SNélio Laranjeiro 0, 7679a7fa9f7SNélio Laranjeiro cs_flags, 7689a7fa9f7SNélio Laranjeiro 0, 769eef822ddSNélio Laranjeiro (ehdr << 16) | htons(pkt_inline_sz), 7709a7fa9f7SNélio Laranjeiro }; 771*3f13f8c2SShahaf Shuler } 772*3f13f8c2SShahaf Shuler next_wqe: 7736579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 77487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 775573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 7766579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 77787011737SAdrien Mazarguil #endif 778c3d62cc9SAdrien Mazarguil } while (pkts_n); 7792e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 780*3f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 7812e22920bSAdrien Mazarguil return 0; 782c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 783*3f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 784c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 7859a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_ctrl *w = 7869a7fa9f7SNélio Laranjeiro (volatile struct mlx5_wqe_ctrl *)wqe; 7879a7fa9f7SNélio Laranjeiro 788c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 7899a7fa9f7SNélio Laranjeiro w->ctrl2 = htonl(8); 790c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 7919a7fa9f7SNélio Laranjeiro w->ctrl3 = elts_head; 792c305090bSAdrien Mazarguil txq->elts_comp = 0; 793c305090bSAdrien Mazarguil } else { 794c305090bSAdrien Mazarguil txq->elts_comp = comp; 795c305090bSAdrien Mazarguil } 79687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 79787011737SAdrien Mazarguil /* Increment sent packets counter. */ 79887011737SAdrien Mazarguil txq->stats.opackets += i; 79987011737SAdrien Mazarguil #endif 8002e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 80130807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)wqe); 8022e22920bSAdrien Mazarguil txq->elts_head = elts_head; 8032e22920bSAdrien Mazarguil return i; 8042e22920bSAdrien Mazarguil } 8052e22920bSAdrien Mazarguil 8062e22920bSAdrien Mazarguil /** 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 { 819a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << 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 (*)[]) 822fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 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; 828fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 8298688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 8308688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 8318688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 8328688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 8338688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 8348688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 835c904ae25SNélio Laranjeiro (txq->wqe_ci << 8) | MLX5_OPCODE_TSO); 8368688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 8378688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 8388688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 8398688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 8408688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 8418688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 842230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 843230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 844230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 845230189d9SNélio Laranjeiro } 846230189d9SNélio Laranjeiro 847230189d9SNélio Laranjeiro /** 848230189d9SNélio Laranjeiro * Close a MPW session. 849230189d9SNélio Laranjeiro * 850230189d9SNélio Laranjeiro * @param txq 851230189d9SNélio Laranjeiro * Pointer to TX queue structure. 852230189d9SNélio Laranjeiro * @param mpw 853230189d9SNélio Laranjeiro * Pointer to MPW session structure. 854230189d9SNélio Laranjeiro */ 855230189d9SNélio Laranjeiro static inline void 856230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 857230189d9SNélio Laranjeiro { 858230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 859230189d9SNélio Laranjeiro 860230189d9SNélio Laranjeiro /* 861230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 862230189d9SNélio Laranjeiro * count as 2. 863230189d9SNélio Laranjeiro */ 8648688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num)); 865230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 866230189d9SNélio Laranjeiro if (num < 3) 867230189d9SNélio Laranjeiro ++txq->wqe_ci; 868230189d9SNélio Laranjeiro else 869230189d9SNélio Laranjeiro txq->wqe_ci += 2; 870fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 871fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 872230189d9SNélio Laranjeiro } 873230189d9SNélio Laranjeiro 874230189d9SNélio Laranjeiro /** 875230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 876230189d9SNélio Laranjeiro * 877230189d9SNélio Laranjeiro * @param dpdk_txq 878230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 879230189d9SNélio Laranjeiro * @param[in] pkts 880230189d9SNélio Laranjeiro * Packets to transmit. 881230189d9SNélio Laranjeiro * @param pkts_n 882230189d9SNélio Laranjeiro * Number of packets in array. 883230189d9SNélio Laranjeiro * 884230189d9SNélio Laranjeiro * @return 885230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 886230189d9SNélio Laranjeiro */ 887230189d9SNélio Laranjeiro uint16_t 888230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 889230189d9SNélio Laranjeiro { 890230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 891230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 892b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 893c3d62cc9SAdrien Mazarguil unsigned int i = 0; 894a5bf6af9SAdrien Mazarguil unsigned int j = 0; 895230189d9SNélio Laranjeiro unsigned int max; 896f04f1d51SNélio Laranjeiro uint16_t max_wqe; 897230189d9SNélio Laranjeiro unsigned int comp; 898230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 899230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 900230189d9SNélio Laranjeiro }; 901230189d9SNélio Laranjeiro 902c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 903c3d62cc9SAdrien Mazarguil return 0; 904230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 905fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 906fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 907230189d9SNélio Laranjeiro /* Start processing. */ 908230189d9SNélio Laranjeiro txq_complete(txq); 909230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 910230189d9SNélio Laranjeiro if (max > elts_n) 911230189d9SNélio Laranjeiro max -= elts_n; 912f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 913f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 914f04f1d51SNélio Laranjeiro return 0; 915c3d62cc9SAdrien Mazarguil do { 916a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 917c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 918230189d9SNélio Laranjeiro uint32_t length; 919a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 920230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 921230189d9SNélio Laranjeiro 922c3d62cc9SAdrien Mazarguil /* 923c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 924c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 925c3d62cc9SAdrien Mazarguil */ 926a5bf6af9SAdrien Mazarguil assert(segs_n); 927a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 928c3d62cc9SAdrien Mazarguil break; 929a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 930a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 931a5bf6af9SAdrien Mazarguil break; 932a5bf6af9SAdrien Mazarguil max -= segs_n; 933c3d62cc9SAdrien Mazarguil --pkts_n; 934230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 935230189d9SNélio Laranjeiro if (buf->ol_flags & 936230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 937230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 938a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 939a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 940a5bf6af9SAdrien Mazarguil assert(length); 941230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 942230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 943230189d9SNélio Laranjeiro ((mpw.len != length) || 944a5bf6af9SAdrien Mazarguil (segs_n != 1) || 9458688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 946230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 947230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 948f04f1d51SNélio Laranjeiro /* 949f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 950f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 951f04f1d51SNélio Laranjeiro * resources. 952f04f1d51SNélio Laranjeiro */ 953f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 954f04f1d51SNélio Laranjeiro break; 955f04f1d51SNélio Laranjeiro max_wqe -= 2; 956230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 9578688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 958230189d9SNélio Laranjeiro } 959a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 960a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 961a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 962a5bf6af9SAdrien Mazarguil length = 0; 963a5bf6af9SAdrien Mazarguil #endif 964a5bf6af9SAdrien Mazarguil do { 965a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 966a5bf6af9SAdrien Mazarguil uintptr_t addr; 967a5bf6af9SAdrien Mazarguil 968a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 969a5bf6af9SAdrien Mazarguil assert(buf); 970a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 971230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 972a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 973230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 974a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 975230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 976230189d9SNélio Laranjeiro .addr = htonll(addr), 977230189d9SNélio Laranjeiro }; 978a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 979a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 980a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 981a5bf6af9SAdrien Mazarguil #endif 982a5bf6af9SAdrien Mazarguil buf = buf->next; 983230189d9SNélio Laranjeiro ++mpw.pkts_n; 984a5bf6af9SAdrien Mazarguil ++j; 985a5bf6af9SAdrien Mazarguil } while (--segs_n); 986a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 987230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 988230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 989230189d9SNélio Laranjeiro elts_head = elts_head_next; 990230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 991230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 992230189d9SNélio Laranjeiro txq->stats.obytes += length; 993230189d9SNélio Laranjeiro #endif 994c3d62cc9SAdrien Mazarguil ++i; 995c3d62cc9SAdrien Mazarguil } while (pkts_n); 996230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 997230189d9SNélio Laranjeiro if (unlikely(i == 0)) 998230189d9SNélio Laranjeiro return 0; 999230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1000a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1001a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1002230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 10038688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1004230189d9SNélio Laranjeiro 1005230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 10068688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1007230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 10088688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1009230189d9SNélio Laranjeiro txq->elts_comp = 0; 1010230189d9SNélio Laranjeiro } else { 1011230189d9SNélio Laranjeiro txq->elts_comp = comp; 1012230189d9SNélio Laranjeiro } 1013230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1014230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1015230189d9SNélio Laranjeiro txq->stats.opackets += i; 1016230189d9SNélio Laranjeiro #endif 1017230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1018230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 1019230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 102030807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1021230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1022230189d9SNélio Laranjeiro return i; 1023230189d9SNélio Laranjeiro } 1024230189d9SNélio Laranjeiro 1025230189d9SNélio Laranjeiro /** 1026230189d9SNélio Laranjeiro * Open a MPW inline session. 1027230189d9SNélio Laranjeiro * 1028230189d9SNélio Laranjeiro * @param txq 1029230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1030230189d9SNélio Laranjeiro * @param mpw 1031230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1032230189d9SNélio Laranjeiro * @param length 1033230189d9SNélio Laranjeiro * Packet length. 1034230189d9SNélio Laranjeiro */ 1035230189d9SNélio Laranjeiro static inline void 1036230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 1037230189d9SNélio Laranjeiro { 1038a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 10398688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 1040230189d9SNélio Laranjeiro 1041230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 1042230189d9SNélio Laranjeiro mpw->pkts_n = 0; 1043230189d9SNélio Laranjeiro mpw->len = length; 1044230189d9SNélio Laranjeiro mpw->total_len = 0; 1045fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 10468688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 1047230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 1048c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 10498688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 10508688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 10518688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 10528688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 10538688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 10548688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 10558688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 10568688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 10578688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 10588688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 10598688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 1060230189d9SNélio Laranjeiro } 1061230189d9SNélio Laranjeiro 1062230189d9SNélio Laranjeiro /** 1063230189d9SNélio Laranjeiro * Close a MPW inline session. 1064230189d9SNélio Laranjeiro * 1065230189d9SNélio Laranjeiro * @param txq 1066230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1067230189d9SNélio Laranjeiro * @param mpw 1068230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1069230189d9SNélio Laranjeiro */ 1070230189d9SNélio Laranjeiro static inline void 1071230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 1072230189d9SNélio Laranjeiro { 1073230189d9SNélio Laranjeiro unsigned int size; 10748688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 10758688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 1076230189d9SNélio Laranjeiro 10778688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 1078230189d9SNélio Laranjeiro /* 1079230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1080230189d9SNélio Laranjeiro * count as 2. 1081230189d9SNélio Laranjeiro */ 10828688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size)); 1083230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 10848688b2f8SNélio Laranjeiro inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 10858688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1086230189d9SNélio Laranjeiro } 1087230189d9SNélio Laranjeiro 1088230189d9SNélio Laranjeiro /** 1089230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1090230189d9SNélio Laranjeiro * 1091230189d9SNélio Laranjeiro * @param dpdk_txq 1092230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1093230189d9SNélio Laranjeiro * @param[in] pkts 1094230189d9SNélio Laranjeiro * Packets to transmit. 1095230189d9SNélio Laranjeiro * @param pkts_n 1096230189d9SNélio Laranjeiro * Number of packets in array. 1097230189d9SNélio Laranjeiro * 1098230189d9SNélio Laranjeiro * @return 1099230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1100230189d9SNélio Laranjeiro */ 1101230189d9SNélio Laranjeiro uint16_t 1102230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1103230189d9SNélio Laranjeiro uint16_t pkts_n) 1104230189d9SNélio Laranjeiro { 1105230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 1106230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 1107b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 1108c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1109a5bf6af9SAdrien Mazarguil unsigned int j = 0; 1110230189d9SNélio Laranjeiro unsigned int max; 1111f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1112230189d9SNélio Laranjeiro unsigned int comp; 11130e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1114230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1115230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1116230189d9SNélio Laranjeiro }; 1117f04f1d51SNélio Laranjeiro /* 1118f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1119f04f1d51SNélio Laranjeiro * code. 1120f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1121f04f1d51SNélio Laranjeiro * - 1 control segment, 1122f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1123f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1124f04f1d51SNélio Laranjeiro */ 1125f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1126f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1127f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1128f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1129230189d9SNélio Laranjeiro 1130c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1131c3d62cc9SAdrien Mazarguil return 0; 1132230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1133fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1134fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1135230189d9SNélio Laranjeiro /* Start processing. */ 1136230189d9SNélio Laranjeiro txq_complete(txq); 1137230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 1138230189d9SNélio Laranjeiro if (max > elts_n) 1139230189d9SNélio Laranjeiro max -= elts_n; 1140c3d62cc9SAdrien Mazarguil do { 1141a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1142c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 1143230189d9SNélio Laranjeiro uintptr_t addr; 1144230189d9SNélio Laranjeiro uint32_t length; 1145a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 1146230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 1147230189d9SNélio Laranjeiro 1148c3d62cc9SAdrien Mazarguil /* 1149c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1150c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1151c3d62cc9SAdrien Mazarguil */ 1152a5bf6af9SAdrien Mazarguil assert(segs_n); 1153a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 1154c3d62cc9SAdrien Mazarguil break; 1155a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 1156a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 1157a5bf6af9SAdrien Mazarguil break; 1158a5bf6af9SAdrien Mazarguil max -= segs_n; 1159c3d62cc9SAdrien Mazarguil --pkts_n; 1160f04f1d51SNélio Laranjeiro /* 1161f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1162f04f1d51SNélio Laranjeiro * iteration. 1163f04f1d51SNélio Laranjeiro */ 1164f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 1165230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 1166230189d9SNélio Laranjeiro if (buf->ol_flags & 1167230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 1168230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 1169a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1170a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1171230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1172230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1173230189d9SNélio Laranjeiro if ((mpw.len != length) || 1174a5bf6af9SAdrien Mazarguil (segs_n != 1) || 11758688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1176230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1177230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1178230189d9SNélio Laranjeiro if ((mpw.len != length) || 1179a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1180230189d9SNélio Laranjeiro (length > inline_room) || 11818688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1182230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 11830e8679fcSNélio Laranjeiro inline_room = 11840e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1185230189d9SNélio Laranjeiro } 1186230189d9SNélio Laranjeiro } 1187230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1188a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1189a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1190f04f1d51SNélio Laranjeiro /* 1191f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1192f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1193f04f1d51SNélio Laranjeiro * such resources. 1194f04f1d51SNélio Laranjeiro */ 1195f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1196f04f1d51SNélio Laranjeiro break; 1197f04f1d51SNélio Laranjeiro max_wqe -= 2; 1198230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 11998688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1200230189d9SNélio Laranjeiro } else { 1201f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1202f04f1d51SNélio Laranjeiro break; 1203f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1204230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 12058688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1206230189d9SNélio Laranjeiro } 1207230189d9SNélio Laranjeiro } 1208a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1209a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1210230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 12110e8679fcSNélio Laranjeiro assert(inline_room == 12120e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1213a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1214a5bf6af9SAdrien Mazarguil length = 0; 1215a5bf6af9SAdrien Mazarguil #endif 1216a5bf6af9SAdrien Mazarguil do { 1217230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1218230189d9SNélio Laranjeiro 1219a5bf6af9SAdrien Mazarguil elts_head_next = 1220a5bf6af9SAdrien Mazarguil (elts_head + 1) & (elts_n - 1); 1221a5bf6af9SAdrien Mazarguil assert(buf); 1222a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1223230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1224a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1225230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 1226a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 1227230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 1228230189d9SNélio Laranjeiro .addr = htonll(addr), 1229230189d9SNélio Laranjeiro }; 1230a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 1231a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1232a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1233a5bf6af9SAdrien Mazarguil #endif 1234a5bf6af9SAdrien Mazarguil buf = buf->next; 1235230189d9SNélio Laranjeiro ++mpw.pkts_n; 1236a5bf6af9SAdrien Mazarguil ++j; 1237a5bf6af9SAdrien Mazarguil } while (--segs_n); 1238a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1239230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1240230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1241230189d9SNélio Laranjeiro } else { 1242230189d9SNélio Laranjeiro unsigned int max; 1243230189d9SNélio Laranjeiro 1244230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1245230189d9SNélio Laranjeiro assert(length <= inline_room); 1246a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1247a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1248a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1249a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1250230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1251fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1252fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1253fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1254230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1255230189d9SNélio Laranjeiro if (length > max) { 1256230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1257230189d9SNélio Laranjeiro (void *)addr, 1258230189d9SNélio Laranjeiro max); 1259fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1260230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1261230189d9SNélio Laranjeiro (void *)(addr + max), 1262230189d9SNélio Laranjeiro length - max); 1263230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1264230189d9SNélio Laranjeiro } else { 1265230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1266230189d9SNélio Laranjeiro (void *)addr, 1267230189d9SNélio Laranjeiro length); 126816c64768SYongseok Koh 126916c64768SYongseok Koh if (length == max) 127016c64768SYongseok Koh mpw.data.raw = 127116c64768SYongseok Koh (volatile void *)txq->wqes; 127216c64768SYongseok Koh else 1273230189d9SNélio Laranjeiro mpw.data.raw += length; 1274230189d9SNélio Laranjeiro } 1275230189d9SNélio Laranjeiro ++mpw.pkts_n; 127676bf1574SYongseok Koh mpw.total_len += length; 1277a5bf6af9SAdrien Mazarguil ++j; 1278230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1279230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 12800e8679fcSNélio Laranjeiro inline_room = 12810e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1282230189d9SNélio Laranjeiro } else { 1283230189d9SNélio Laranjeiro inline_room -= length; 1284230189d9SNélio Laranjeiro } 1285230189d9SNélio Laranjeiro } 1286230189d9SNélio Laranjeiro elts_head = elts_head_next; 1287230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1288230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1289230189d9SNélio Laranjeiro txq->stats.obytes += length; 1290230189d9SNélio Laranjeiro #endif 1291c3d62cc9SAdrien Mazarguil ++i; 1292c3d62cc9SAdrien Mazarguil } while (pkts_n); 1293230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1294230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1295230189d9SNélio Laranjeiro return 0; 1296230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1297a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1298a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1299230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 13008688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1301230189d9SNélio Laranjeiro 1302230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 13038688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1304230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 13058688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1306230189d9SNélio Laranjeiro txq->elts_comp = 0; 1307230189d9SNélio Laranjeiro } else { 1308230189d9SNélio Laranjeiro txq->elts_comp = comp; 1309230189d9SNélio Laranjeiro } 1310230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1311230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1312230189d9SNélio Laranjeiro txq->stats.opackets += i; 1313230189d9SNélio Laranjeiro #endif 1314230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1315230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1316230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1317230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1318230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 131930807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1320230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1321230189d9SNélio Laranjeiro return i; 1322230189d9SNélio Laranjeiro } 1323230189d9SNélio Laranjeiro 1324230189d9SNélio Laranjeiro /** 132567fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 132667fa62bcSAdrien Mazarguil * 13276218063bSNélio Laranjeiro * @param[in] cqe 13286218063bSNélio Laranjeiro * Pointer to CQE. 132967fa62bcSAdrien Mazarguil * 133078a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 133178a38edfSJianfeng Tan * 133267fa62bcSAdrien Mazarguil * @return 133367fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 133467fa62bcSAdrien Mazarguil */ 133567fa62bcSAdrien Mazarguil static inline uint32_t 133697267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 133767fa62bcSAdrien Mazarguil { 133867fa62bcSAdrien Mazarguil uint32_t pkt_type; 13390603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 134067fa62bcSAdrien Mazarguil 13410603df73SNélio Laranjeiro if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) { 134267fa62bcSAdrien Mazarguil pkt_type = 134367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1344350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV4_PACKET, 1345501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) | 134667fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1347350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV6_PACKET, 1348501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN); 13490603df73SNélio Laranjeiro pkt_type |= ((cqe->pkt_info & MLX5_CQE_RX_OUTER_PACKET) ? 13500603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV6_EXT_UNKNOWN : 13510603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 13520603df73SNélio Laranjeiro } else { 135367fa62bcSAdrien Mazarguil pkt_type = 135467fa62bcSAdrien Mazarguil TRANSPOSE(flags, 13556218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 1356501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) | 135767fa62bcSAdrien Mazarguil TRANSPOSE(flags, 13586218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 1359501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 13600603df73SNélio Laranjeiro } 136167fa62bcSAdrien Mazarguil return pkt_type; 136267fa62bcSAdrien Mazarguil } 136367fa62bcSAdrien Mazarguil 136467fa62bcSAdrien Mazarguil /** 136599c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 136699c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 136799c12dccSNélio Laranjeiro * been processed. 136899c12dccSNélio Laranjeiro * 136999c12dccSNélio Laranjeiro * @param rxq 137099c12dccSNélio Laranjeiro * Pointer to RX queue. 137199c12dccSNélio Laranjeiro * @param cqe 137299c12dccSNélio Laranjeiro * CQE to process. 1373ecf60761SNélio Laranjeiro * @param[out] rss_hash 1374ecf60761SNélio Laranjeiro * Packet RSS Hash result. 137599c12dccSNélio Laranjeiro * 137699c12dccSNélio Laranjeiro * @return 137799c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 137899c12dccSNélio Laranjeiro * with error. 137999c12dccSNélio Laranjeiro */ 138099c12dccSNélio Laranjeiro static inline int 138197267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 1382ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 138399c12dccSNélio Laranjeiro { 138499c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 138599c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 138699c12dccSNélio Laranjeiro int len = 0; 1387d2e842d0SYongseok Koh uint16_t idx, end; 138899c12dccSNélio Laranjeiro 138999c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 139099c12dccSNélio Laranjeiro if (zip->ai) { 139199c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 139299c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 139397267b8eSNelio Laranjeiro (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt]); 139499c12dccSNélio Laranjeiro 139599c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 1396ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result); 139799c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1398d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1399d2e842d0SYongseok Koh idx = zip->ca; 1400d2e842d0SYongseok Koh end = zip->na; 1401d2e842d0SYongseok Koh while (idx != end) { 1402d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1403d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1404d2e842d0SYongseok Koh ++idx; 1405d2e842d0SYongseok Koh } 140699c12dccSNélio Laranjeiro /* 140799c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 140899c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 140999c12dccSNélio Laranjeiro * ring for software use. 141099c12dccSNélio Laranjeiro */ 141199c12dccSNélio Laranjeiro zip->ca = zip->na; 141299c12dccSNélio Laranjeiro zip->na += 8; 141399c12dccSNélio Laranjeiro } 141499c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1415d2e842d0SYongseok Koh /* Invalidate the rest */ 1416d2e842d0SYongseok Koh idx = zip->ca; 1417d2e842d0SYongseok Koh end = zip->cq_ci; 141899c12dccSNélio Laranjeiro 141999c12dccSNélio Laranjeiro while (idx != end) { 142097267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 142199c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 142299c12dccSNélio Laranjeiro ++idx; 142399c12dccSNélio Laranjeiro } 142499c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 142599c12dccSNélio Laranjeiro zip->ai = 0; 142699c12dccSNélio Laranjeiro } 142799c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 142899c12dccSNélio Laranjeiro } else { 142999c12dccSNélio Laranjeiro int ret; 143099c12dccSNélio Laranjeiro int8_t op_own; 143199c12dccSNélio Laranjeiro 143297267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 143399c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 143499c12dccSNélio Laranjeiro return 0; 143599c12dccSNélio Laranjeiro ++rxq->cq_ci; 143699c12dccSNélio Laranjeiro op_own = cqe->op_own; 143799c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 143899c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 143999c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 144099c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 144197267b8eSNelio Laranjeiro cqe_cnt]); 144299c12dccSNélio Laranjeiro 144399c12dccSNélio Laranjeiro /* Fix endianness. */ 144499c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 144599c12dccSNélio Laranjeiro /* 144699c12dccSNélio Laranjeiro * Current mini array position is the one returned by 144799c12dccSNélio Laranjeiro * check_cqe64(). 144899c12dccSNélio Laranjeiro * 144999c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 145099c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 145199c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 145299c12dccSNélio Laranjeiro */ 1453d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 145499c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 145599c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 145699c12dccSNélio Laranjeiro --rxq->cq_ci; 145799c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 145899c12dccSNélio Laranjeiro /* Get packet size to return. */ 145999c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 1460ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[0].rx_hash_result); 146199c12dccSNélio Laranjeiro zip->ai = 1; 1462d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1463d2e842d0SYongseok Koh idx = zip->ca; 1464d2e842d0SYongseok Koh end = zip->cq_ci; 1465d2e842d0SYongseok Koh while (idx != end) { 1466d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1467d2e842d0SYongseok Koh ++idx; 1468d2e842d0SYongseok Koh } 146999c12dccSNélio Laranjeiro } else { 147099c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 1471ecf60761SNélio Laranjeiro *rss_hash = ntohl(cqe->rx_hash_res); 147299c12dccSNélio Laranjeiro } 147399c12dccSNélio Laranjeiro /* Error while receiving packet. */ 147499c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 147599c12dccSNélio Laranjeiro return -1; 147699c12dccSNélio Laranjeiro } 147799c12dccSNélio Laranjeiro return len; 147899c12dccSNélio Laranjeiro } 147999c12dccSNélio Laranjeiro 148099c12dccSNélio Laranjeiro /** 148167fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 148267fa62bcSAdrien Mazarguil * 148367fa62bcSAdrien Mazarguil * @param[in] rxq 148467fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 14856218063bSNélio Laranjeiro * @param[in] cqe 14866218063bSNélio Laranjeiro * Pointer to CQE. 148767fa62bcSAdrien Mazarguil * 148867fa62bcSAdrien Mazarguil * @return 148967fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 149067fa62bcSAdrien Mazarguil */ 149167fa62bcSAdrien Mazarguil static inline uint32_t 149297267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe) 149367fa62bcSAdrien Mazarguil { 149467fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 14950603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 149667fa62bcSAdrien Mazarguil 14970603df73SNélio Laranjeiro ol_flags = 14980603df73SNélio Laranjeiro TRANSPOSE(flags, 14990603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 15000603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 15010603df73SNélio Laranjeiro TRANSPOSE(flags, 15020603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 150383e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 150497267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 150567fa62bcSAdrien Mazarguil ol_flags |= 15060603df73SNélio Laranjeiro TRANSPOSE(flags, 15070603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 150883e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 15090603df73SNélio Laranjeiro TRANSPOSE(flags, 15100603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 151183e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 151267fa62bcSAdrien Mazarguil return ol_flags; 151367fa62bcSAdrien Mazarguil } 151467fa62bcSAdrien Mazarguil 151567fa62bcSAdrien Mazarguil /** 15162e22920bSAdrien Mazarguil * DPDK callback for RX. 15172e22920bSAdrien Mazarguil * 15182e22920bSAdrien Mazarguil * @param dpdk_rxq 15192e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 15202e22920bSAdrien Mazarguil * @param[out] pkts 15212e22920bSAdrien Mazarguil * Array to store received packets. 15222e22920bSAdrien Mazarguil * @param pkts_n 15232e22920bSAdrien Mazarguil * Maximum number of packets in array. 15242e22920bSAdrien Mazarguil * 15252e22920bSAdrien Mazarguil * @return 15262e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 15272e22920bSAdrien Mazarguil */ 15282e22920bSAdrien Mazarguil uint16_t 15292e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 15302e22920bSAdrien Mazarguil { 15316218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 1532b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1533e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 15349964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 15359964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 15369964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 153797267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 153897267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 15399964b965SNélio Laranjeiro unsigned int i = 0; 15409964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 1541ecf60761SNélio Laranjeiro int len; /* keep its value across iterations. */ 15422e22920bSAdrien Mazarguil 15439964b965SNélio Laranjeiro while (pkts_n) { 15449964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 15459964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 15469964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1547ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 15489964b965SNélio Laranjeiro 15499964b965SNélio Laranjeiro if (pkt) 15509964b965SNélio Laranjeiro NEXT(seg) = rep; 15519964b965SNélio Laranjeiro seg = rep; 15529964b965SNélio Laranjeiro rte_prefetch0(seg); 15536218063bSNélio Laranjeiro rte_prefetch0(cqe); 15549964b965SNélio Laranjeiro rte_prefetch0(wqe); 1555fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 15562e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 155715a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 155815a756b6SSagi Grimberg if (!pkt) { 155915a756b6SSagi Grimberg /* 156015a756b6SSagi Grimberg * no buffers before we even started, 156115a756b6SSagi Grimberg * bail out silently. 156215a756b6SSagi Grimberg */ 156315a756b6SSagi Grimberg break; 156415a756b6SSagi Grimberg } 1565a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1566a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1567fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 15689964b965SNélio Laranjeiro rte_mbuf_refcnt_set(pkt, 0); 15699964b965SNélio Laranjeiro __rte_mbuf_raw_free(pkt); 1570fe5fe382SNélio Laranjeiro pkt = rep; 15719964b965SNélio Laranjeiro } 15726218063bSNélio Laranjeiro break; 15732e22920bSAdrien Mazarguil } 15749964b965SNélio Laranjeiro if (!pkt) { 157597267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1576ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1577ecf60761SNélio Laranjeiro &rss_hash_res); 1578ecf60761SNélio Laranjeiro if (!len) { 15796218063bSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 15806218063bSNélio Laranjeiro __rte_mbuf_raw_free(rep); 15816218063bSNélio Laranjeiro break; 15826218063bSNélio Laranjeiro } 158399c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 158499c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 158599c12dccSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 158699c12dccSNélio Laranjeiro __rte_mbuf_raw_free(rep); 158799c12dccSNélio Laranjeiro ++rxq->stats.idropped; 158899c12dccSNélio Laranjeiro goto skip; 158999c12dccSNélio Laranjeiro } 15909964b965SNélio Laranjeiro pkt = seg; 15919964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 15929964b965SNélio Laranjeiro /* Update packet information. */ 15930ac64846SMaxime Leroy pkt->packet_type = 0; 15940ac64846SMaxime Leroy pkt->ol_flags = 0; 159536ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1596ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1597ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1598ecf60761SNélio Laranjeiro } 1599b268a3eeSNélio Laranjeiro if (rxq->mark && (cqe->sop_drop_qpn != 1600b268a3eeSNélio Laranjeiro htonl(MLX5_FLOW_MARK_INVALID))) { 1601b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 1602b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 1603b268a3eeSNélio Laranjeiro htonl(MLX5_FLOW_MARK_DEFAULT)) { 1604b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 1605b268a3eeSNélio Laranjeiro 1606b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 1607ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1608b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 1609b268a3eeSNélio Laranjeiro } 1610ea3bc3b1SNélio Laranjeiro } 16116218063bSNélio Laranjeiro if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip | 16126218063bSNélio Laranjeiro rxq->crc_present) { 16136218063bSNélio Laranjeiro if (rxq->csum) { 16149964b965SNélio Laranjeiro pkt->packet_type = 16159964b965SNélio Laranjeiro rxq_cq_to_pkt_type(cqe); 1616ecf60761SNélio Laranjeiro pkt->ol_flags |= 16179964b965SNélio Laranjeiro rxq_cq_to_ol_flags(rxq, cqe); 16186218063bSNélio Laranjeiro } 16199514fa2dSShahaf Shuler if (ntohs(cqe->hdr_type_etc) & 16209964b965SNélio Laranjeiro MLX5_CQE_VLAN_STRIPPED) { 16216218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1622b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 16236218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 1624f3db9489SYaacov Hazan } 16256218063bSNélio Laranjeiro if (rxq->crc_present) 16266218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 1627081f7eaeSNelio Laranjeiro } 16286218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 16299964b965SNélio Laranjeiro } 16309964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 16319964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 16329964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 16339964b965SNélio Laranjeiro NB_SEGS(rep) = NB_SEGS(seg); 16349964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 16359964b965SNélio Laranjeiro NEXT(rep) = NULL; 16369964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 16379964b965SNélio Laranjeiro /* 16389964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 16399964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 16409964b965SNélio Laranjeiro * changes. 16419964b965SNélio Laranjeiro */ 16429964b965SNélio Laranjeiro wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t)); 16439964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 16449964b965SNélio Laranjeiro len -= DATA_LEN(seg); 16459964b965SNélio Laranjeiro ++NB_SEGS(pkt); 16469964b965SNélio Laranjeiro ++rq_ci; 16479964b965SNélio Laranjeiro continue; 16489964b965SNélio Laranjeiro } 16499964b965SNélio Laranjeiro DATA_LEN(seg) = len; 165087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 165187011737SAdrien Mazarguil /* Increment bytes counter. */ 16529964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 165387011737SAdrien Mazarguil #endif 16546218063bSNélio Laranjeiro /* Return packet. */ 16556218063bSNélio Laranjeiro *(pkts++) = pkt; 16569964b965SNélio Laranjeiro pkt = NULL; 16579964b965SNélio Laranjeiro --pkts_n; 16589964b965SNélio Laranjeiro ++i; 165999c12dccSNélio Laranjeiro skip: 16609964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 16619964b965SNélio Laranjeiro rq_ci >>= sges_n; 16626218063bSNélio Laranjeiro ++rq_ci; 16639964b965SNélio Laranjeiro rq_ci <<= sges_n; 16642e22920bSAdrien Mazarguil } 16659964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 16662e22920bSAdrien Mazarguil return 0; 16676218063bSNélio Laranjeiro /* Update the consumer index. */ 16689964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 16696218063bSNélio Laranjeiro rte_wmb(); 16706218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 16716218063bSNélio Laranjeiro rte_wmb(); 16726218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 167387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 167487011737SAdrien Mazarguil /* Increment packets counter. */ 16759964b965SNélio Laranjeiro rxq->stats.ipackets += i; 167687011737SAdrien Mazarguil #endif 16779964b965SNélio Laranjeiro return i; 16782e22920bSAdrien Mazarguil } 16792e22920bSAdrien Mazarguil 16802e22920bSAdrien Mazarguil /** 16812e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 16822e22920bSAdrien Mazarguil * 16832e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 16842e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 16852e22920bSAdrien Mazarguil * 16862e22920bSAdrien Mazarguil * @param dpdk_txq 16872e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 16882e22920bSAdrien Mazarguil * @param[in] pkts 16892e22920bSAdrien Mazarguil * Packets to transmit. 16902e22920bSAdrien Mazarguil * @param pkts_n 16912e22920bSAdrien Mazarguil * Number of packets in array. 16922e22920bSAdrien Mazarguil * 16932e22920bSAdrien Mazarguil * @return 16942e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 16952e22920bSAdrien Mazarguil */ 16962e22920bSAdrien Mazarguil uint16_t 16972e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 16982e22920bSAdrien Mazarguil { 16992e22920bSAdrien Mazarguil (void)dpdk_txq; 17002e22920bSAdrien Mazarguil (void)pkts; 17012e22920bSAdrien Mazarguil (void)pkts_n; 17022e22920bSAdrien Mazarguil return 0; 17032e22920bSAdrien Mazarguil } 17042e22920bSAdrien Mazarguil 17052e22920bSAdrien Mazarguil /** 17062e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 17072e22920bSAdrien Mazarguil * 17082e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 17092e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 17102e22920bSAdrien Mazarguil * 17112e22920bSAdrien Mazarguil * @param dpdk_rxq 17122e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 17132e22920bSAdrien Mazarguil * @param[out] pkts 17142e22920bSAdrien Mazarguil * Array to store received packets. 17152e22920bSAdrien Mazarguil * @param pkts_n 17162e22920bSAdrien Mazarguil * Maximum number of packets in array. 17172e22920bSAdrien Mazarguil * 17182e22920bSAdrien Mazarguil * @return 17192e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 17202e22920bSAdrien Mazarguil */ 17212e22920bSAdrien Mazarguil uint16_t 17222e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 17232e22920bSAdrien Mazarguil { 17242e22920bSAdrien Mazarguil (void)dpdk_rxq; 17252e22920bSAdrien Mazarguil (void)pkts; 17262e22920bSAdrien Mazarguil (void)pkts_n; 17272e22920bSAdrien Mazarguil return 0; 17282e22920bSAdrien Mazarguil } 1729