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 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 155a6ca35aaSNélio Laranjeiro static inline void 156a6ca35aaSNélio Laranjeiro txq_complete(struct txq *txq) __attribute__((always_inline)); 157a6ca35aaSNélio Laranjeiro 1582e22920bSAdrien Mazarguil /** 1592e22920bSAdrien Mazarguil * Manage TX completions. 1602e22920bSAdrien Mazarguil * 1612e22920bSAdrien Mazarguil * When sending a burst, mlx5_tx_burst() posts several WRs. 1622e22920bSAdrien Mazarguil * 1632e22920bSAdrien Mazarguil * @param txq 1642e22920bSAdrien Mazarguil * Pointer to TX queue structure. 1652e22920bSAdrien Mazarguil */ 166a6ca35aaSNélio Laranjeiro static inline void 1672e22920bSAdrien Mazarguil txq_complete(struct txq *txq) 1682e22920bSAdrien Mazarguil { 1691d88ba17SNélio Laranjeiro const unsigned int cqe_n = txq->cqe_n; 170*b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 17199c12dccSNélio Laranjeiro const unsigned int cqe_cnt = cqe_n - 1; 1721d88ba17SNélio Laranjeiro uint16_t elts_free = txq->elts_tail; 1731d88ba17SNélio Laranjeiro uint16_t elts_tail; 1741d88ba17SNélio Laranjeiro uint16_t cq_ci = txq->cq_ci; 175c305090bSAdrien Mazarguil volatile struct mlx5_cqe64 *cqe = NULL; 1768688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe; 1772e22920bSAdrien Mazarguil 17899c12dccSNélio Laranjeiro do { 179c305090bSAdrien Mazarguil volatile struct mlx5_cqe64 *tmp; 1801d88ba17SNélio Laranjeiro 181c305090bSAdrien Mazarguil tmp = &(*txq->cqes)[cq_ci & cqe_cnt].cqe64; 182c305090bSAdrien Mazarguil if (check_cqe64(tmp, cqe_n, cq_ci)) 1831d88ba17SNélio Laranjeiro break; 184c305090bSAdrien Mazarguil cqe = tmp; 18599c12dccSNélio Laranjeiro #ifndef NDEBUG 18699c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) { 18799c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 18899c12dccSNélio Laranjeiro ERROR("unexpected compressed CQE, TX stopped"); 18999c12dccSNélio Laranjeiro return; 1902e22920bSAdrien Mazarguil } 19199c12dccSNélio Laranjeiro if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) || 19299c12dccSNélio Laranjeiro (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) { 19399c12dccSNélio Laranjeiro if (!check_cqe64_seen(cqe)) 19499c12dccSNélio Laranjeiro ERROR("unexpected error CQE, TX stopped"); 19599c12dccSNélio Laranjeiro return; 19699c12dccSNélio Laranjeiro } 19799c12dccSNélio Laranjeiro #endif /* NDEBUG */ 19899c12dccSNélio Laranjeiro ++cq_ci; 19999c12dccSNélio Laranjeiro } while (1); 200c305090bSAdrien Mazarguil if (unlikely(cqe == NULL)) 2011d88ba17SNélio Laranjeiro return; 2028688b2f8SNélio Laranjeiro wqe = &(*txq->wqes)[htons(cqe->wqe_counter) & (txq->wqe_n - 1)].hdr; 2038688b2f8SNélio Laranjeiro elts_tail = wqe->ctrl[3]; 204c305090bSAdrien Mazarguil assert(elts_tail < txq->wqe_n); 2051d88ba17SNélio Laranjeiro /* Free buffers. */ 206c305090bSAdrien Mazarguil while (elts_free != elts_tail) { 2071d88ba17SNélio Laranjeiro struct rte_mbuf *elt = (*txq->elts)[elts_free]; 208a859e8a9SNelio Laranjeiro unsigned int elts_free_next = 2091d88ba17SNélio Laranjeiro (elts_free + 1) & (elts_n - 1); 2101d88ba17SNélio Laranjeiro struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next]; 211a859e8a9SNelio Laranjeiro 212b185e63fSAdrien Mazarguil #ifndef NDEBUG 213b185e63fSAdrien Mazarguil /* Poisoning. */ 2141d88ba17SNélio Laranjeiro memset(&(*txq->elts)[elts_free], 2151d88ba17SNélio Laranjeiro 0x66, 2161d88ba17SNélio Laranjeiro sizeof((*txq->elts)[elts_free])); 217b185e63fSAdrien Mazarguil #endif 2181d88ba17SNélio Laranjeiro RTE_MBUF_PREFETCH_TO_FREE(elt_next); 2191d88ba17SNélio Laranjeiro /* Only one segment needs to be freed. */ 2201d88ba17SNélio Laranjeiro rte_pktmbuf_free_seg(elt); 221a859e8a9SNelio Laranjeiro elts_free = elts_free_next; 222c305090bSAdrien Mazarguil } 2231d88ba17SNélio Laranjeiro txq->cq_ci = cq_ci; 2242e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 2251d88ba17SNélio Laranjeiro /* Update the consumer index. */ 2261d88ba17SNélio Laranjeiro rte_wmb(); 2271d88ba17SNélio Laranjeiro *txq->cq_db = htonl(cq_ci); 2282e22920bSAdrien Mazarguil } 2292e22920bSAdrien Mazarguil 2302e22920bSAdrien Mazarguil /** 2318340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 2328340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 2338340392eSAdrien Mazarguil * 2348340392eSAdrien Mazarguil * @param buf 2358340392eSAdrien Mazarguil * Pointer to mbuf. 2368340392eSAdrien Mazarguil * 2378340392eSAdrien Mazarguil * @return 2388340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 2398340392eSAdrien Mazarguil */ 2408340392eSAdrien Mazarguil static struct rte_mempool * 2418340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 2428340392eSAdrien Mazarguil { 2438340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 2448340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 2458340392eSAdrien Mazarguil return buf->pool; 2468340392eSAdrien Mazarguil } 2478340392eSAdrien Mazarguil 248491770faSNélio Laranjeiro static inline uint32_t 249491770faSNélio Laranjeiro txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 250491770faSNélio Laranjeiro __attribute__((always_inline)); 251491770faSNélio Laranjeiro 2528340392eSAdrien Mazarguil /** 2532e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 2542e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 2552e22920bSAdrien Mazarguil * remove an entry first. 2562e22920bSAdrien Mazarguil * 2572e22920bSAdrien Mazarguil * @param txq 2582e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2592e22920bSAdrien Mazarguil * @param[in] mp 2602e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 2612e22920bSAdrien Mazarguil * 2622e22920bSAdrien Mazarguil * @return 2632e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 2642e22920bSAdrien Mazarguil */ 265491770faSNélio Laranjeiro static inline uint32_t 266d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 2672e22920bSAdrien Mazarguil { 2682e22920bSAdrien Mazarguil unsigned int i; 269491770faSNélio Laranjeiro uint32_t lkey = (uint32_t)-1; 2702e22920bSAdrien Mazarguil 2712e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 2722e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 2732e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 2742e22920bSAdrien Mazarguil break; 2752e22920bSAdrien Mazarguil } 2762e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 2772e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 2781d88ba17SNélio Laranjeiro assert(htonl(txq->mp2mr[i].mr->lkey) == 2791d88ba17SNélio Laranjeiro txq->mp2mr[i].lkey); 280491770faSNélio Laranjeiro lkey = txq->mp2mr[i].lkey; 281491770faSNélio Laranjeiro break; 2822e22920bSAdrien Mazarguil } 2832e22920bSAdrien Mazarguil } 284491770faSNélio Laranjeiro if (unlikely(lkey == (uint32_t)-1)) 285491770faSNélio Laranjeiro lkey = txq_mp2mr_reg(txq, mp, i); 286491770faSNélio Laranjeiro return lkey; 2870a3b350dSOlga Shern } 2880a3b350dSOlga Shern 289e192ef80SYaacov Hazan /** 2901d88ba17SNélio Laranjeiro * Write a regular WQE. 291e192ef80SYaacov Hazan * 2921d88ba17SNélio Laranjeiro * @param txq 2931d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 2941d88ba17SNélio Laranjeiro * @param wqe 2951d88ba17SNélio Laranjeiro * Pointer to the WQE to fill. 296d772d440SNélio Laranjeiro * @param buf 297d772d440SNélio Laranjeiro * Buffer. 2981d88ba17SNélio Laranjeiro * @param length 2991d88ba17SNélio Laranjeiro * Packet length. 3000e8679fcSNélio Laranjeiro * 3010e8679fcSNélio Laranjeiro * @return ds 3020e8679fcSNélio Laranjeiro * Number of DS elements consumed. 303e192ef80SYaacov Hazan */ 3040e8679fcSNélio Laranjeiro static inline unsigned int 3058688b2f8SNélio Laranjeiro mlx5_wqe_write(struct txq *txq, volatile struct mlx5_wqe *wqe, 3060e8679fcSNélio Laranjeiro struct rte_mbuf *buf, uint32_t length) 307e192ef80SYaacov Hazan { 3088688b2f8SNélio Laranjeiro uint8_t *raw = (uint8_t *)(uintptr_t)&wqe->eseg.inline_hdr[0]; 3090e8679fcSNélio Laranjeiro uint16_t ds; 3108688b2f8SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE; 311d772d440SNélio Laranjeiro uintptr_t addr = rte_pktmbuf_mtod(buf, uintptr_t); 3120e8679fcSNélio Laranjeiro struct mlx5_wqe_data_seg *dseg = NULL; 313e192ef80SYaacov Hazan 3148688b2f8SNélio Laranjeiro assert(length >= MLX5_WQE_DWORD_SIZE); 3150e8679fcSNélio Laranjeiro /* Start the know and common part of the WQE structure. */ 3168688b2f8SNélio Laranjeiro wqe->ctrl[0] = htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND); 3178688b2f8SNélio Laranjeiro wqe->ctrl[2] = 0; 3188688b2f8SNélio Laranjeiro wqe->ctrl[3] = 0; 3198688b2f8SNélio Laranjeiro wqe->eseg.rsvd0 = 0; 3208688b2f8SNélio Laranjeiro wqe->eseg.rsvd1 = 0; 3218688b2f8SNélio Laranjeiro wqe->eseg.mss = 0; 3228688b2f8SNélio Laranjeiro wqe->eseg.rsvd2 = 0; 3230e8679fcSNélio Laranjeiro /* Start by copying the Ethernet Header. */ 3240e8679fcSNélio Laranjeiro rte_mov16((uint8_t *)raw, (uint8_t *)addr); 3258688b2f8SNélio Laranjeiro length -= MLX5_WQE_DWORD_SIZE; 3268688b2f8SNélio Laranjeiro addr += MLX5_WQE_DWORD_SIZE; 3270e8679fcSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 328d772d440SNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 329d772d440SNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | buf->vlan_tci); 330e192ef80SYaacov Hazan 3318688b2f8SNélio Laranjeiro memcpy((uint8_t *)(raw + MLX5_WQE_DWORD_SIZE - sizeof(vlan)), 3321d88ba17SNélio Laranjeiro &vlan, sizeof(vlan)); 333d772d440SNélio Laranjeiro addr -= sizeof(vlan); 334d772d440SNélio Laranjeiro length += sizeof(vlan); 335d772d440SNélio Laranjeiro } 3360e8679fcSNélio Laranjeiro /* Inline if enough room. */ 3370e8679fcSNélio Laranjeiro if (txq->max_inline != 0) { 3380e8679fcSNélio Laranjeiro uintptr_t end = (uintptr_t)&(*txq->wqes)[txq->wqe_n]; 3390e8679fcSNélio Laranjeiro uint16_t max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 3400e8679fcSNélio Laranjeiro uint16_t room; 3410e8679fcSNélio Laranjeiro 3428688b2f8SNélio Laranjeiro raw += MLX5_WQE_DWORD_SIZE; 3430e8679fcSNélio Laranjeiro room = end - (uintptr_t)raw; 3440e8679fcSNélio Laranjeiro if (room > max_inline) { 3450e8679fcSNélio Laranjeiro uintptr_t addr_end = (addr + max_inline) & 3460e8679fcSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 3470e8679fcSNélio Laranjeiro uint16_t copy_b = ((addr_end - addr) > length) ? 3480e8679fcSNélio Laranjeiro length : 3490e8679fcSNélio Laranjeiro (addr_end - addr); 3500e8679fcSNélio Laranjeiro 3510e8679fcSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 3520e8679fcSNélio Laranjeiro addr += copy_b; 3530e8679fcSNélio Laranjeiro length -= copy_b; 3540e8679fcSNélio Laranjeiro pkt_inline_sz += copy_b; 3550e8679fcSNélio Laranjeiro /* Sanity check. */ 3560e8679fcSNélio Laranjeiro assert(addr <= addr_end); 3571d88ba17SNélio Laranjeiro } 3580e8679fcSNélio Laranjeiro /* Store the inlined packet size in the WQE. */ 3598688b2f8SNélio Laranjeiro wqe->eseg.inline_hdr_sz = htons(pkt_inline_sz); 3602a66cf37SYaacov Hazan /* 3610e8679fcSNélio Laranjeiro * 2 DWORDs consumed by the WQE header + 1 DSEG + 3620e8679fcSNélio Laranjeiro * the size of the inline part of the packet. 3632a66cf37SYaacov Hazan */ 3648688b2f8SNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 3650e8679fcSNélio Laranjeiro if (length > 0) { 3660e8679fcSNélio Laranjeiro dseg = (struct mlx5_wqe_data_seg *) 3678688b2f8SNélio Laranjeiro ((uintptr_t)wqe + (ds * MLX5_WQE_DWORD_SIZE)); 3680e8679fcSNélio Laranjeiro if ((uintptr_t)dseg >= end) 3690e8679fcSNélio Laranjeiro dseg = (struct mlx5_wqe_data_seg *) 3700e8679fcSNélio Laranjeiro ((uintptr_t)&(*txq->wqes)[0]); 3710e8679fcSNélio Laranjeiro goto use_dseg; 3722a66cf37SYaacov Hazan } 3730e8679fcSNélio Laranjeiro } else { 3740e8679fcSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 3750e8679fcSNélio Laranjeiro ds = 3; 3760e8679fcSNélio Laranjeiro /* 3770e8679fcSNélio Laranjeiro * No inline has been done in the packet, only the Ethernet 3780e8679fcSNélio Laranjeiro * Header as been stored. 3790e8679fcSNélio Laranjeiro */ 3808688b2f8SNélio Laranjeiro wqe->eseg.inline_hdr_sz = htons(MLX5_WQE_DWORD_SIZE); 3810e8679fcSNélio Laranjeiro dseg = (struct mlx5_wqe_data_seg *) 3828688b2f8SNélio Laranjeiro ((uintptr_t)wqe + (ds * MLX5_WQE_DWORD_SIZE)); 3830e8679fcSNélio Laranjeiro use_dseg: 3840e8679fcSNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg) { 3850e8679fcSNélio Laranjeiro .addr = htonll(addr), 3860e8679fcSNélio Laranjeiro .byte_count = htonl(length), 3870e8679fcSNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 3880e8679fcSNélio Laranjeiro }; 3890e8679fcSNélio Laranjeiro ++ds; 3900e8679fcSNélio Laranjeiro } 3918688b2f8SNélio Laranjeiro wqe->ctrl[1] = htonl(txq->qp_num_8s | ds); 3920e8679fcSNélio Laranjeiro return ds; 3932a66cf37SYaacov Hazan } 3942a66cf37SYaacov Hazan 3952a66cf37SYaacov Hazan /** 3961d88ba17SNélio Laranjeiro * Ring TX queue doorbell. 3971d88ba17SNélio Laranjeiro * 3981d88ba17SNélio Laranjeiro * @param txq 3991d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 4001d88ba17SNélio Laranjeiro */ 4011d88ba17SNélio Laranjeiro static inline void 4021d88ba17SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq) 4031d88ba17SNélio Laranjeiro { 4041d88ba17SNélio Laranjeiro uint8_t *dst = (uint8_t *)((uintptr_t)txq->bf_reg + txq->bf_offset); 4051d88ba17SNélio Laranjeiro uint32_t data[4] = { 4061d88ba17SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 4071d88ba17SNélio Laranjeiro htonl(txq->qp_num_8s), 4081d88ba17SNélio Laranjeiro 0, 4091d88ba17SNélio Laranjeiro 0, 4101d88ba17SNélio Laranjeiro }; 4111d88ba17SNélio Laranjeiro rte_wmb(); 4121d88ba17SNélio Laranjeiro *txq->qp_db = htonl(txq->wqe_ci); 4131d88ba17SNélio Laranjeiro /* Ensure ordering between DB record and BF copy. */ 4141d88ba17SNélio Laranjeiro rte_wmb(); 4151d88ba17SNélio Laranjeiro rte_mov16(dst, (uint8_t *)data); 4161d88ba17SNélio Laranjeiro txq->bf_offset ^= txq->bf_buf_size; 4171d88ba17SNélio Laranjeiro } 418e192ef80SYaacov Hazan 4191d88ba17SNélio Laranjeiro /** 4201d88ba17SNélio Laranjeiro * Prefetch a CQE. 4211d88ba17SNélio Laranjeiro * 4221d88ba17SNélio Laranjeiro * @param txq 4231d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 4241d88ba17SNélio Laranjeiro * @param cqe_ci 4251d88ba17SNélio Laranjeiro * CQE consumer index. 4261d88ba17SNélio Laranjeiro */ 4271d88ba17SNélio Laranjeiro static inline void 4281d88ba17SNélio Laranjeiro tx_prefetch_cqe(struct txq *txq, uint16_t ci) 4291d88ba17SNélio Laranjeiro { 4301d88ba17SNélio Laranjeiro volatile struct mlx5_cqe64 *cqe; 4311d88ba17SNélio Laranjeiro 4321d88ba17SNélio Laranjeiro cqe = &(*txq->cqes)[ci & (txq->cqe_n - 1)].cqe64; 4331d88ba17SNélio Laranjeiro rte_prefetch0(cqe); 434e192ef80SYaacov Hazan } 435e192ef80SYaacov Hazan 4362e22920bSAdrien Mazarguil /** 4372a66cf37SYaacov Hazan * Prefetch a WQE. 4382a66cf37SYaacov Hazan * 4392a66cf37SYaacov Hazan * @param txq 4402a66cf37SYaacov Hazan * Pointer to TX queue structure. 4412a66cf37SYaacov Hazan * @param wqe_ci 4422a66cf37SYaacov Hazan * WQE consumer index. 4432a66cf37SYaacov Hazan */ 4442a66cf37SYaacov Hazan static inline void 4452a66cf37SYaacov Hazan tx_prefetch_wqe(struct txq *txq, uint16_t ci) 4462a66cf37SYaacov Hazan { 4478688b2f8SNélio Laranjeiro volatile struct mlx5_wqe64 *wqe; 4482a66cf37SYaacov Hazan 4492a66cf37SYaacov Hazan wqe = &(*txq->wqes)[ci & (txq->wqe_n - 1)]; 4502a66cf37SYaacov Hazan rte_prefetch0(wqe); 4512a66cf37SYaacov Hazan } 4522a66cf37SYaacov Hazan 4532a66cf37SYaacov Hazan /** 4542e22920bSAdrien Mazarguil * DPDK callback for TX. 4552e22920bSAdrien Mazarguil * 4562e22920bSAdrien Mazarguil * @param dpdk_txq 4572e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 4582e22920bSAdrien Mazarguil * @param[in] pkts 4592e22920bSAdrien Mazarguil * Packets to transmit. 4602e22920bSAdrien Mazarguil * @param pkts_n 4612e22920bSAdrien Mazarguil * Number of packets in array. 4622e22920bSAdrien Mazarguil * 4632e22920bSAdrien Mazarguil * @return 4642e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 4652e22920bSAdrien Mazarguil */ 4662e22920bSAdrien Mazarguil uint16_t 4672e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 4682e22920bSAdrien Mazarguil { 4692e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 4701d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 471*b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 472c3d62cc9SAdrien Mazarguil unsigned int i = 0; 473a5bf6af9SAdrien Mazarguil unsigned int j = 0; 4742e22920bSAdrien Mazarguil unsigned int max; 475c305090bSAdrien Mazarguil unsigned int comp; 4768688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = NULL; 4772e22920bSAdrien Mazarguil 4781d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 4791d88ba17SNélio Laranjeiro return 0; 4805e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 4811d88ba17SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 4821d88ba17SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci + 1); 483c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 4841d88ba17SNélio Laranjeiro /* Start processing. */ 4852e22920bSAdrien Mazarguil txq_complete(txq); 4864f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 4872e22920bSAdrien Mazarguil if (max > elts_n) 4882e22920bSAdrien Mazarguil max -= elts_n; 489c3d62cc9SAdrien Mazarguil do { 490a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 491c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 492573f54afSNélio Laranjeiro uint32_t length; 493a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 494a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 4958688b2f8SNélio Laranjeiro unsigned int ds = 0; 4962e22920bSAdrien Mazarguil 497c3d62cc9SAdrien Mazarguil /* 498c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 499c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 500c3d62cc9SAdrien Mazarguil */ 501a5bf6af9SAdrien Mazarguil assert(segs_n); 502a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 503c3d62cc9SAdrien Mazarguil break; 504a5bf6af9SAdrien Mazarguil max -= segs_n; 505c3d62cc9SAdrien Mazarguil --pkts_n; 506c3d62cc9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 5078688b2f8SNélio Laranjeiro wqe = &(*txq->wqes)[txq->wqe_ci & (txq->wqe_n - 1)].hdr; 5080e8679fcSNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 5090e8679fcSNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 510c3d62cc9SAdrien Mazarguil if (pkts_n) 511c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 5122e22920bSAdrien Mazarguil length = DATA_LEN(buf); 5132e22920bSAdrien Mazarguil /* Update element. */ 5141d88ba17SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 5155e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 516c3d62cc9SAdrien Mazarguil if (pkts_n) 517c3d62cc9SAdrien Mazarguil rte_prefetch0(rte_pktmbuf_mtod(*pkts, 5181d88ba17SNélio Laranjeiro volatile void *)); 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)) { 5228688b2f8SNélio Laranjeiro wqe->eseg.cs_flags = 5231d88ba17SNélio Laranjeiro MLX5_ETH_WQE_L3_CSUM | 5241d88ba17SNélio Laranjeiro MLX5_ETH_WQE_L4_CSUM; 5251d88ba17SNélio Laranjeiro } else { 5268688b2f8SNélio Laranjeiro wqe->eseg.cs_flags = 0; 5271d88ba17SNélio Laranjeiro } 5280e8679fcSNélio Laranjeiro ds = mlx5_wqe_write(txq, wqe, buf, length); 5290e8679fcSNélio Laranjeiro if (segs_n == 1) 5300e8679fcSNélio Laranjeiro goto skip_segs; 5310e8679fcSNélio Laranjeiro dseg = (volatile struct mlx5_wqe_data_seg *) 5328688b2f8SNélio Laranjeiro (((uintptr_t)wqe) + ds * MLX5_WQE_DWORD_SIZE); 533a5bf6af9SAdrien Mazarguil while (--segs_n) { 534a5bf6af9SAdrien Mazarguil /* 535a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 536a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 537a5bf6af9SAdrien Mazarguil * of data segment size. 538a5bf6af9SAdrien Mazarguil */ 5398688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 5408688b2f8SNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) 541a5bf6af9SAdrien Mazarguil dseg = (volatile void *) 542a5bf6af9SAdrien Mazarguil &(*txq->wqes)[txq->wqe_ci++ & 543a5bf6af9SAdrien Mazarguil (txq->wqe_n - 1)]; 544a5bf6af9SAdrien Mazarguil else 545a5bf6af9SAdrien Mazarguil ++dseg; 546a5bf6af9SAdrien Mazarguil ++ds; 547a5bf6af9SAdrien Mazarguil buf = buf->next; 548a5bf6af9SAdrien Mazarguil assert(buf); 549a5bf6af9SAdrien Mazarguil /* Store segment information. */ 550a5bf6af9SAdrien Mazarguil dseg->byte_count = htonl(DATA_LEN(buf)); 551a5bf6af9SAdrien Mazarguil dseg->lkey = txq_mp2mr(txq, txq_mb2mp(buf)); 552a5bf6af9SAdrien Mazarguil dseg->addr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)); 553a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head_next] = buf; 554a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head_next + 1) & (elts_n - 1); 555a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 556a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 557a5bf6af9SAdrien Mazarguil #endif 558a5bf6af9SAdrien Mazarguil ++j; 559a5bf6af9SAdrien Mazarguil } 560a5bf6af9SAdrien Mazarguil /* Update DS field in WQE. */ 5618688b2f8SNélio Laranjeiro wqe->ctrl[1] &= htonl(0xffffffc0); 5628688b2f8SNélio Laranjeiro wqe->ctrl[1] |= htonl(ds & 0x3f); 5630e8679fcSNélio Laranjeiro skip_segs: 56487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 565573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 566573f54afSNélio Laranjeiro txq->stats.obytes += length; 56787011737SAdrien Mazarguil #endif 5680e8679fcSNélio Laranjeiro /* Increment consumer index. */ 5690e8679fcSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 5702e22920bSAdrien Mazarguil elts_head = elts_head_next; 571c3d62cc9SAdrien Mazarguil ++i; 572c3d62cc9SAdrien Mazarguil } while (pkts_n); 5732e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 5742e22920bSAdrien Mazarguil if (unlikely(i == 0)) 5752e22920bSAdrien Mazarguil return 0; 576c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 577a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + i + j; 578c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 579c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 5808688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 581c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 5828688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 583c305090bSAdrien Mazarguil txq->elts_comp = 0; 584c305090bSAdrien Mazarguil } else { 585c305090bSAdrien Mazarguil txq->elts_comp = comp; 586c305090bSAdrien Mazarguil } 58787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 58887011737SAdrien Mazarguil /* Increment sent packets counter. */ 58987011737SAdrien Mazarguil txq->stats.opackets += i; 59087011737SAdrien Mazarguil #endif 5912e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 5921d88ba17SNélio Laranjeiro mlx5_tx_dbrec(txq); 5932e22920bSAdrien Mazarguil txq->elts_head = elts_head; 5942e22920bSAdrien Mazarguil return i; 5952e22920bSAdrien Mazarguil } 5962e22920bSAdrien Mazarguil 5972e22920bSAdrien Mazarguil /** 598230189d9SNélio Laranjeiro * Open a MPW session. 599230189d9SNélio Laranjeiro * 600230189d9SNélio Laranjeiro * @param txq 601230189d9SNélio Laranjeiro * Pointer to TX queue structure. 602230189d9SNélio Laranjeiro * @param mpw 603230189d9SNélio Laranjeiro * Pointer to MPW session structure. 604230189d9SNélio Laranjeiro * @param length 605230189d9SNélio Laranjeiro * Packet length. 606230189d9SNélio Laranjeiro */ 607230189d9SNélio Laranjeiro static inline void 608230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 609230189d9SNélio Laranjeiro { 610230189d9SNélio Laranjeiro uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1); 611230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 612230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 613230189d9SNélio Laranjeiro (uintptr_t)&(*txq->wqes)[(idx + 1) & (txq->wqe_n - 1)]; 614230189d9SNélio Laranjeiro 615230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 616230189d9SNélio Laranjeiro mpw->pkts_n = 0; 617230189d9SNélio Laranjeiro mpw->len = length; 618230189d9SNélio Laranjeiro mpw->total_len = 0; 6198688b2f8SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)&(*txq->wqes)[idx].hdr; 6208688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 6218688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 6228688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 6238688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 6248688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 6258688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 6268688b2f8SNélio Laranjeiro (txq->wqe_ci << 8) | MLX5_OPCODE_LSO_MPW); 6278688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 6288688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 6298688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 6308688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 6318688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 6328688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 633230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 634230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 635230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 636230189d9SNélio Laranjeiro } 637230189d9SNélio Laranjeiro 638230189d9SNélio Laranjeiro /** 639230189d9SNélio Laranjeiro * Close a MPW session. 640230189d9SNélio Laranjeiro * 641230189d9SNélio Laranjeiro * @param txq 642230189d9SNélio Laranjeiro * Pointer to TX queue structure. 643230189d9SNélio Laranjeiro * @param mpw 644230189d9SNélio Laranjeiro * Pointer to MPW session structure. 645230189d9SNélio Laranjeiro */ 646230189d9SNélio Laranjeiro static inline void 647230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 648230189d9SNélio Laranjeiro { 649230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 650230189d9SNélio Laranjeiro 651230189d9SNélio Laranjeiro /* 652230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 653230189d9SNélio Laranjeiro * count as 2. 654230189d9SNélio Laranjeiro */ 6558688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num)); 656230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 657230189d9SNélio Laranjeiro if (num < 3) 658230189d9SNélio Laranjeiro ++txq->wqe_ci; 659230189d9SNélio Laranjeiro else 660230189d9SNélio Laranjeiro txq->wqe_ci += 2; 661230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 662230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 663230189d9SNélio Laranjeiro } 664230189d9SNélio Laranjeiro 665230189d9SNélio Laranjeiro /** 666230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 667230189d9SNélio Laranjeiro * 668230189d9SNélio Laranjeiro * @param dpdk_txq 669230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 670230189d9SNélio Laranjeiro * @param[in] pkts 671230189d9SNélio Laranjeiro * Packets to transmit. 672230189d9SNélio Laranjeiro * @param pkts_n 673230189d9SNélio Laranjeiro * Number of packets in array. 674230189d9SNélio Laranjeiro * 675230189d9SNélio Laranjeiro * @return 676230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 677230189d9SNélio Laranjeiro */ 678230189d9SNélio Laranjeiro uint16_t 679230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 680230189d9SNélio Laranjeiro { 681230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 682230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 683*b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 684c3d62cc9SAdrien Mazarguil unsigned int i = 0; 685a5bf6af9SAdrien Mazarguil unsigned int j = 0; 686230189d9SNélio Laranjeiro unsigned int max; 687230189d9SNélio Laranjeiro unsigned int comp; 688230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 689230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 690230189d9SNélio Laranjeiro }; 691230189d9SNélio Laranjeiro 692c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 693c3d62cc9SAdrien Mazarguil return 0; 694230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 695230189d9SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 696230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 697230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 698230189d9SNélio Laranjeiro /* Start processing. */ 699230189d9SNélio Laranjeiro txq_complete(txq); 700230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 701230189d9SNélio Laranjeiro if (max > elts_n) 702230189d9SNélio Laranjeiro max -= elts_n; 703c3d62cc9SAdrien Mazarguil do { 704a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 705c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 706230189d9SNélio Laranjeiro uint32_t length; 707a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 708230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 709230189d9SNélio Laranjeiro 710c3d62cc9SAdrien Mazarguil /* 711c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 712c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 713c3d62cc9SAdrien Mazarguil */ 714a5bf6af9SAdrien Mazarguil assert(segs_n); 715a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 716c3d62cc9SAdrien Mazarguil break; 717a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 718a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 719a5bf6af9SAdrien Mazarguil break; 720a5bf6af9SAdrien Mazarguil max -= segs_n; 721c3d62cc9SAdrien Mazarguil --pkts_n; 722230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 723230189d9SNélio Laranjeiro if (buf->ol_flags & 724230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 725230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 726a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 727a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 728a5bf6af9SAdrien Mazarguil assert(length); 729230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 730230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 731230189d9SNélio Laranjeiro ((mpw.len != length) || 732a5bf6af9SAdrien Mazarguil (segs_n != 1) || 7338688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 734230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 735230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 736230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 7378688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 738230189d9SNélio Laranjeiro } 739a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 740a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 741a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 742a5bf6af9SAdrien Mazarguil length = 0; 743a5bf6af9SAdrien Mazarguil #endif 744a5bf6af9SAdrien Mazarguil do { 745a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 746a5bf6af9SAdrien Mazarguil uintptr_t addr; 747a5bf6af9SAdrien Mazarguil 748a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 749a5bf6af9SAdrien Mazarguil assert(buf); 750a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 751230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 752a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 753230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 754a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 755230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 756230189d9SNélio Laranjeiro .addr = htonll(addr), 757230189d9SNélio Laranjeiro }; 758a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 759a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 760a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 761a5bf6af9SAdrien Mazarguil #endif 762a5bf6af9SAdrien Mazarguil buf = buf->next; 763230189d9SNélio Laranjeiro ++mpw.pkts_n; 764a5bf6af9SAdrien Mazarguil ++j; 765a5bf6af9SAdrien Mazarguil } while (--segs_n); 766a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 767230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 768230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 769230189d9SNélio Laranjeiro elts_head = elts_head_next; 770230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 771230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 772230189d9SNélio Laranjeiro txq->stats.obytes += length; 773230189d9SNélio Laranjeiro #endif 774c3d62cc9SAdrien Mazarguil ++i; 775c3d62cc9SAdrien Mazarguil } while (pkts_n); 776230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 777230189d9SNélio Laranjeiro if (unlikely(i == 0)) 778230189d9SNélio Laranjeiro return 0; 779230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 780a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 781a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 782230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 7838688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 784230189d9SNélio Laranjeiro 785230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 7868688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 787230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 7888688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 789230189d9SNélio Laranjeiro txq->elts_comp = 0; 790230189d9SNélio Laranjeiro } else { 791230189d9SNélio Laranjeiro txq->elts_comp = comp; 792230189d9SNélio Laranjeiro } 793230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 794230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 795230189d9SNélio Laranjeiro txq->stats.opackets += i; 796230189d9SNélio Laranjeiro #endif 797230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 798230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 799230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 800230189d9SNélio Laranjeiro mlx5_tx_dbrec(txq); 801230189d9SNélio Laranjeiro txq->elts_head = elts_head; 802230189d9SNélio Laranjeiro return i; 803230189d9SNélio Laranjeiro } 804230189d9SNélio Laranjeiro 805230189d9SNélio Laranjeiro /** 806230189d9SNélio Laranjeiro * Open a MPW inline session. 807230189d9SNélio Laranjeiro * 808230189d9SNélio Laranjeiro * @param txq 809230189d9SNélio Laranjeiro * Pointer to TX queue structure. 810230189d9SNélio Laranjeiro * @param mpw 811230189d9SNélio Laranjeiro * Pointer to MPW session structure. 812230189d9SNélio Laranjeiro * @param length 813230189d9SNélio Laranjeiro * Packet length. 814230189d9SNélio Laranjeiro */ 815230189d9SNélio Laranjeiro static inline void 816230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 817230189d9SNélio Laranjeiro { 818230189d9SNélio Laranjeiro uint16_t idx = txq->wqe_ci & (txq->wqe_n - 1); 8198688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 820230189d9SNélio Laranjeiro 821230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 822230189d9SNélio Laranjeiro mpw->pkts_n = 0; 823230189d9SNélio Laranjeiro mpw->len = length; 824230189d9SNélio Laranjeiro mpw->total_len = 0; 8258688b2f8SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)&(*txq->wqes)[idx].hdr; 8268688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 827230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 828230189d9SNélio Laranjeiro MLX5_OPCODE_LSO_MPW); 8298688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 8308688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 8318688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 8328688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 8338688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 8348688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 8358688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 8368688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 8378688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 8388688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 8398688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 840230189d9SNélio Laranjeiro } 841230189d9SNélio Laranjeiro 842230189d9SNélio Laranjeiro /** 843230189d9SNélio Laranjeiro * Close a MPW inline session. 844230189d9SNélio Laranjeiro * 845230189d9SNélio Laranjeiro * @param txq 846230189d9SNélio Laranjeiro * Pointer to TX queue structure. 847230189d9SNélio Laranjeiro * @param mpw 848230189d9SNélio Laranjeiro * Pointer to MPW session structure. 849230189d9SNélio Laranjeiro */ 850230189d9SNélio Laranjeiro static inline void 851230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 852230189d9SNélio Laranjeiro { 853230189d9SNélio Laranjeiro unsigned int size; 8548688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 8558688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 856230189d9SNélio Laranjeiro 8578688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 858230189d9SNélio Laranjeiro /* 859230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 860230189d9SNélio Laranjeiro * count as 2. 861230189d9SNélio Laranjeiro */ 8628688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size)); 863230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 8648688b2f8SNélio Laranjeiro inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 8658688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 866230189d9SNélio Laranjeiro } 867230189d9SNélio Laranjeiro 868230189d9SNélio Laranjeiro /** 869230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 870230189d9SNélio Laranjeiro * 871230189d9SNélio Laranjeiro * @param dpdk_txq 872230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 873230189d9SNélio Laranjeiro * @param[in] pkts 874230189d9SNélio Laranjeiro * Packets to transmit. 875230189d9SNélio Laranjeiro * @param pkts_n 876230189d9SNélio Laranjeiro * Number of packets in array. 877230189d9SNélio Laranjeiro * 878230189d9SNélio Laranjeiro * @return 879230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 880230189d9SNélio Laranjeiro */ 881230189d9SNélio Laranjeiro uint16_t 882230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 883230189d9SNélio Laranjeiro uint16_t pkts_n) 884230189d9SNélio Laranjeiro { 885230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 886230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 887*b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 888c3d62cc9SAdrien Mazarguil unsigned int i = 0; 889a5bf6af9SAdrien Mazarguil unsigned int j = 0; 890230189d9SNélio Laranjeiro unsigned int max; 891230189d9SNélio Laranjeiro unsigned int comp; 8920e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 893230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 894230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 895230189d9SNélio Laranjeiro }; 896230189d9SNélio Laranjeiro 897c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 898c3d62cc9SAdrien Mazarguil return 0; 899230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 900230189d9SNélio Laranjeiro tx_prefetch_cqe(txq, txq->cq_ci); 901230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci); 902230189d9SNélio Laranjeiro tx_prefetch_wqe(txq, txq->wqe_ci + 1); 903230189d9SNélio Laranjeiro /* Start processing. */ 904230189d9SNélio Laranjeiro txq_complete(txq); 905230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 906230189d9SNélio Laranjeiro if (max > elts_n) 907230189d9SNélio Laranjeiro max -= elts_n; 908c3d62cc9SAdrien Mazarguil do { 909a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 910c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 911230189d9SNélio Laranjeiro uintptr_t addr; 912230189d9SNélio Laranjeiro uint32_t length; 913a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 914230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 915230189d9SNélio Laranjeiro 916c3d62cc9SAdrien Mazarguil /* 917c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 918c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 919c3d62cc9SAdrien Mazarguil */ 920a5bf6af9SAdrien Mazarguil assert(segs_n); 921a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 922c3d62cc9SAdrien Mazarguil break; 923a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 924a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 925a5bf6af9SAdrien Mazarguil break; 926a5bf6af9SAdrien Mazarguil max -= segs_n; 927c3d62cc9SAdrien Mazarguil --pkts_n; 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; 932a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 933a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 934230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 935230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 936230189d9SNélio Laranjeiro if ((mpw.len != length) || 937a5bf6af9SAdrien Mazarguil (segs_n != 1) || 9388688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 939230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 940230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 941230189d9SNélio Laranjeiro if ((mpw.len != length) || 942a5bf6af9SAdrien Mazarguil (segs_n != 1) || 943230189d9SNélio Laranjeiro (length > inline_room) || 9448688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 945230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 9460e8679fcSNélio Laranjeiro inline_room = 9470e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 948230189d9SNélio Laranjeiro } 949230189d9SNélio Laranjeiro } 950230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 951a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 952a5bf6af9SAdrien Mazarguil (length > inline_room)) { 953230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 9548688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 955230189d9SNélio Laranjeiro } else { 956230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 9578688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 958230189d9SNélio Laranjeiro } 959230189d9SNélio Laranjeiro } 960a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 961a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 962230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 9630e8679fcSNélio Laranjeiro assert(inline_room == 9640e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 965a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 966a5bf6af9SAdrien Mazarguil length = 0; 967a5bf6af9SAdrien Mazarguil #endif 968a5bf6af9SAdrien Mazarguil do { 969230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 970230189d9SNélio Laranjeiro 971a5bf6af9SAdrien Mazarguil elts_head_next = 972a5bf6af9SAdrien Mazarguil (elts_head + 1) & (elts_n - 1); 973a5bf6af9SAdrien Mazarguil assert(buf); 974a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 975230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 976a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 977230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 978a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 979230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 980230189d9SNélio Laranjeiro .addr = htonll(addr), 981230189d9SNélio Laranjeiro }; 982a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 983a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 984a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 985a5bf6af9SAdrien Mazarguil #endif 986a5bf6af9SAdrien Mazarguil buf = buf->next; 987230189d9SNélio Laranjeiro ++mpw.pkts_n; 988a5bf6af9SAdrien Mazarguil ++j; 989a5bf6af9SAdrien Mazarguil } while (--segs_n); 990a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 991230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 992230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 993230189d9SNélio Laranjeiro } else { 994230189d9SNélio Laranjeiro unsigned int max; 995230189d9SNélio Laranjeiro 996230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 997230189d9SNélio Laranjeiro assert(length <= inline_room); 998a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 999a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1000a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1001a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1002230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1003230189d9SNélio Laranjeiro max = ((uintptr_t)&(*txq->wqes)[txq->wqe_n] - 1004230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1005230189d9SNélio Laranjeiro if (length > max) { 1006230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1007230189d9SNélio Laranjeiro (void *)addr, 1008230189d9SNélio Laranjeiro max); 1009230189d9SNélio Laranjeiro mpw.data.raw = 1010230189d9SNélio Laranjeiro (volatile void *)&(*txq->wqes)[0]; 1011230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1012230189d9SNélio Laranjeiro (void *)(addr + max), 1013230189d9SNélio Laranjeiro length - max); 1014230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1015230189d9SNélio Laranjeiro } else { 1016230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1017230189d9SNélio Laranjeiro (void *)addr, 1018230189d9SNélio Laranjeiro length); 1019230189d9SNélio Laranjeiro mpw.data.raw += length; 1020230189d9SNélio Laranjeiro } 1021230189d9SNélio Laranjeiro if ((uintptr_t)mpw.data.raw == 1022230189d9SNélio Laranjeiro (uintptr_t)&(*txq->wqes)[txq->wqe_n]) 1023230189d9SNélio Laranjeiro mpw.data.raw = 1024230189d9SNélio Laranjeiro (volatile void *)&(*txq->wqes)[0]; 1025230189d9SNélio Laranjeiro ++mpw.pkts_n; 1026a5bf6af9SAdrien Mazarguil ++j; 1027230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1028230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 10290e8679fcSNélio Laranjeiro inline_room = 10300e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1031230189d9SNélio Laranjeiro } else { 1032230189d9SNélio Laranjeiro inline_room -= length; 1033230189d9SNélio Laranjeiro } 1034230189d9SNélio Laranjeiro } 1035230189d9SNélio Laranjeiro mpw.total_len += length; 1036230189d9SNélio Laranjeiro elts_head = elts_head_next; 1037230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1038230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1039230189d9SNélio Laranjeiro txq->stats.obytes += length; 1040230189d9SNélio Laranjeiro #endif 1041c3d62cc9SAdrien Mazarguil ++i; 1042c3d62cc9SAdrien Mazarguil } while (pkts_n); 1043230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1044230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1045230189d9SNélio Laranjeiro return 0; 1046230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1047a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1048a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1049230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 10508688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1051230189d9SNélio Laranjeiro 1052230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 10538688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1054230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 10558688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1056230189d9SNélio Laranjeiro txq->elts_comp = 0; 1057230189d9SNélio Laranjeiro } else { 1058230189d9SNélio Laranjeiro txq->elts_comp = comp; 1059230189d9SNélio Laranjeiro } 1060230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1061230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1062230189d9SNélio Laranjeiro txq->stats.opackets += i; 1063230189d9SNélio Laranjeiro #endif 1064230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1065230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1066230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1067230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1068230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1069230189d9SNélio Laranjeiro mlx5_tx_dbrec(txq); 1070230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1071230189d9SNélio Laranjeiro return i; 1072230189d9SNélio Laranjeiro } 1073230189d9SNélio Laranjeiro 1074230189d9SNélio Laranjeiro /** 107567fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 107667fa62bcSAdrien Mazarguil * 10776218063bSNélio Laranjeiro * @param[in] cqe 10786218063bSNélio Laranjeiro * Pointer to CQE. 107967fa62bcSAdrien Mazarguil * 108078a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 108178a38edfSJianfeng Tan * 108267fa62bcSAdrien Mazarguil * @return 108367fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 108467fa62bcSAdrien Mazarguil */ 108567fa62bcSAdrien Mazarguil static inline uint32_t 10866218063bSNélio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe64 *cqe) 108767fa62bcSAdrien Mazarguil { 108867fa62bcSAdrien Mazarguil uint32_t pkt_type; 10896218063bSNélio Laranjeiro uint8_t flags = cqe->l4_hdr_type_etc; 10906218063bSNélio Laranjeiro uint8_t info = cqe->rsvd0[0]; 109167fa62bcSAdrien Mazarguil 10926218063bSNélio Laranjeiro if (info & IBV_EXP_CQ_RX_TUNNEL_PACKET) 109367fa62bcSAdrien Mazarguil pkt_type = 109467fa62bcSAdrien Mazarguil TRANSPOSE(flags, 109567fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV4_PACKET, 109667fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV4) | 109767fa62bcSAdrien Mazarguil TRANSPOSE(flags, 109867fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IPV6_PACKET, 109967fa62bcSAdrien Mazarguil RTE_PTYPE_L3_IPV6) | 110067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 110167fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV4_PACKET, 110267fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV4) | 110367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 110467fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_IPV6_PACKET, 110567fa62bcSAdrien Mazarguil RTE_PTYPE_INNER_L3_IPV6); 110667fa62bcSAdrien Mazarguil else 110767fa62bcSAdrien Mazarguil pkt_type = 110867fa62bcSAdrien Mazarguil TRANSPOSE(flags, 11096218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 11106218063bSNélio Laranjeiro RTE_PTYPE_L3_IPV6) | 111167fa62bcSAdrien Mazarguil TRANSPOSE(flags, 11126218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 11136218063bSNélio Laranjeiro RTE_PTYPE_L3_IPV4); 111467fa62bcSAdrien Mazarguil return pkt_type; 111567fa62bcSAdrien Mazarguil } 111667fa62bcSAdrien Mazarguil 111767fa62bcSAdrien Mazarguil /** 111899c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 111999c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 112099c12dccSNélio Laranjeiro * been processed. 112199c12dccSNélio Laranjeiro * 112299c12dccSNélio Laranjeiro * @param rxq 112399c12dccSNélio Laranjeiro * Pointer to RX queue. 112499c12dccSNélio Laranjeiro * @param cqe 112599c12dccSNélio Laranjeiro * CQE to process. 112699c12dccSNélio Laranjeiro * 112799c12dccSNélio Laranjeiro * @return 112899c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 112999c12dccSNélio Laranjeiro * with error. 113099c12dccSNélio Laranjeiro */ 113199c12dccSNélio Laranjeiro static inline int 113299c12dccSNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe, 113399c12dccSNélio Laranjeiro uint16_t cqe_cnt) 113499c12dccSNélio Laranjeiro { 113599c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 113699c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 113799c12dccSNélio Laranjeiro int len = 0; 113899c12dccSNélio Laranjeiro 113999c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 114099c12dccSNélio Laranjeiro if (zip->ai) { 114199c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 114299c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 114399c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].cqe64); 114499c12dccSNélio Laranjeiro 114599c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 114699c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 114799c12dccSNélio Laranjeiro /* 114899c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 114999c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 115099c12dccSNélio Laranjeiro * ring for software use. 115199c12dccSNélio Laranjeiro */ 115299c12dccSNélio Laranjeiro zip->ca = zip->na; 115399c12dccSNélio Laranjeiro zip->na += 8; 115499c12dccSNélio Laranjeiro } 115599c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 115699c12dccSNélio Laranjeiro uint16_t idx = rxq->cq_ci; 115799c12dccSNélio Laranjeiro uint16_t end = zip->cq_ci; 115899c12dccSNélio Laranjeiro 115999c12dccSNélio Laranjeiro while (idx != end) { 116099c12dccSNélio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].cqe64.op_own = 116199c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 116299c12dccSNélio Laranjeiro ++idx; 116399c12dccSNélio Laranjeiro } 116499c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 116599c12dccSNélio Laranjeiro zip->ai = 0; 116699c12dccSNélio Laranjeiro } 116799c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 116899c12dccSNélio Laranjeiro } else { 116999c12dccSNélio Laranjeiro int ret; 117099c12dccSNélio Laranjeiro int8_t op_own; 117199c12dccSNélio Laranjeiro 117299c12dccSNélio Laranjeiro ret = check_cqe64(cqe, cqe_n, rxq->cq_ci); 117399c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 117499c12dccSNélio Laranjeiro return 0; 117599c12dccSNélio Laranjeiro ++rxq->cq_ci; 117699c12dccSNélio Laranjeiro op_own = cqe->op_own; 117799c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 117899c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 117999c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 118099c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 118199c12dccSNélio Laranjeiro cqe_cnt].cqe64); 118299c12dccSNélio Laranjeiro 118399c12dccSNélio Laranjeiro /* Fix endianness. */ 118499c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 118599c12dccSNélio Laranjeiro /* 118699c12dccSNélio Laranjeiro * Current mini array position is the one returned by 118799c12dccSNélio Laranjeiro * check_cqe64(). 118899c12dccSNélio Laranjeiro * 118999c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 119099c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 119199c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 119299c12dccSNélio Laranjeiro */ 119399c12dccSNélio Laranjeiro zip->ca = rxq->cq_ci & cqe_cnt; 119499c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 119599c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 119699c12dccSNélio Laranjeiro --rxq->cq_ci; 119799c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 119899c12dccSNélio Laranjeiro /* Get packet size to return. */ 119999c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 120099c12dccSNélio Laranjeiro zip->ai = 1; 120199c12dccSNélio Laranjeiro } else { 120299c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 120399c12dccSNélio Laranjeiro } 120499c12dccSNélio Laranjeiro /* Error while receiving packet. */ 120599c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 120699c12dccSNélio Laranjeiro return -1; 120799c12dccSNélio Laranjeiro } 120899c12dccSNélio Laranjeiro return len; 120999c12dccSNélio Laranjeiro } 121099c12dccSNélio Laranjeiro 121199c12dccSNélio Laranjeiro /** 121267fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 121367fa62bcSAdrien Mazarguil * 121467fa62bcSAdrien Mazarguil * @param[in] rxq 121567fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 12166218063bSNélio Laranjeiro * @param[in] cqe 12176218063bSNélio Laranjeiro * Pointer to CQE. 121867fa62bcSAdrien Mazarguil * 121967fa62bcSAdrien Mazarguil * @return 122067fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 122167fa62bcSAdrien Mazarguil */ 122267fa62bcSAdrien Mazarguil static inline uint32_t 12236218063bSNélio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe64 *cqe) 122467fa62bcSAdrien Mazarguil { 122567fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 12266218063bSNélio Laranjeiro uint8_t l3_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L3_HDR_TYPE_MASK; 12276218063bSNélio Laranjeiro uint8_t l4_hdr = (cqe->l4_hdr_type_etc) & MLX5_CQE_L4_HDR_TYPE_MASK; 12286218063bSNélio Laranjeiro uint8_t info = cqe->rsvd0[0]; 122967fa62bcSAdrien Mazarguil 12306218063bSNélio Laranjeiro if ((l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV4) || 12316218063bSNélio Laranjeiro (l3_hdr == MLX5_CQE_L3_HDR_TYPE_IPV6)) 123267fa62bcSAdrien Mazarguil ol_flags |= 12336218063bSNélio Laranjeiro (!(cqe->hds_ip_ext & MLX5_CQE_L3_OK) * 1234d0087d76SYaacov Hazan PKT_RX_IP_CKSUM_BAD); 12356218063bSNélio Laranjeiro if ((l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP) || 12366218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_EMP_ACK) || 12376218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_TCP_ACK) || 12386218063bSNélio Laranjeiro (l4_hdr == MLX5_CQE_L4_HDR_TYPE_UDP)) 1239d0087d76SYaacov Hazan ol_flags |= 12406218063bSNélio Laranjeiro (!(cqe->hds_ip_ext & MLX5_CQE_L4_OK) * 124167fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 124267fa62bcSAdrien Mazarguil /* 124367fa62bcSAdrien Mazarguil * PKT_RX_IP_CKSUM_BAD and PKT_RX_L4_CKSUM_BAD are used in place 124467fa62bcSAdrien Mazarguil * of PKT_RX_EIP_CKSUM_BAD because the latter is not functional 124567fa62bcSAdrien Mazarguil * (its value is 0). 124667fa62bcSAdrien Mazarguil */ 12476218063bSNélio Laranjeiro if ((info & IBV_EXP_CQ_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 124867fa62bcSAdrien Mazarguil ol_flags |= 12496218063bSNélio Laranjeiro TRANSPOSE(~cqe->l4_hdr_type_etc, 125067fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_IP_CSUM_OK, 125167fa62bcSAdrien Mazarguil PKT_RX_IP_CKSUM_BAD) | 12526218063bSNélio Laranjeiro TRANSPOSE(~cqe->l4_hdr_type_etc, 125367fa62bcSAdrien Mazarguil IBV_EXP_CQ_RX_OUTER_TCP_UDP_CSUM_OK, 125467fa62bcSAdrien Mazarguil PKT_RX_L4_CKSUM_BAD); 125567fa62bcSAdrien Mazarguil return ol_flags; 125667fa62bcSAdrien Mazarguil } 125767fa62bcSAdrien Mazarguil 125867fa62bcSAdrien Mazarguil /** 12592e22920bSAdrien Mazarguil * DPDK callback for RX. 12602e22920bSAdrien Mazarguil * 12612e22920bSAdrien Mazarguil * @param dpdk_rxq 12622e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 12632e22920bSAdrien Mazarguil * @param[out] pkts 12642e22920bSAdrien Mazarguil * Array to store received packets. 12652e22920bSAdrien Mazarguil * @param pkts_n 12662e22920bSAdrien Mazarguil * Maximum number of packets in array. 12672e22920bSAdrien Mazarguil * 12682e22920bSAdrien Mazarguil * @return 12692e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 12702e22920bSAdrien Mazarguil */ 12712e22920bSAdrien Mazarguil uint16_t 12722e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 12732e22920bSAdrien Mazarguil { 12746218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 127599c12dccSNélio Laranjeiro const unsigned int cqe_cnt = rxq->cqe_n - 1; 1276*b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 12779964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 12789964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 12799964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 12806218063bSNélio Laranjeiro volatile struct mlx5_cqe64 *cqe = 128199c12dccSNélio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64; 12829964b965SNélio Laranjeiro unsigned int i = 0; 12839964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 12849964b965SNélio Laranjeiro int len; 12852e22920bSAdrien Mazarguil 12869964b965SNélio Laranjeiro while (pkts_n) { 12879964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 12889964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 12899964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 12909964b965SNélio Laranjeiro 12919964b965SNélio Laranjeiro if (pkt) 12929964b965SNélio Laranjeiro NEXT(seg) = rep; 12939964b965SNélio Laranjeiro seg = rep; 12949964b965SNélio Laranjeiro rte_prefetch0(seg); 12956218063bSNélio Laranjeiro rte_prefetch0(cqe); 12969964b965SNélio Laranjeiro rte_prefetch0(wqe); 1297fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 12982e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 129915a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 130015a756b6SSagi Grimberg if (!pkt) { 130115a756b6SSagi Grimberg /* 130215a756b6SSagi Grimberg * no buffers before we even started, 130315a756b6SSagi Grimberg * bail out silently. 130415a756b6SSagi Grimberg */ 130515a756b6SSagi Grimberg break; 130615a756b6SSagi Grimberg } 1307a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1308a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 13099964b965SNélio Laranjeiro seg = NEXT(pkt); 13109964b965SNélio Laranjeiro rte_mbuf_refcnt_set(pkt, 0); 13119964b965SNélio Laranjeiro __rte_mbuf_raw_free(pkt); 13129964b965SNélio Laranjeiro pkt = seg; 13139964b965SNélio Laranjeiro } 13146218063bSNélio Laranjeiro break; 13152e22920bSAdrien Mazarguil } 13169964b965SNélio Laranjeiro if (!pkt) { 13179964b965SNélio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt].cqe64; 131899c12dccSNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt); 13199964b965SNélio Laranjeiro if (len == 0) { 13206218063bSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 13216218063bSNélio Laranjeiro __rte_mbuf_raw_free(rep); 13226218063bSNélio Laranjeiro break; 13236218063bSNélio Laranjeiro } 132499c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 132599c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 132699c12dccSNélio Laranjeiro rte_mbuf_refcnt_set(rep, 0); 132799c12dccSNélio Laranjeiro __rte_mbuf_raw_free(rep); 132899c12dccSNélio Laranjeiro ++rxq->stats.idropped; 132999c12dccSNélio Laranjeiro goto skip; 133099c12dccSNélio Laranjeiro } 13319964b965SNélio Laranjeiro pkt = seg; 13329964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 13339964b965SNélio Laranjeiro /* Update packet information. */ 13340ac64846SMaxime Leroy pkt->packet_type = 0; 13350ac64846SMaxime Leroy pkt->ol_flags = 0; 13366218063bSNélio Laranjeiro if (rxq->csum | rxq->csum_l2tun | rxq->vlan_strip | 13376218063bSNélio Laranjeiro rxq->crc_present) { 13386218063bSNélio Laranjeiro if (rxq->csum) { 13399964b965SNélio Laranjeiro pkt->packet_type = 13409964b965SNélio Laranjeiro rxq_cq_to_pkt_type(cqe); 13419964b965SNélio Laranjeiro pkt->ol_flags = 13429964b965SNélio Laranjeiro rxq_cq_to_ol_flags(rxq, cqe); 13436218063bSNélio Laranjeiro } 13449964b965SNélio Laranjeiro if (cqe->l4_hdr_type_etc & 13459964b965SNélio Laranjeiro MLX5_CQE_VLAN_STRIPPED) { 13466218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1347b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 13486218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 1349f3db9489SYaacov Hazan } 13506218063bSNélio Laranjeiro if (rxq->crc_present) 13516218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 1352081f7eaeSNelio Laranjeiro } 13536218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 13549964b965SNélio Laranjeiro } 13559964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 13569964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 13579964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 13589964b965SNélio Laranjeiro NB_SEGS(rep) = NB_SEGS(seg); 13599964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 13609964b965SNélio Laranjeiro NEXT(rep) = NULL; 13619964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 13629964b965SNélio Laranjeiro /* 13639964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 13649964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 13659964b965SNélio Laranjeiro * changes. 13669964b965SNélio Laranjeiro */ 13679964b965SNélio Laranjeiro wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t)); 13689964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 13699964b965SNélio Laranjeiro len -= DATA_LEN(seg); 13709964b965SNélio Laranjeiro ++NB_SEGS(pkt); 13719964b965SNélio Laranjeiro ++rq_ci; 13729964b965SNélio Laranjeiro continue; 13739964b965SNélio Laranjeiro } 13749964b965SNélio Laranjeiro DATA_LEN(seg) = len; 137587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 137687011737SAdrien Mazarguil /* Increment bytes counter. */ 13779964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 137887011737SAdrien Mazarguil #endif 13796218063bSNélio Laranjeiro /* Return packet. */ 13806218063bSNélio Laranjeiro *(pkts++) = pkt; 13819964b965SNélio Laranjeiro pkt = NULL; 13829964b965SNélio Laranjeiro --pkts_n; 13839964b965SNélio Laranjeiro ++i; 138499c12dccSNélio Laranjeiro skip: 13859964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 13869964b965SNélio Laranjeiro rq_ci >>= sges_n; 13876218063bSNélio Laranjeiro ++rq_ci; 13889964b965SNélio Laranjeiro rq_ci <<= sges_n; 13892e22920bSAdrien Mazarguil } 13909964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 13912e22920bSAdrien Mazarguil return 0; 13926218063bSNélio Laranjeiro /* Update the consumer index. */ 13939964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 13946218063bSNélio Laranjeiro rte_wmb(); 13956218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 13966218063bSNélio Laranjeiro rte_wmb(); 13976218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 139887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 139987011737SAdrien Mazarguil /* Increment packets counter. */ 14009964b965SNélio Laranjeiro rxq->stats.ipackets += i; 140187011737SAdrien Mazarguil #endif 14029964b965SNélio Laranjeiro return i; 14032e22920bSAdrien Mazarguil } 14042e22920bSAdrien Mazarguil 14052e22920bSAdrien Mazarguil /** 14062e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 14072e22920bSAdrien Mazarguil * 14082e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 14092e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 14102e22920bSAdrien Mazarguil * 14112e22920bSAdrien Mazarguil * @param dpdk_txq 14122e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 14132e22920bSAdrien Mazarguil * @param[in] pkts 14142e22920bSAdrien Mazarguil * Packets to transmit. 14152e22920bSAdrien Mazarguil * @param pkts_n 14162e22920bSAdrien Mazarguil * Number of packets in array. 14172e22920bSAdrien Mazarguil * 14182e22920bSAdrien Mazarguil * @return 14192e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 14202e22920bSAdrien Mazarguil */ 14212e22920bSAdrien Mazarguil uint16_t 14222e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 14232e22920bSAdrien Mazarguil { 14242e22920bSAdrien Mazarguil (void)dpdk_txq; 14252e22920bSAdrien Mazarguil (void)pkts; 14262e22920bSAdrien Mazarguil (void)pkts_n; 14272e22920bSAdrien Mazarguil return 0; 14282e22920bSAdrien Mazarguil } 14292e22920bSAdrien Mazarguil 14302e22920bSAdrien Mazarguil /** 14312e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 14322e22920bSAdrien Mazarguil * 14332e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 14342e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 14352e22920bSAdrien Mazarguil * 14362e22920bSAdrien Mazarguil * @param dpdk_rxq 14372e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 14382e22920bSAdrien Mazarguil * @param[out] pkts 14392e22920bSAdrien Mazarguil * Array to store received packets. 14402e22920bSAdrien Mazarguil * @param pkts_n 14412e22920bSAdrien Mazarguil * Maximum number of packets in array. 14422e22920bSAdrien Mazarguil * 14432e22920bSAdrien Mazarguil * @return 14442e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 14452e22920bSAdrien Mazarguil */ 14462e22920bSAdrien Mazarguil uint16_t 14472e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 14482e22920bSAdrien Mazarguil { 14492e22920bSAdrien Mazarguil (void)dpdk_rxq; 14502e22920bSAdrien Mazarguil (void)pkts; 14512e22920bSAdrien Mazarguil (void)pkts_n; 14522e22920bSAdrien Mazarguil return 0; 14532e22920bSAdrien Mazarguil } 1454