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 /** 1986ce84bd8SYongseok Koh * Return the size of tailroom of WQ. 1996ce84bd8SYongseok Koh * 2006ce84bd8SYongseok Koh * @param txq 2016ce84bd8SYongseok Koh * Pointer to TX queue structure. 2026ce84bd8SYongseok Koh * @param addr 2036ce84bd8SYongseok Koh * Pointer to tail of WQ. 2046ce84bd8SYongseok Koh * 2056ce84bd8SYongseok Koh * @return 2066ce84bd8SYongseok Koh * Size of tailroom. 2076ce84bd8SYongseok Koh */ 2086ce84bd8SYongseok Koh static inline size_t 2096ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr) 2106ce84bd8SYongseok Koh { 2116ce84bd8SYongseok Koh size_t tailroom; 2126ce84bd8SYongseok Koh tailroom = (uintptr_t)(txq->wqes) + 2136ce84bd8SYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE - 2146ce84bd8SYongseok Koh (uintptr_t)addr; 2156ce84bd8SYongseok Koh return tailroom; 2166ce84bd8SYongseok Koh } 2176ce84bd8SYongseok Koh 2186ce84bd8SYongseok Koh /** 2196ce84bd8SYongseok Koh * Copy data to tailroom of circular queue. 2206ce84bd8SYongseok Koh * 2216ce84bd8SYongseok Koh * @param dst 2226ce84bd8SYongseok Koh * Pointer to destination. 2236ce84bd8SYongseok Koh * @param src 2246ce84bd8SYongseok Koh * Pointer to source. 2256ce84bd8SYongseok Koh * @param n 2266ce84bd8SYongseok Koh * Number of bytes to copy. 2276ce84bd8SYongseok Koh * @param base 2286ce84bd8SYongseok Koh * Pointer to head of queue. 2296ce84bd8SYongseok Koh * @param tailroom 2306ce84bd8SYongseok Koh * Size of tailroom from dst. 2316ce84bd8SYongseok Koh * 2326ce84bd8SYongseok Koh * @return 2336ce84bd8SYongseok Koh * Pointer after copied data. 2346ce84bd8SYongseok Koh */ 2356ce84bd8SYongseok Koh static inline void * 2366ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n, 2376ce84bd8SYongseok Koh void *base, size_t tailroom) 2386ce84bd8SYongseok Koh { 2396ce84bd8SYongseok Koh void *ret; 2406ce84bd8SYongseok Koh 2416ce84bd8SYongseok Koh if (n > tailroom) { 2426ce84bd8SYongseok Koh rte_memcpy(dst, src, tailroom); 2436ce84bd8SYongseok Koh rte_memcpy(base, (void *)((uintptr_t)src + tailroom), 2446ce84bd8SYongseok Koh n - tailroom); 2456ce84bd8SYongseok Koh ret = (uint8_t *)base + n - tailroom; 2466ce84bd8SYongseok Koh } else { 2476ce84bd8SYongseok Koh rte_memcpy(dst, src, n); 2486ce84bd8SYongseok Koh ret = (n == tailroom) ? base : (uint8_t *)dst + n; 2496ce84bd8SYongseok Koh } 2506ce84bd8SYongseok Koh return ret; 2516ce84bd8SYongseok Koh } 2526ce84bd8SYongseok Koh 2536ce84bd8SYongseok Koh /** 2542e22920bSAdrien Mazarguil * Manage TX completions. 2552e22920bSAdrien Mazarguil * 2562e22920bSAdrien Mazarguil * When sending a burst, mlx5_tx_burst() posts several WRs. 2572e22920bSAdrien Mazarguil * 2582e22920bSAdrien Mazarguil * @param txq 2592e22920bSAdrien Mazarguil * Pointer to TX queue structure. 2602e22920bSAdrien Mazarguil */ 261a6ca35aaSNélio Laranjeiro static inline void 2622e22920bSAdrien Mazarguil txq_complete(struct txq *txq) 2632e22920bSAdrien Mazarguil { 264b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 265e2f116eeSNélio Laranjeiro const unsigned int cqe_n = 1 << txq->cqe_n; 26699c12dccSNélio Laranjeiro const unsigned int cqe_cnt = cqe_n - 1; 2671d88ba17SNélio Laranjeiro uint16_t elts_free = txq->elts_tail; 2681d88ba17SNélio Laranjeiro uint16_t elts_tail; 2691d88ba17SNélio Laranjeiro uint16_t cq_ci = txq->cq_ci; 27097267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = NULL; 271fdcb0f53SNélio Laranjeiro volatile struct mlx5_wqe_ctrl *ctrl; 2722e22920bSAdrien Mazarguil 27399c12dccSNélio Laranjeiro do { 27497267b8eSNelio Laranjeiro volatile struct mlx5_cqe *tmp; 2751d88ba17SNélio Laranjeiro 27697267b8eSNelio Laranjeiro tmp = &(*txq->cqes)[cq_ci & cqe_cnt]; 27797267b8eSNelio Laranjeiro if (check_cqe(tmp, cqe_n, cq_ci)) 2781d88ba17SNélio Laranjeiro break; 279c305090bSAdrien Mazarguil cqe = tmp; 28099c12dccSNélio Laranjeiro #ifndef NDEBUG 28199c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(cqe->op_own) == MLX5_COMPRESSED) { 28297267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 28399c12dccSNélio Laranjeiro ERROR("unexpected compressed CQE, TX stopped"); 28499c12dccSNélio Laranjeiro return; 2852e22920bSAdrien Mazarguil } 28699c12dccSNélio Laranjeiro if ((MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_RESP_ERR) || 28799c12dccSNélio Laranjeiro (MLX5_CQE_OPCODE(cqe->op_own) == MLX5_CQE_REQ_ERR)) { 28897267b8eSNelio Laranjeiro if (!check_cqe_seen(cqe)) 28999c12dccSNélio Laranjeiro ERROR("unexpected error CQE, TX stopped"); 29099c12dccSNélio Laranjeiro return; 29199c12dccSNélio Laranjeiro } 29299c12dccSNélio Laranjeiro #endif /* NDEBUG */ 29399c12dccSNélio Laranjeiro ++cq_ci; 29499c12dccSNélio Laranjeiro } while (1); 295c305090bSAdrien Mazarguil if (unlikely(cqe == NULL)) 2961d88ba17SNélio Laranjeiro return; 297f04f1d51SNélio Laranjeiro txq->wqe_pi = ntohs(cqe->wqe_counter); 298fdcb0f53SNélio Laranjeiro ctrl = (volatile struct mlx5_wqe_ctrl *) 299f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_pi); 300fdcb0f53SNélio Laranjeiro elts_tail = ctrl->ctrl3; 301a821d09dSNélio Laranjeiro assert(elts_tail < (1 << txq->wqe_n)); 3021d88ba17SNélio Laranjeiro /* Free buffers. */ 303c305090bSAdrien Mazarguil while (elts_free != elts_tail) { 3041d88ba17SNélio Laranjeiro struct rte_mbuf *elt = (*txq->elts)[elts_free]; 305a859e8a9SNelio Laranjeiro unsigned int elts_free_next = 3061d88ba17SNélio Laranjeiro (elts_free + 1) & (elts_n - 1); 3071d88ba17SNélio Laranjeiro struct rte_mbuf *elt_next = (*txq->elts)[elts_free_next]; 308a859e8a9SNelio Laranjeiro 309b185e63fSAdrien Mazarguil #ifndef NDEBUG 310b185e63fSAdrien Mazarguil /* Poisoning. */ 3111d88ba17SNélio Laranjeiro memset(&(*txq->elts)[elts_free], 3121d88ba17SNélio Laranjeiro 0x66, 3131d88ba17SNélio Laranjeiro sizeof((*txq->elts)[elts_free])); 314b185e63fSAdrien Mazarguil #endif 3151d88ba17SNélio Laranjeiro RTE_MBUF_PREFETCH_TO_FREE(elt_next); 3161d88ba17SNélio Laranjeiro /* Only one segment needs to be freed. */ 3171d88ba17SNélio Laranjeiro rte_pktmbuf_free_seg(elt); 318a859e8a9SNelio Laranjeiro elts_free = elts_free_next; 319c305090bSAdrien Mazarguil } 3201d88ba17SNélio Laranjeiro txq->cq_ci = cq_ci; 3212e22920bSAdrien Mazarguil txq->elts_tail = elts_tail; 3221d88ba17SNélio Laranjeiro /* Update the consumer index. */ 3231d88ba17SNélio Laranjeiro rte_wmb(); 3241d88ba17SNélio Laranjeiro *txq->cq_db = htonl(cq_ci); 3252e22920bSAdrien Mazarguil } 3262e22920bSAdrien Mazarguil 3272e22920bSAdrien Mazarguil /** 3288340392eSAdrien Mazarguil * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which 3298340392eSAdrien Mazarguil * the cloned mbuf is allocated is returned instead. 3308340392eSAdrien Mazarguil * 3318340392eSAdrien Mazarguil * @param buf 3328340392eSAdrien Mazarguil * Pointer to mbuf. 3338340392eSAdrien Mazarguil * 3348340392eSAdrien Mazarguil * @return 3358340392eSAdrien Mazarguil * Memory pool where data is located for given mbuf. 3368340392eSAdrien Mazarguil */ 3378340392eSAdrien Mazarguil static struct rte_mempool * 3388340392eSAdrien Mazarguil txq_mb2mp(struct rte_mbuf *buf) 3398340392eSAdrien Mazarguil { 3408340392eSAdrien Mazarguil if (unlikely(RTE_MBUF_INDIRECT(buf))) 3418340392eSAdrien Mazarguil return rte_mbuf_from_indirect(buf)->pool; 3428340392eSAdrien Mazarguil return buf->pool; 3438340392eSAdrien Mazarguil } 3448340392eSAdrien Mazarguil 3458340392eSAdrien Mazarguil /** 3462e22920bSAdrien Mazarguil * Get Memory Region (MR) <-> Memory Pool (MP) association from txq->mp2mr[]. 3472e22920bSAdrien Mazarguil * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, 3482e22920bSAdrien Mazarguil * remove an entry first. 3492e22920bSAdrien Mazarguil * 3502e22920bSAdrien Mazarguil * @param txq 3512e22920bSAdrien Mazarguil * Pointer to TX queue structure. 3522e22920bSAdrien Mazarguil * @param[in] mp 3532e22920bSAdrien Mazarguil * Memory Pool for which a Memory Region lkey must be returned. 3542e22920bSAdrien Mazarguil * 3552e22920bSAdrien Mazarguil * @return 3562e22920bSAdrien Mazarguil * mr->lkey on success, (uint32_t)-1 on failure. 3572e22920bSAdrien Mazarguil */ 358491770faSNélio Laranjeiro static inline uint32_t 359d1d914ebSOlivier Matz txq_mp2mr(struct txq *txq, struct rte_mempool *mp) 3602e22920bSAdrien Mazarguil { 3612e22920bSAdrien Mazarguil unsigned int i; 362491770faSNélio Laranjeiro uint32_t lkey = (uint32_t)-1; 3632e22920bSAdrien Mazarguil 3642e22920bSAdrien Mazarguil for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { 3652e22920bSAdrien Mazarguil if (unlikely(txq->mp2mr[i].mp == NULL)) { 3662e22920bSAdrien Mazarguil /* Unknown MP, add a new MR for it. */ 3672e22920bSAdrien Mazarguil break; 3682e22920bSAdrien Mazarguil } 3692e22920bSAdrien Mazarguil if (txq->mp2mr[i].mp == mp) { 3702e22920bSAdrien Mazarguil assert(txq->mp2mr[i].lkey != (uint32_t)-1); 3711d88ba17SNélio Laranjeiro assert(htonl(txq->mp2mr[i].mr->lkey) == 3721d88ba17SNélio Laranjeiro txq->mp2mr[i].lkey); 373491770faSNélio Laranjeiro lkey = txq->mp2mr[i].lkey; 374491770faSNélio Laranjeiro break; 3752e22920bSAdrien Mazarguil } 3762e22920bSAdrien Mazarguil } 377491770faSNélio Laranjeiro if (unlikely(lkey == (uint32_t)-1)) 378491770faSNélio Laranjeiro lkey = txq_mp2mr_reg(txq, mp, i); 379491770faSNélio Laranjeiro return lkey; 3800a3b350dSOlga Shern } 3810a3b350dSOlga Shern 382e192ef80SYaacov Hazan /** 3831d88ba17SNélio Laranjeiro * Ring TX queue doorbell. 3841d88ba17SNélio Laranjeiro * 3851d88ba17SNélio Laranjeiro * @param txq 3861d88ba17SNélio Laranjeiro * Pointer to TX queue structure. 38730807f62SNélio Laranjeiro * @param wqe 38830807f62SNélio Laranjeiro * Pointer to the last WQE posted in the NIC. 3891d88ba17SNélio Laranjeiro */ 3901d88ba17SNélio Laranjeiro static inline void 39130807f62SNélio Laranjeiro mlx5_tx_dbrec(struct txq *txq, volatile struct mlx5_wqe *wqe) 3921d88ba17SNélio Laranjeiro { 39330807f62SNélio Laranjeiro uint64_t *dst = (uint64_t *)((uintptr_t)txq->bf_reg); 39430807f62SNélio Laranjeiro volatile uint64_t *src = ((volatile uint64_t *)wqe); 39530807f62SNélio Laranjeiro 3961d88ba17SNélio Laranjeiro rte_wmb(); 3971d88ba17SNélio Laranjeiro *txq->qp_db = htonl(txq->wqe_ci); 3981d88ba17SNélio Laranjeiro /* Ensure ordering between DB record and BF copy. */ 3991d88ba17SNélio Laranjeiro rte_wmb(); 40030807f62SNélio Laranjeiro *dst = *src; 4011d88ba17SNélio Laranjeiro } 402e192ef80SYaacov Hazan 4031d88ba17SNélio Laranjeiro /** 4048788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 4058788fec1SOlivier Matz * 4068788fec1SOlivier Matz * @param tx_queue 4078788fec1SOlivier Matz * The tx queue. 4088788fec1SOlivier Matz * @param[in] offset 4098788fec1SOlivier Matz * The index of the descriptor in the ring. 4108788fec1SOlivier Matz * 4118788fec1SOlivier Matz * @return 4128788fec1SOlivier Matz * The status of the tx descriptor. 4138788fec1SOlivier Matz */ 4148788fec1SOlivier Matz int 4158788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 4168788fec1SOlivier Matz { 4178788fec1SOlivier Matz struct txq *txq = tx_queue; 4188788fec1SOlivier Matz const unsigned int elts_n = 1 << txq->elts_n; 4198788fec1SOlivier Matz const unsigned int elts_cnt = elts_n - 1; 4208788fec1SOlivier Matz unsigned int used; 4218788fec1SOlivier Matz 4228788fec1SOlivier Matz txq_complete(txq); 4238788fec1SOlivier Matz used = (txq->elts_head - txq->elts_tail) & elts_cnt; 4248788fec1SOlivier Matz if (offset < used) 4258788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 4268788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 4278788fec1SOlivier Matz } 4288788fec1SOlivier Matz 4298788fec1SOlivier Matz /** 4308788fec1SOlivier Matz * DPDK callback to check the status of a rx descriptor. 4318788fec1SOlivier Matz * 4328788fec1SOlivier Matz * @param rx_queue 4338788fec1SOlivier Matz * The rx queue. 4348788fec1SOlivier Matz * @param[in] offset 4358788fec1SOlivier Matz * The index of the descriptor in the ring. 4368788fec1SOlivier Matz * 4378788fec1SOlivier Matz * @return 4388788fec1SOlivier Matz * The status of the tx descriptor. 4398788fec1SOlivier Matz */ 4408788fec1SOlivier Matz int 4418788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 4428788fec1SOlivier Matz { 4438788fec1SOlivier Matz struct rxq *rxq = rx_queue; 4448788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 4458788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 4468788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 4478788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 4488788fec1SOlivier Matz unsigned int cq_ci; 4498788fec1SOlivier Matz unsigned int used; 4508788fec1SOlivier Matz 4518788fec1SOlivier Matz /* if we are processing a compressed cqe */ 4528788fec1SOlivier Matz if (zip->ai) { 4538788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 4548788fec1SOlivier Matz cq_ci = zip->cq_ci; 4558788fec1SOlivier Matz } else { 4568788fec1SOlivier Matz used = 0; 4578788fec1SOlivier Matz cq_ci = rxq->cq_ci; 4588788fec1SOlivier Matz } 4598788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4608788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 4618788fec1SOlivier Matz int8_t op_own; 4628788fec1SOlivier Matz unsigned int n; 4638788fec1SOlivier Matz 4648788fec1SOlivier Matz op_own = cqe->op_own; 4658788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 4668788fec1SOlivier Matz n = ntohl(cqe->byte_cnt); 4678788fec1SOlivier Matz else 4688788fec1SOlivier Matz n = 1; 4698788fec1SOlivier Matz cq_ci += n; 4708788fec1SOlivier Matz used += n; 4718788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4728788fec1SOlivier Matz } 4738788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 4748788fec1SOlivier Matz if (offset < used) 4758788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 4768788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 4778788fec1SOlivier Matz } 4788788fec1SOlivier Matz 4798788fec1SOlivier Matz /** 4802e22920bSAdrien Mazarguil * DPDK callback for TX. 4812e22920bSAdrien Mazarguil * 4822e22920bSAdrien Mazarguil * @param dpdk_txq 4832e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 4842e22920bSAdrien Mazarguil * @param[in] pkts 4852e22920bSAdrien Mazarguil * Packets to transmit. 4862e22920bSAdrien Mazarguil * @param pkts_n 4872e22920bSAdrien Mazarguil * Number of packets in array. 4882e22920bSAdrien Mazarguil * 4892e22920bSAdrien Mazarguil * @return 4902e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 4912e22920bSAdrien Mazarguil */ 4922e22920bSAdrien Mazarguil uint16_t 4932e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 4942e22920bSAdrien Mazarguil { 4952e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 4961d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 497b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 498c3d62cc9SAdrien Mazarguil unsigned int i = 0; 499a5bf6af9SAdrien Mazarguil unsigned int j = 0; 5003f13f8c2SShahaf Shuler unsigned int k = 0; 5012e22920bSAdrien Mazarguil unsigned int max; 502*ab76eab3SYongseok Koh unsigned int max_inline = txq->max_inline; 503*ab76eab3SYongseok Koh const unsigned int inline_en = !!max_inline && txq->inline_en; 504f04f1d51SNélio Laranjeiro uint16_t max_wqe; 505c305090bSAdrien Mazarguil unsigned int comp; 5069a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 5076579c27cSNélio Laranjeiro unsigned int segs_n = 0; 5086579c27cSNélio Laranjeiro struct rte_mbuf *buf = NULL; 5096579c27cSNélio Laranjeiro uint8_t *raw; 5102e22920bSAdrien Mazarguil 5111d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 5121d88ba17SNélio Laranjeiro return 0; 5135e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 514c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 5151d88ba17SNélio Laranjeiro /* Start processing. */ 5162e22920bSAdrien Mazarguil txq_complete(txq); 5174f52bbfbSNelio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 5182e22920bSAdrien Mazarguil if (max > elts_n) 5192e22920bSAdrien Mazarguil max -= elts_n; 520f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 521f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 522f04f1d51SNélio Laranjeiro return 0; 523c3d62cc9SAdrien Mazarguil do { 5249a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 525573f54afSNélio Laranjeiro uint32_t length; 5268688b2f8SNélio Laranjeiro unsigned int ds = 0; 5276579c27cSNélio Laranjeiro uintptr_t addr; 5289a7fa9f7SNélio Laranjeiro uint64_t naddr; 5290d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 5303f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 531eef822ddSNélio Laranjeiro uint16_t ehdr; 5329a7fa9f7SNélio Laranjeiro uint8_t cs_flags = 0; 5333f13f8c2SShahaf Shuler uint64_t tso = 0; 5346579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 5356579c27cSNélio Laranjeiro uint32_t total_length = 0; 5366579c27cSNélio Laranjeiro #endif 5372e22920bSAdrien Mazarguil 5386579c27cSNélio Laranjeiro /* first_seg */ 5396579c27cSNélio Laranjeiro buf = *(pkts++); 5406579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 541c3d62cc9SAdrien Mazarguil /* 542c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 543c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 544c3d62cc9SAdrien Mazarguil */ 545a5bf6af9SAdrien Mazarguil assert(segs_n); 546a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 547c3d62cc9SAdrien Mazarguil break; 548a5bf6af9SAdrien Mazarguil max -= segs_n; 5496579c27cSNélio Laranjeiro --segs_n; 5506579c27cSNélio Laranjeiro if (!segs_n) 551c3d62cc9SAdrien Mazarguil --pkts_n; 552f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 553f04f1d51SNélio Laranjeiro break; 5549a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 555fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 556fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 5576579c27cSNélio Laranjeiro if (pkts_n > 1) 558c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 5596579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 5602e22920bSAdrien Mazarguil length = DATA_LEN(buf); 561eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 562eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 5636579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 5646579c27cSNélio Laranjeiro total_length = length; 5656579c27cSNélio Laranjeiro #endif 566959be52eSNélio Laranjeiro if (length < (MLX5_WQE_DWORD_SIZE + 2)) 567959be52eSNélio Laranjeiro break; 5682e22920bSAdrien Mazarguil /* Update element. */ 5691d88ba17SNélio Laranjeiro (*txq->elts)[elts_head] = buf; 5706579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 5715e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 5726579c27cSNélio Laranjeiro if (pkts_n > 1) { 5736579c27cSNélio Laranjeiro volatile void *pkt_addr; 5746579c27cSNélio Laranjeiro 5756579c27cSNélio Laranjeiro pkt_addr = rte_pktmbuf_mtod(*pkts, volatile void *); 5766579c27cSNélio Laranjeiro rte_prefetch0(pkt_addr); 5776579c27cSNélio Laranjeiro } 5781d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 5791d88ba17SNélio Laranjeiro if (buf->ol_flags & 5801d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 581f5fde520SShahaf Shuler const uint64_t is_tunneled = buf->ol_flags & 582f5fde520SShahaf Shuler (PKT_TX_TUNNEL_GRE | 583f5fde520SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 584f5fde520SShahaf Shuler 585f5fde520SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 586f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM | 587f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_INNER_CSUM; 588f5fde520SShahaf Shuler if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM) 589f5fde520SShahaf Shuler cs_flags |= MLX5_ETH_WQE_L3_CSUM; 590f5fde520SShahaf Shuler } else { 591f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_CSUM | 592f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_CSUM; 593f5fde520SShahaf Shuler } 5941d88ba17SNélio Laranjeiro } 595b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 5966579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 5976579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 5986579c27cSNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | buf->vlan_tci); 5990d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 6006579c27cSNélio Laranjeiro 6010d637a34SNélio Laranjeiro addr += 2; 6020d637a34SNélio Laranjeiro length -= 2; 6030d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 6040d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 6050d637a34SNélio Laranjeiro /* Copy VLAN. */ 6060d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 6070d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 6080d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 6090d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 6100d637a34SNélio Laranjeiro addr += len + 2; 6110d637a34SNélio Laranjeiro length -= (len + 2); 6120d637a34SNélio Laranjeiro } else { 6130d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 6140d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 6150d637a34SNélio Laranjeiro length -= pkt_inline_sz; 6160d637a34SNélio Laranjeiro addr += pkt_inline_sz; 6176579c27cSNélio Laranjeiro } 6183f13f8c2SShahaf Shuler if (txq->tso_en) { 6193f13f8c2SShahaf Shuler tso = buf->ol_flags & PKT_TX_TCP_SEG; 6203f13f8c2SShahaf Shuler if (tso) { 6213f13f8c2SShahaf Shuler uintptr_t end = (uintptr_t) 6223f13f8c2SShahaf Shuler (((uintptr_t)txq->wqes) + 6233f13f8c2SShahaf Shuler (1 << txq->wqe_n) * 6243f13f8c2SShahaf Shuler MLX5_WQE_SIZE); 6253f13f8c2SShahaf Shuler unsigned int copy_b; 6263f13f8c2SShahaf Shuler uint8_t vlan_sz = (buf->ol_flags & 6273f13f8c2SShahaf Shuler PKT_TX_VLAN_PKT) ? 4 : 0; 628b247f346SShahaf Shuler const uint64_t is_tunneled = 629b247f346SShahaf Shuler buf->ol_flags & 630b247f346SShahaf Shuler (PKT_TX_TUNNEL_GRE | 631b247f346SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 6323f13f8c2SShahaf Shuler 6333f13f8c2SShahaf Shuler tso_header_sz = buf->l2_len + vlan_sz + 6343f13f8c2SShahaf Shuler buf->l3_len + buf->l4_len; 6353f13f8c2SShahaf Shuler 636b247f346SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 637b247f346SShahaf Shuler tso_header_sz += buf->outer_l2_len + 638b247f346SShahaf Shuler buf->outer_l3_len; 6392a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM; 6402a6c96beSShahaf Shuler } else { 6412a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_CSUM; 642b247f346SShahaf Shuler } 6433f13f8c2SShahaf Shuler if (unlikely(tso_header_sz > 6443f13f8c2SShahaf Shuler MLX5_MAX_TSO_HEADER)) 6453f13f8c2SShahaf Shuler break; 6463f13f8c2SShahaf Shuler copy_b = tso_header_sz - pkt_inline_sz; 6473f13f8c2SShahaf Shuler /* First seg must contain all headers. */ 6483f13f8c2SShahaf Shuler assert(copy_b <= length); 6493f13f8c2SShahaf Shuler raw += MLX5_WQE_DWORD_SIZE; 6503f13f8c2SShahaf Shuler if (copy_b && 6513f13f8c2SShahaf Shuler ((end - (uintptr_t)raw) > copy_b)) { 6523f13f8c2SShahaf Shuler uint16_t n = (MLX5_WQE_DS(copy_b) - 6533f13f8c2SShahaf Shuler 1 + 3) / 4; 6543f13f8c2SShahaf Shuler 6553f13f8c2SShahaf Shuler if (unlikely(max_wqe < n)) 6563f13f8c2SShahaf Shuler break; 6573f13f8c2SShahaf Shuler max_wqe -= n; 6583f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 6593f13f8c2SShahaf Shuler (void *)addr, copy_b); 6603f13f8c2SShahaf Shuler addr += copy_b; 6613f13f8c2SShahaf Shuler length -= copy_b; 6623f13f8c2SShahaf Shuler pkt_inline_sz += copy_b; 6633f13f8c2SShahaf Shuler /* 6643f13f8c2SShahaf Shuler * Another DWORD will be added 6653f13f8c2SShahaf Shuler * in the inline part. 6663f13f8c2SShahaf Shuler */ 6673f13f8c2SShahaf Shuler raw += MLX5_WQE_DS(copy_b) * 6683f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE - 6693f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 6703f13f8c2SShahaf Shuler } else { 6713f13f8c2SShahaf Shuler /* NOP WQE. */ 6723f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 6733f13f8c2SShahaf Shuler htonl(txq->wqe_ci << 8), 6743f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | 1), 6753f13f8c2SShahaf Shuler 0, 6763f13f8c2SShahaf Shuler 0, 6773f13f8c2SShahaf Shuler }; 6783f13f8c2SShahaf Shuler ds = 1; 6793f13f8c2SShahaf Shuler total_length = 0; 6803f13f8c2SShahaf Shuler pkts--; 6813f13f8c2SShahaf Shuler pkts_n++; 6823f13f8c2SShahaf Shuler elts_head = (elts_head - 1) & 6833f13f8c2SShahaf Shuler (elts_n - 1); 6843f13f8c2SShahaf Shuler k++; 6853f13f8c2SShahaf Shuler goto next_wqe; 6863f13f8c2SShahaf Shuler } 6873f13f8c2SShahaf Shuler } 6883f13f8c2SShahaf Shuler } 6896579c27cSNélio Laranjeiro /* Inline if enough room. */ 690*ab76eab3SYongseok Koh if (inline_en || tso) { 691fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 692fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 693fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 694*ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 6958fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 6963f13f8c2SShahaf Shuler (pkt_inline_sz - 2); 697*ab76eab3SYongseok Koh uintptr_t addr_end = (addr + inline_room) & 6986579c27cSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 6998fcd6c2cSNélio Laranjeiro unsigned int copy_b = (addr_end > addr) ? 7008fcd6c2cSNélio Laranjeiro RTE_MIN((addr_end - addr), length) : 7018fcd6c2cSNélio Laranjeiro 0; 7026579c27cSNélio Laranjeiro 7038fcd6c2cSNélio Laranjeiro raw += MLX5_WQE_DWORD_SIZE; 7048fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 705f04f1d51SNélio Laranjeiro /* 706f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 707f04f1d51SNélio Laranjeiro * keep the computation positive, it is 708f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 709f04f1d51SNélio Laranjeiro */ 7108fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 7118fcd6c2cSNélio Laranjeiro 712f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 713f04f1d51SNélio Laranjeiro break; 714f04f1d51SNélio Laranjeiro max_wqe -= n; 7153f13f8c2SShahaf Shuler if (tso) { 7163f13f8c2SShahaf Shuler uint32_t inl = 7173f13f8c2SShahaf Shuler htonl(copy_b | MLX5_INLINE_SEG); 7183f13f8c2SShahaf Shuler 7193f13f8c2SShahaf Shuler pkt_inline_sz = 7203f13f8c2SShahaf Shuler MLX5_WQE_DS(tso_header_sz) * 7213f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 7223f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 7233f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 7243f13f8c2SShahaf Shuler raw += sizeof(inl); 7253f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 7263f13f8c2SShahaf Shuler } 7276579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 7286579c27cSNélio Laranjeiro addr += copy_b; 7296579c27cSNélio Laranjeiro length -= copy_b; 7306579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 7316579c27cSNélio Laranjeiro } 7326579c27cSNélio Laranjeiro /* 733786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 7346579c27cSNélio Laranjeiro * the size of the inline part of the packet. 7356579c27cSNélio Laranjeiro */ 7366579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 7376579c27cSNélio Laranjeiro if (length > 0) { 738f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 739f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 740f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 741f04f1d51SNélio Laranjeiro break; 742f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 743f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 744f04f1d51SNélio Laranjeiro ds / 4); 745f04f1d51SNélio Laranjeiro } else { 7469a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 7476579c27cSNélio Laranjeiro ((uintptr_t)wqe + 7486579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 749f04f1d51SNélio Laranjeiro } 7506579c27cSNélio Laranjeiro goto use_dseg; 7516579c27cSNélio Laranjeiro } else if (!segs_n) { 7526579c27cSNélio Laranjeiro goto next_pkt; 7536579c27cSNélio Laranjeiro } else { 754786b5c2dSShahaf Shuler /* dseg will be advance as part of next_seg */ 755786b5c2dSShahaf Shuler dseg = (volatile rte_v128u32_t *) 756786b5c2dSShahaf Shuler ((uintptr_t)wqe + 757786b5c2dSShahaf Shuler ((ds - 1) * MLX5_WQE_DWORD_SIZE)); 7586579c27cSNélio Laranjeiro goto next_seg; 7596579c27cSNélio Laranjeiro } 7606579c27cSNélio Laranjeiro } else { 7616579c27cSNélio Laranjeiro /* 7626579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 7636579c27cSNélio Laranjeiro * Ethernet Header as been stored. 7646579c27cSNélio Laranjeiro */ 7659a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 7666579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 7676579c27cSNélio Laranjeiro ds = 3; 7686579c27cSNélio Laranjeiro use_dseg: 7696579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 7709a7fa9f7SNélio Laranjeiro naddr = htonll(addr); 7719a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 7729a7fa9f7SNélio Laranjeiro htonl(length), 7739a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 7749a7fa9f7SNélio Laranjeiro naddr, 7759a7fa9f7SNélio Laranjeiro naddr >> 32, 7766579c27cSNélio Laranjeiro }; 7776579c27cSNélio Laranjeiro ++ds; 7786579c27cSNélio Laranjeiro if (!segs_n) 7796579c27cSNélio Laranjeiro goto next_pkt; 7806579c27cSNélio Laranjeiro } 7816579c27cSNélio Laranjeiro next_seg: 7826579c27cSNélio Laranjeiro assert(buf); 7836579c27cSNélio Laranjeiro assert(ds); 7846579c27cSNélio Laranjeiro assert(wqe); 785a5bf6af9SAdrien Mazarguil /* 786a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 787a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 788a5bf6af9SAdrien Mazarguil * of data segment size. 789a5bf6af9SAdrien Mazarguil */ 7908688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 7916579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 792f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 793f04f1d51SNélio Laranjeiro break; 7949a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 795f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 796f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 797f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 7986579c27cSNélio Laranjeiro } else { 799a5bf6af9SAdrien Mazarguil ++dseg; 8006579c27cSNélio Laranjeiro } 801a5bf6af9SAdrien Mazarguil ++ds; 802a5bf6af9SAdrien Mazarguil buf = buf->next; 803a5bf6af9SAdrien Mazarguil assert(buf); 8046579c27cSNélio Laranjeiro length = DATA_LEN(buf); 805a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 8066579c27cSNélio Laranjeiro total_length += length; 807a5bf6af9SAdrien Mazarguil #endif 8086579c27cSNélio Laranjeiro /* Store segment information. */ 8099a7fa9f7SNélio Laranjeiro naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)); 8109a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 8119a7fa9f7SNélio Laranjeiro htonl(length), 8129a7fa9f7SNélio Laranjeiro txq_mp2mr(txq, txq_mb2mp(buf)), 8139a7fa9f7SNélio Laranjeiro naddr, 8149a7fa9f7SNélio Laranjeiro naddr >> 32, 8156579c27cSNélio Laranjeiro }; 8166579c27cSNélio Laranjeiro (*txq->elts)[elts_head] = buf; 8176579c27cSNélio Laranjeiro elts_head = (elts_head + 1) & (elts_n - 1); 818a5bf6af9SAdrien Mazarguil ++j; 8196579c27cSNélio Laranjeiro --segs_n; 8206579c27cSNélio Laranjeiro if (segs_n) 8216579c27cSNélio Laranjeiro goto next_seg; 8226579c27cSNélio Laranjeiro else 8236579c27cSNélio Laranjeiro --pkts_n; 8246579c27cSNélio Laranjeiro next_pkt: 8256579c27cSNélio Laranjeiro ++i; 826b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 8273f13f8c2SShahaf Shuler if (tso) { 8283f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 8293f13f8c2SShahaf Shuler htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO), 8303f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | ds), 8313f13f8c2SShahaf Shuler 0, 8323f13f8c2SShahaf Shuler 0, 8333f13f8c2SShahaf Shuler }; 8343f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 8353f13f8c2SShahaf Shuler 0, 8363f13f8c2SShahaf Shuler cs_flags | (htons(buf->tso_segsz) << 16), 8373f13f8c2SShahaf Shuler 0, 8383f13f8c2SShahaf Shuler (ehdr << 16) | htons(tso_header_sz), 8393f13f8c2SShahaf Shuler }; 8403f13f8c2SShahaf Shuler } else { 8419a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 8429a7fa9f7SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 8439a7fa9f7SNélio Laranjeiro htonl(txq->qp_num_8s | ds), 8449a7fa9f7SNélio Laranjeiro 0, 8459a7fa9f7SNélio Laranjeiro 0, 8469a7fa9f7SNélio Laranjeiro }; 8479a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 8489a7fa9f7SNélio Laranjeiro 0, 8499a7fa9f7SNélio Laranjeiro cs_flags, 8509a7fa9f7SNélio Laranjeiro 0, 851eef822ddSNélio Laranjeiro (ehdr << 16) | htons(pkt_inline_sz), 8529a7fa9f7SNélio Laranjeiro }; 8533f13f8c2SShahaf Shuler } 8543f13f8c2SShahaf Shuler next_wqe: 8556579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 85687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 857573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 8586579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 85987011737SAdrien Mazarguil #endif 860c3d62cc9SAdrien Mazarguil } while (pkts_n); 8612e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 8623f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 8632e22920bSAdrien Mazarguil return 0; 864c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 8653f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 866c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 8679a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_ctrl *w = 8689a7fa9f7SNélio Laranjeiro (volatile struct mlx5_wqe_ctrl *)wqe; 8699a7fa9f7SNélio Laranjeiro 870c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 8719a7fa9f7SNélio Laranjeiro w->ctrl2 = htonl(8); 872c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 8739a7fa9f7SNélio Laranjeiro w->ctrl3 = elts_head; 874c305090bSAdrien Mazarguil txq->elts_comp = 0; 875c305090bSAdrien Mazarguil } else { 876c305090bSAdrien Mazarguil txq->elts_comp = comp; 877c305090bSAdrien Mazarguil } 87887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 87987011737SAdrien Mazarguil /* Increment sent packets counter. */ 88087011737SAdrien Mazarguil txq->stats.opackets += i; 88187011737SAdrien Mazarguil #endif 8822e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 88330807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)wqe); 8842e22920bSAdrien Mazarguil txq->elts_head = elts_head; 8852e22920bSAdrien Mazarguil return i; 8862e22920bSAdrien Mazarguil } 8872e22920bSAdrien Mazarguil 8882e22920bSAdrien Mazarguil /** 889230189d9SNélio Laranjeiro * Open a MPW session. 890230189d9SNélio Laranjeiro * 891230189d9SNélio Laranjeiro * @param txq 892230189d9SNélio Laranjeiro * Pointer to TX queue structure. 893230189d9SNélio Laranjeiro * @param mpw 894230189d9SNélio Laranjeiro * Pointer to MPW session structure. 895230189d9SNélio Laranjeiro * @param length 896230189d9SNélio Laranjeiro * Packet length. 897230189d9SNélio Laranjeiro */ 898230189d9SNélio Laranjeiro static inline void 899230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 900230189d9SNélio Laranjeiro { 901a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 902230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 903230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 904fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 905230189d9SNélio Laranjeiro 906230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 907230189d9SNélio Laranjeiro mpw->pkts_n = 0; 908230189d9SNélio Laranjeiro mpw->len = length; 909230189d9SNélio Laranjeiro mpw->total_len = 0; 910fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 9118688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 9128688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 9138688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 9148688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 9158688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 9168688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 917c904ae25SNélio Laranjeiro (txq->wqe_ci << 8) | MLX5_OPCODE_TSO); 9188688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 9198688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 9208688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 9218688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 9228688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 9238688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 924230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 925230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 926230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 927230189d9SNélio Laranjeiro } 928230189d9SNélio Laranjeiro 929230189d9SNélio Laranjeiro /** 930230189d9SNélio Laranjeiro * Close a MPW session. 931230189d9SNélio Laranjeiro * 932230189d9SNélio Laranjeiro * @param txq 933230189d9SNélio Laranjeiro * Pointer to TX queue structure. 934230189d9SNélio Laranjeiro * @param mpw 935230189d9SNélio Laranjeiro * Pointer to MPW session structure. 936230189d9SNélio Laranjeiro */ 937230189d9SNélio Laranjeiro static inline void 938230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 939230189d9SNélio Laranjeiro { 940230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 941230189d9SNélio Laranjeiro 942230189d9SNélio Laranjeiro /* 943230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 944230189d9SNélio Laranjeiro * count as 2. 945230189d9SNélio Laranjeiro */ 9468688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num)); 947230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 948230189d9SNélio Laranjeiro if (num < 3) 949230189d9SNélio Laranjeiro ++txq->wqe_ci; 950230189d9SNélio Laranjeiro else 951230189d9SNélio Laranjeiro txq->wqe_ci += 2; 952fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 953fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 954230189d9SNélio Laranjeiro } 955230189d9SNélio Laranjeiro 956230189d9SNélio Laranjeiro /** 957230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 958230189d9SNélio Laranjeiro * 959230189d9SNélio Laranjeiro * @param dpdk_txq 960230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 961230189d9SNélio Laranjeiro * @param[in] pkts 962230189d9SNélio Laranjeiro * Packets to transmit. 963230189d9SNélio Laranjeiro * @param pkts_n 964230189d9SNélio Laranjeiro * Number of packets in array. 965230189d9SNélio Laranjeiro * 966230189d9SNélio Laranjeiro * @return 967230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 968230189d9SNélio Laranjeiro */ 969230189d9SNélio Laranjeiro uint16_t 970230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 971230189d9SNélio Laranjeiro { 972230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 973230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 974b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 975c3d62cc9SAdrien Mazarguil unsigned int i = 0; 976a5bf6af9SAdrien Mazarguil unsigned int j = 0; 977230189d9SNélio Laranjeiro unsigned int max; 978f04f1d51SNélio Laranjeiro uint16_t max_wqe; 979230189d9SNélio Laranjeiro unsigned int comp; 980230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 981230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 982230189d9SNélio Laranjeiro }; 983230189d9SNélio Laranjeiro 984c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 985c3d62cc9SAdrien Mazarguil return 0; 986230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 987fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 988fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 989230189d9SNélio Laranjeiro /* Start processing. */ 990230189d9SNélio Laranjeiro txq_complete(txq); 991230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 992230189d9SNélio Laranjeiro if (max > elts_n) 993230189d9SNélio Laranjeiro max -= elts_n; 994f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 995f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 996f04f1d51SNélio Laranjeiro return 0; 997c3d62cc9SAdrien Mazarguil do { 998a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 999c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 1000230189d9SNélio Laranjeiro uint32_t length; 1001a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 1002230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 1003230189d9SNélio Laranjeiro 1004c3d62cc9SAdrien Mazarguil /* 1005c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1006c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1007c3d62cc9SAdrien Mazarguil */ 1008a5bf6af9SAdrien Mazarguil assert(segs_n); 1009a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 1010c3d62cc9SAdrien Mazarguil break; 1011a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 1012a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 1013a5bf6af9SAdrien Mazarguil break; 1014a5bf6af9SAdrien Mazarguil max -= segs_n; 1015c3d62cc9SAdrien Mazarguil --pkts_n; 1016230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 1017230189d9SNélio Laranjeiro if (buf->ol_flags & 1018230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 1019230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 1020a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1021a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1022a5bf6af9SAdrien Mazarguil assert(length); 1023230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1024230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 1025230189d9SNélio Laranjeiro ((mpw.len != length) || 1026a5bf6af9SAdrien Mazarguil (segs_n != 1) || 10278688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 1028230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1029230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1030f04f1d51SNélio Laranjeiro /* 1031f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1032f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 1033f04f1d51SNélio Laranjeiro * resources. 1034f04f1d51SNélio Laranjeiro */ 1035f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1036f04f1d51SNélio Laranjeiro break; 1037f04f1d51SNélio Laranjeiro max_wqe -= 2; 1038230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 10398688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1040230189d9SNélio Laranjeiro } 1041a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1042a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1043a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1044a5bf6af9SAdrien Mazarguil length = 0; 1045a5bf6af9SAdrien Mazarguil #endif 1046a5bf6af9SAdrien Mazarguil do { 1047a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 1048a5bf6af9SAdrien Mazarguil uintptr_t addr; 1049a5bf6af9SAdrien Mazarguil 1050a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1051a5bf6af9SAdrien Mazarguil assert(buf); 1052a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1053230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1054a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1055230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 1056a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 1057230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 1058230189d9SNélio Laranjeiro .addr = htonll(addr), 1059230189d9SNélio Laranjeiro }; 1060a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 1061a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1062a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1063a5bf6af9SAdrien Mazarguil #endif 1064a5bf6af9SAdrien Mazarguil buf = buf->next; 1065230189d9SNélio Laranjeiro ++mpw.pkts_n; 1066a5bf6af9SAdrien Mazarguil ++j; 1067a5bf6af9SAdrien Mazarguil } while (--segs_n); 1068a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1069230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1070230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1071230189d9SNélio Laranjeiro elts_head = elts_head_next; 1072230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1073230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1074230189d9SNélio Laranjeiro txq->stats.obytes += length; 1075230189d9SNélio Laranjeiro #endif 1076c3d62cc9SAdrien Mazarguil ++i; 1077c3d62cc9SAdrien Mazarguil } while (pkts_n); 1078230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1079230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1080230189d9SNélio Laranjeiro return 0; 1081230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1082a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1083a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1084230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 10858688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1086230189d9SNélio Laranjeiro 1087230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 10888688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1089230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 10908688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1091230189d9SNélio Laranjeiro txq->elts_comp = 0; 1092230189d9SNélio Laranjeiro } else { 1093230189d9SNélio Laranjeiro txq->elts_comp = comp; 1094230189d9SNélio Laranjeiro } 1095230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1096230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1097230189d9SNélio Laranjeiro txq->stats.opackets += i; 1098230189d9SNélio Laranjeiro #endif 1099230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1100230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 1101230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 110230807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1103230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1104230189d9SNélio Laranjeiro return i; 1105230189d9SNélio Laranjeiro } 1106230189d9SNélio Laranjeiro 1107230189d9SNélio Laranjeiro /** 1108230189d9SNélio Laranjeiro * Open a MPW inline session. 1109230189d9SNélio Laranjeiro * 1110230189d9SNélio Laranjeiro * @param txq 1111230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1112230189d9SNélio Laranjeiro * @param mpw 1113230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1114230189d9SNélio Laranjeiro * @param length 1115230189d9SNélio Laranjeiro * Packet length. 1116230189d9SNélio Laranjeiro */ 1117230189d9SNélio Laranjeiro static inline void 1118230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 1119230189d9SNélio Laranjeiro { 1120a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 11218688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 1122230189d9SNélio Laranjeiro 1123230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 1124230189d9SNélio Laranjeiro mpw->pkts_n = 0; 1125230189d9SNélio Laranjeiro mpw->len = length; 1126230189d9SNélio Laranjeiro mpw->total_len = 0; 1127fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 11288688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 1129230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 1130c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 11318688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 11328688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 11338688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 11348688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 11358688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 11368688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 11378688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 11388688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 11398688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 11408688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 11418688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 1142230189d9SNélio Laranjeiro } 1143230189d9SNélio Laranjeiro 1144230189d9SNélio Laranjeiro /** 1145230189d9SNélio Laranjeiro * Close a MPW inline session. 1146230189d9SNélio Laranjeiro * 1147230189d9SNélio Laranjeiro * @param txq 1148230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1149230189d9SNélio Laranjeiro * @param mpw 1150230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1151230189d9SNélio Laranjeiro */ 1152230189d9SNélio Laranjeiro static inline void 1153230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 1154230189d9SNélio Laranjeiro { 1155230189d9SNélio Laranjeiro unsigned int size; 11568688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 11578688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 1158230189d9SNélio Laranjeiro 11598688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 1160230189d9SNélio Laranjeiro /* 1161230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1162230189d9SNélio Laranjeiro * count as 2. 1163230189d9SNélio Laranjeiro */ 11648688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size)); 1165230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 11668688b2f8SNélio Laranjeiro inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 11678688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1168230189d9SNélio Laranjeiro } 1169230189d9SNélio Laranjeiro 1170230189d9SNélio Laranjeiro /** 1171230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1172230189d9SNélio Laranjeiro * 1173230189d9SNélio Laranjeiro * @param dpdk_txq 1174230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1175230189d9SNélio Laranjeiro * @param[in] pkts 1176230189d9SNélio Laranjeiro * Packets to transmit. 1177230189d9SNélio Laranjeiro * @param pkts_n 1178230189d9SNélio Laranjeiro * Number of packets in array. 1179230189d9SNélio Laranjeiro * 1180230189d9SNélio Laranjeiro * @return 1181230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1182230189d9SNélio Laranjeiro */ 1183230189d9SNélio Laranjeiro uint16_t 1184230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1185230189d9SNélio Laranjeiro uint16_t pkts_n) 1186230189d9SNélio Laranjeiro { 1187230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 1188230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 1189b4b12e55SNélio Laranjeiro const unsigned int elts_n = 1 << txq->elts_n; 1190c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1191a5bf6af9SAdrien Mazarguil unsigned int j = 0; 1192230189d9SNélio Laranjeiro unsigned int max; 1193f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1194230189d9SNélio Laranjeiro unsigned int comp; 11950e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1196230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1197230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1198230189d9SNélio Laranjeiro }; 1199f04f1d51SNélio Laranjeiro /* 1200f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1201f04f1d51SNélio Laranjeiro * code. 1202f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1203f04f1d51SNélio Laranjeiro * - 1 control segment, 1204f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1205f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1206f04f1d51SNélio Laranjeiro */ 1207f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1208f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1209f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1210f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1211230189d9SNélio Laranjeiro 1212c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1213c3d62cc9SAdrien Mazarguil return 0; 1214230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1215fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1216fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1217230189d9SNélio Laranjeiro /* Start processing. */ 1218230189d9SNélio Laranjeiro txq_complete(txq); 1219230189d9SNélio Laranjeiro max = (elts_n - (elts_head - txq->elts_tail)); 1220230189d9SNélio Laranjeiro if (max > elts_n) 1221230189d9SNélio Laranjeiro max -= elts_n; 1222c3d62cc9SAdrien Mazarguil do { 1223a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1224c3d62cc9SAdrien Mazarguil unsigned int elts_head_next; 1225230189d9SNélio Laranjeiro uintptr_t addr; 1226230189d9SNélio Laranjeiro uint32_t length; 1227a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 1228230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 1229230189d9SNélio Laranjeiro 1230c3d62cc9SAdrien Mazarguil /* 1231c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1232c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1233c3d62cc9SAdrien Mazarguil */ 1234a5bf6af9SAdrien Mazarguil assert(segs_n); 1235a5bf6af9SAdrien Mazarguil if (max < segs_n + 1) 1236c3d62cc9SAdrien Mazarguil break; 1237a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 1238a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 1239a5bf6af9SAdrien Mazarguil break; 1240a5bf6af9SAdrien Mazarguil max -= segs_n; 1241c3d62cc9SAdrien Mazarguil --pkts_n; 1242f04f1d51SNélio Laranjeiro /* 1243f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1244f04f1d51SNélio Laranjeiro * iteration. 1245f04f1d51SNélio Laranjeiro */ 1246f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 1247230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 1248230189d9SNélio Laranjeiro if (buf->ol_flags & 1249230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 1250230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 1251a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1252a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1253230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1254230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1255230189d9SNélio Laranjeiro if ((mpw.len != length) || 1256a5bf6af9SAdrien Mazarguil (segs_n != 1) || 12578688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1258230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1259230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1260230189d9SNélio Laranjeiro if ((mpw.len != length) || 1261a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1262230189d9SNélio Laranjeiro (length > inline_room) || 12638688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1264230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 12650e8679fcSNélio Laranjeiro inline_room = 12660e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1267230189d9SNélio Laranjeiro } 1268230189d9SNélio Laranjeiro } 1269230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1270a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1271a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1272f04f1d51SNélio Laranjeiro /* 1273f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1274f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1275f04f1d51SNélio Laranjeiro * such resources. 1276f04f1d51SNélio Laranjeiro */ 1277f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1278f04f1d51SNélio Laranjeiro break; 1279f04f1d51SNélio Laranjeiro max_wqe -= 2; 1280230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 12818688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1282230189d9SNélio Laranjeiro } else { 1283f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1284f04f1d51SNélio Laranjeiro break; 1285f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1286230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 12878688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1288230189d9SNélio Laranjeiro } 1289230189d9SNélio Laranjeiro } 1290a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1291a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1292230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 12930e8679fcSNélio Laranjeiro assert(inline_room == 12940e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1295a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1296a5bf6af9SAdrien Mazarguil length = 0; 1297a5bf6af9SAdrien Mazarguil #endif 1298a5bf6af9SAdrien Mazarguil do { 1299230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1300230189d9SNélio Laranjeiro 1301a5bf6af9SAdrien Mazarguil elts_head_next = 1302a5bf6af9SAdrien Mazarguil (elts_head + 1) & (elts_n - 1); 1303a5bf6af9SAdrien Mazarguil assert(buf); 1304a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1305230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1306a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1307230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 1308a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 1309230189d9SNélio Laranjeiro .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 1310230189d9SNélio Laranjeiro .addr = htonll(addr), 1311230189d9SNélio Laranjeiro }; 1312a5bf6af9SAdrien Mazarguil elts_head = elts_head_next; 1313a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1314a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1315a5bf6af9SAdrien Mazarguil #endif 1316a5bf6af9SAdrien Mazarguil buf = buf->next; 1317230189d9SNélio Laranjeiro ++mpw.pkts_n; 1318a5bf6af9SAdrien Mazarguil ++j; 1319a5bf6af9SAdrien Mazarguil } while (--segs_n); 1320a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1321230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1322230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1323230189d9SNélio Laranjeiro } else { 1324230189d9SNélio Laranjeiro unsigned int max; 1325230189d9SNélio Laranjeiro 1326230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1327230189d9SNélio Laranjeiro assert(length <= inline_room); 1328a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1329a5bf6af9SAdrien Mazarguil elts_head_next = (elts_head + 1) & (elts_n - 1); 1330a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1331a5bf6af9SAdrien Mazarguil (*txq->elts)[elts_head] = buf; 1332230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1333fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1334fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1335fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1336230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1337230189d9SNélio Laranjeiro if (length > max) { 1338230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1339230189d9SNélio Laranjeiro (void *)addr, 1340230189d9SNélio Laranjeiro max); 1341fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1342230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1343230189d9SNélio Laranjeiro (void *)(addr + max), 1344230189d9SNélio Laranjeiro length - max); 1345230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1346230189d9SNélio Laranjeiro } else { 1347230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1348230189d9SNélio Laranjeiro (void *)addr, 1349230189d9SNélio Laranjeiro length); 135016c64768SYongseok Koh 135116c64768SYongseok Koh if (length == max) 135216c64768SYongseok Koh mpw.data.raw = 135316c64768SYongseok Koh (volatile void *)txq->wqes; 135416c64768SYongseok Koh else 1355230189d9SNélio Laranjeiro mpw.data.raw += length; 1356230189d9SNélio Laranjeiro } 1357230189d9SNélio Laranjeiro ++mpw.pkts_n; 135876bf1574SYongseok Koh mpw.total_len += length; 1359a5bf6af9SAdrien Mazarguil ++j; 1360230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1361230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 13620e8679fcSNélio Laranjeiro inline_room = 13630e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1364230189d9SNélio Laranjeiro } else { 1365230189d9SNélio Laranjeiro inline_room -= length; 1366230189d9SNélio Laranjeiro } 1367230189d9SNélio Laranjeiro } 1368230189d9SNélio Laranjeiro elts_head = elts_head_next; 1369230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1370230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1371230189d9SNélio Laranjeiro txq->stats.obytes += length; 1372230189d9SNélio Laranjeiro #endif 1373c3d62cc9SAdrien Mazarguil ++i; 1374c3d62cc9SAdrien Mazarguil } while (pkts_n); 1375230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1376230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1377230189d9SNélio Laranjeiro return 0; 1378230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1379a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1380a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1381230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 13828688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1383230189d9SNélio Laranjeiro 1384230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 13858688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1386230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 13878688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1388230189d9SNélio Laranjeiro txq->elts_comp = 0; 1389230189d9SNélio Laranjeiro } else { 1390230189d9SNélio Laranjeiro txq->elts_comp = comp; 1391230189d9SNélio Laranjeiro } 1392230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1393230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1394230189d9SNélio Laranjeiro txq->stats.opackets += i; 1395230189d9SNélio Laranjeiro #endif 1396230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1397230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1398230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1399230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1400230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 140130807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1402230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1403230189d9SNélio Laranjeiro return i; 1404230189d9SNélio Laranjeiro } 1405230189d9SNélio Laranjeiro 1406230189d9SNélio Laranjeiro /** 14076ce84bd8SYongseok Koh * Open an Enhanced MPW session. 14086ce84bd8SYongseok Koh * 14096ce84bd8SYongseok Koh * @param txq 14106ce84bd8SYongseok Koh * Pointer to TX queue structure. 14116ce84bd8SYongseok Koh * @param mpw 14126ce84bd8SYongseok Koh * Pointer to MPW session structure. 14136ce84bd8SYongseok Koh * @param length 14146ce84bd8SYongseok Koh * Packet length. 14156ce84bd8SYongseok Koh */ 14166ce84bd8SYongseok Koh static inline void 14176ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding) 14186ce84bd8SYongseok Koh { 14196ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 14206ce84bd8SYongseok Koh 14216ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 14226ce84bd8SYongseok Koh mpw->pkts_n = 0; 14236ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 14246ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 14256ce84bd8SYongseok Koh mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 14266ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 14276ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 14286ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 14296ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 14306ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 14316ce84bd8SYongseok Koh if (unlikely(padding)) { 14326ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 14336ce84bd8SYongseok Koh 14346ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 14356ce84bd8SYongseok Koh *(volatile uint32_t *)addr = htonl(MLX5_INLINE_SEG); 14366ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 14376ce84bd8SYongseok Koh htonl(MLX5_INLINE_SEG); 14386ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 14396ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 14406ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 14416ce84bd8SYongseok Koh } else { 14426ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 14436ce84bd8SYongseok Koh } 14446ce84bd8SYongseok Koh } 14456ce84bd8SYongseok Koh 14466ce84bd8SYongseok Koh /** 14476ce84bd8SYongseok Koh * Close an Enhanced MPW session. 14486ce84bd8SYongseok Koh * 14496ce84bd8SYongseok Koh * @param txq 14506ce84bd8SYongseok Koh * Pointer to TX queue structure. 14516ce84bd8SYongseok Koh * @param mpw 14526ce84bd8SYongseok Koh * Pointer to MPW session structure. 14536ce84bd8SYongseok Koh * 14546ce84bd8SYongseok Koh * @return 14556ce84bd8SYongseok Koh * Number of consumed WQEs. 14566ce84bd8SYongseok Koh */ 14576ce84bd8SYongseok Koh static inline uint16_t 14586ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw) 14596ce84bd8SYongseok Koh { 14606ce84bd8SYongseok Koh uint16_t ret; 14616ce84bd8SYongseok Koh 14626ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 14636ce84bd8SYongseok Koh * count as 2. 14646ce84bd8SYongseok Koh */ 14656ce84bd8SYongseok Koh mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(mpw->total_len)); 14666ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 14676ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 14686ce84bd8SYongseok Koh txq->wqe_ci += ret; 14696ce84bd8SYongseok Koh return ret; 14706ce84bd8SYongseok Koh } 14716ce84bd8SYongseok Koh 14726ce84bd8SYongseok Koh /** 14736ce84bd8SYongseok Koh * DPDK callback for TX with Enhanced MPW support. 14746ce84bd8SYongseok Koh * 14756ce84bd8SYongseok Koh * @param dpdk_txq 14766ce84bd8SYongseok Koh * Generic pointer to TX queue structure. 14776ce84bd8SYongseok Koh * @param[in] pkts 14786ce84bd8SYongseok Koh * Packets to transmit. 14796ce84bd8SYongseok Koh * @param pkts_n 14806ce84bd8SYongseok Koh * Number of packets in array. 14816ce84bd8SYongseok Koh * 14826ce84bd8SYongseok Koh * @return 14836ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 14846ce84bd8SYongseok Koh */ 14856ce84bd8SYongseok Koh uint16_t 14866ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 14876ce84bd8SYongseok Koh { 14886ce84bd8SYongseok Koh struct txq *txq = (struct txq *)dpdk_txq; 14896ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 14906ce84bd8SYongseok Koh const unsigned int elts_n = 1 << txq->elts_n; 14916ce84bd8SYongseok Koh unsigned int i = 0; 14926ce84bd8SYongseok Koh unsigned int j = 0; 14936ce84bd8SYongseok Koh unsigned int max_elts; 14946ce84bd8SYongseok Koh uint16_t max_wqe; 14956ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 14966ce84bd8SYongseok Koh unsigned int mpw_room = 0; 14976ce84bd8SYongseok Koh unsigned int inl_pad = 0; 14986ce84bd8SYongseok Koh uint32_t inl_hdr; 14996ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 15006ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 15016ce84bd8SYongseok Koh }; 15026ce84bd8SYongseok Koh 15036ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 15046ce84bd8SYongseok Koh return 0; 15056ce84bd8SYongseok Koh /* Start processing. */ 15066ce84bd8SYongseok Koh txq_complete(txq); 15076ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 15086ce84bd8SYongseok Koh if (max_elts > elts_n) 15096ce84bd8SYongseok Koh max_elts -= elts_n; 15106ce84bd8SYongseok Koh /* A CQE slot must always be available. */ 15116ce84bd8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 15126ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 15136ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 15146ce84bd8SYongseok Koh return 0; 15156ce84bd8SYongseok Koh do { 15166ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 15176ce84bd8SYongseok Koh unsigned int elts_head_next; 15186ce84bd8SYongseok Koh uintptr_t addr; 15196ce84bd8SYongseok Koh uint64_t naddr; 15206ce84bd8SYongseok Koh unsigned int n; 15216ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 15226ce84bd8SYongseok Koh uint32_t length; 15236ce84bd8SYongseok Koh unsigned int segs_n = buf->nb_segs; 15246ce84bd8SYongseok Koh uint32_t cs_flags = 0; 15256ce84bd8SYongseok Koh 15266ce84bd8SYongseok Koh /* 15276ce84bd8SYongseok Koh * Make sure there is enough room to store this packet and 15286ce84bd8SYongseok Koh * that one ring entry remains unused. 15296ce84bd8SYongseok Koh */ 15306ce84bd8SYongseok Koh assert(segs_n); 15316ce84bd8SYongseok Koh if (max_elts - j < segs_n + 1) 15326ce84bd8SYongseok Koh break; 15336ce84bd8SYongseok Koh /* Do not bother with large packets MPW cannot handle. */ 15346ce84bd8SYongseok Koh if (segs_n > MLX5_MPW_DSEG_MAX) 15356ce84bd8SYongseok Koh break; 15366ce84bd8SYongseok Koh /* Should we enable HW CKSUM offload. */ 15376ce84bd8SYongseok Koh if (buf->ol_flags & 15386ce84bd8SYongseok Koh (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 15396ce84bd8SYongseok Koh cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 15406ce84bd8SYongseok Koh /* Retrieve packet information. */ 15416ce84bd8SYongseok Koh length = PKT_LEN(buf); 15426ce84bd8SYongseok Koh /* Start new session if: 15436ce84bd8SYongseok Koh * - multi-segment packet 15446ce84bd8SYongseok Koh * - no space left even for a dseg 15456ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 15466ce84bd8SYongseok Koh * - cs_flag differs 15476ce84bd8SYongseok Koh * It can't be MLX5_MPW_STATE_OPENED as always have a single 15486ce84bd8SYongseok Koh * segmented packet. 15496ce84bd8SYongseok Koh */ 15506ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 15516ce84bd8SYongseok Koh if ((segs_n != 1) || 15526ce84bd8SYongseok Koh (inl_pad + sizeof(struct mlx5_wqe_data_seg) > 15536ce84bd8SYongseok Koh mpw_room) || 15546ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 15556ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 15566ce84bd8SYongseok Koh mpw_room) || 15576ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 15586ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 15596ce84bd8SYongseok Koh } 15606ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 15616ce84bd8SYongseok Koh if (unlikely(segs_n != 1)) { 15626ce84bd8SYongseok Koh /* Fall back to legacy MPW. 15636ce84bd8SYongseok Koh * A MPW session consumes 2 WQEs at most to 15646ce84bd8SYongseok Koh * include MLX5_MPW_DSEG_MAX pointers. 15656ce84bd8SYongseok Koh */ 15666ce84bd8SYongseok Koh if (unlikely(max_wqe < 2)) 15676ce84bd8SYongseok Koh break; 15686ce84bd8SYongseok Koh mlx5_mpw_new(txq, &mpw, length); 15696ce84bd8SYongseok Koh } else { 15706ce84bd8SYongseok Koh /* In Enhanced MPW, inline as much as the budget 15716ce84bd8SYongseok Koh * is allowed. The remaining space is to be 15726ce84bd8SYongseok Koh * filled with dsegs. If the title WQEBB isn't 15736ce84bd8SYongseok Koh * padded, it will have 2 dsegs there. 15746ce84bd8SYongseok Koh */ 15756ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 15766ce84bd8SYongseok Koh (max_inline ? max_inline : 15776ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 15786ce84bd8SYongseok Koh MLX5_WQE_SIZE); 15796ce84bd8SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < 15806ce84bd8SYongseok Koh mpw_room)) 15816ce84bd8SYongseok Koh break; 15826ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 15836ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 15846ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 15856ce84bd8SYongseok Koh inl_pad = 0; 15866ce84bd8SYongseok Koh do_inline = 15876ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 15886ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 15896ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 15906ce84bd8SYongseok Koh } 15916ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 15926ce84bd8SYongseok Koh } else { 15936ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 15946ce84bd8SYongseok Koh * Inlininig is possible when: 15956ce84bd8SYongseok Koh * - length is less than configured value 15966ce84bd8SYongseok Koh * - length fits for remaining space 15976ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 15986ce84bd8SYongseok Koh */ 15996ce84bd8SYongseok Koh do_inline = 16006ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 16016ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 16026ce84bd8SYongseok Koh mpw_room && 16036ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 16046ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 16056ce84bd8SYongseok Koh } 16066ce84bd8SYongseok Koh /* Multi-segment packets must be alone in their MPW. */ 16076ce84bd8SYongseok Koh assert((segs_n == 1) || (mpw.pkts_n == 0)); 16086ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) { 16096ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 16106ce84bd8SYongseok Koh length = 0; 16116ce84bd8SYongseok Koh #endif 16126ce84bd8SYongseok Koh do { 16136ce84bd8SYongseok Koh volatile struct mlx5_wqe_data_seg *dseg; 16146ce84bd8SYongseok Koh 16156ce84bd8SYongseok Koh elts_head_next = 16166ce84bd8SYongseok Koh (elts_head + 1) & (elts_n - 1); 16176ce84bd8SYongseok Koh assert(buf); 16186ce84bd8SYongseok Koh (*txq->elts)[elts_head] = buf; 16196ce84bd8SYongseok Koh dseg = mpw.data.dseg[mpw.pkts_n]; 16206ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 16216ce84bd8SYongseok Koh *dseg = (struct mlx5_wqe_data_seg){ 16226ce84bd8SYongseok Koh .byte_count = htonl(DATA_LEN(buf)), 16236ce84bd8SYongseok Koh .lkey = txq_mp2mr(txq, txq_mb2mp(buf)), 16246ce84bd8SYongseok Koh .addr = htonll(addr), 16256ce84bd8SYongseok Koh }; 16266ce84bd8SYongseok Koh elts_head = elts_head_next; 16276ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 16286ce84bd8SYongseok Koh length += DATA_LEN(buf); 16296ce84bd8SYongseok Koh #endif 16306ce84bd8SYongseok Koh buf = buf->next; 16316ce84bd8SYongseok Koh ++j; 16326ce84bd8SYongseok Koh ++mpw.pkts_n; 16336ce84bd8SYongseok Koh } while (--segs_n); 16346ce84bd8SYongseok Koh /* A multi-segmented packet takes one MPW session. 16356ce84bd8SYongseok Koh * TODO: Pack more multi-segmented packets if possible. 16366ce84bd8SYongseok Koh */ 16376ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 16386ce84bd8SYongseok Koh if (mpw.pkts_n < 3) 16396ce84bd8SYongseok Koh max_wqe--; 16406ce84bd8SYongseok Koh else 16416ce84bd8SYongseok Koh max_wqe -= 2; 16426ce84bd8SYongseok Koh } else if (do_inline) { 16436ce84bd8SYongseok Koh /* Inline packet into WQE. */ 16446ce84bd8SYongseok Koh unsigned int max; 16456ce84bd8SYongseok Koh 16466ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 16476ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 16486ce84bd8SYongseok Koh inl_hdr = htonl(length | MLX5_INLINE_SEG); 16496ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 16506ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16516ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 16526ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 16536ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 16546ce84bd8SYongseok Koh /* Copy inline header. */ 16556ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16566ce84bd8SYongseok Koh mlx5_copy_to_wq( 16576ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 16586ce84bd8SYongseok Koh &inl_hdr, 16596ce84bd8SYongseok Koh sizeof(inl_hdr), 16606ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 16616ce84bd8SYongseok Koh max); 16626ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 16636ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 16646ce84bd8SYongseok Koh /* Copy packet data. */ 16656ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16666ce84bd8SYongseok Koh mlx5_copy_to_wq( 16676ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 16686ce84bd8SYongseok Koh (void *)addr, 16696ce84bd8SYongseok Koh length, 16706ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 16716ce84bd8SYongseok Koh max); 16726ce84bd8SYongseok Koh ++mpw.pkts_n; 16736ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 16746ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 16756ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 16766ce84bd8SYongseok Koh */ 16776ce84bd8SYongseok Koh elts_head_next = elts_head; 16786ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 16796ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 16806ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 16816ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 16826ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 16836ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 16846ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 16856ce84bd8SYongseok Koh } else { 16866ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 16876ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 16886ce84bd8SYongseok Koh 16896ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 16906ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 16916ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 16926ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 16936ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 16946ce84bd8SYongseok Koh + inl_pad))) 16956ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 16966ce84bd8SYongseok Koh else 16976ce84bd8SYongseok Koh dseg = (volatile void *) 16986ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 16996ce84bd8SYongseok Koh inl_pad); 17006ce84bd8SYongseok Koh elts_head_next = (elts_head + 1) & (elts_n - 1); 17016ce84bd8SYongseok Koh (*txq->elts)[elts_head] = buf; 17026ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 17036ce84bd8SYongseok Koh for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++) 17046ce84bd8SYongseok Koh rte_prefetch2((void *)(addr + 17056ce84bd8SYongseok Koh n * RTE_CACHE_LINE_SIZE)); 17066ce84bd8SYongseok Koh naddr = htonll(addr); 17076ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 17086ce84bd8SYongseok Koh htonl(length), 17096ce84bd8SYongseok Koh txq_mp2mr(txq, txq_mb2mp(buf)), 17106ce84bd8SYongseok Koh naddr, 17116ce84bd8SYongseok Koh naddr >> 32, 17126ce84bd8SYongseok Koh }; 17136ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 17146ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 17156ce84bd8SYongseok Koh ++j; 17166ce84bd8SYongseok Koh ++mpw.pkts_n; 17176ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 17186ce84bd8SYongseok Koh inl_pad = 0; 17196ce84bd8SYongseok Koh } 17206ce84bd8SYongseok Koh elts_head = elts_head_next; 17216ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 17226ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 17236ce84bd8SYongseok Koh txq->stats.obytes += length; 17246ce84bd8SYongseok Koh #endif 17256ce84bd8SYongseok Koh ++i; 17266ce84bd8SYongseok Koh } while (i < pkts_n); 17276ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 17286ce84bd8SYongseok Koh if (unlikely(i == 0)) 17296ce84bd8SYongseok Koh return 0; 17306ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 17316ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 17326ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 17336ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 17346ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 17356ce84bd8SYongseok Koh 17366ce84bd8SYongseok Koh /* Request completion on last WQE. */ 17376ce84bd8SYongseok Koh wqe->ctrl[2] = htonl(8); 17386ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 17396ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 17406ce84bd8SYongseok Koh txq->elts_comp = 0; 17416ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 17426ce84bd8SYongseok Koh txq->cq_pi++; 17436ce84bd8SYongseok Koh } else { 17446ce84bd8SYongseok Koh txq->elts_comp += j; 17456ce84bd8SYongseok Koh } 17466ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 17476ce84bd8SYongseok Koh /* Increment sent packets counter. */ 17486ce84bd8SYongseok Koh txq->stats.opackets += i; 17496ce84bd8SYongseok Koh #endif 17506ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 17516ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 17526ce84bd8SYongseok Koh else if (mpw.state == MLX5_MPW_STATE_OPENED) 17536ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 17546ce84bd8SYongseok Koh /* Ring QP doorbell. */ 17556ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 17566ce84bd8SYongseok Koh txq->elts_head = elts_head; 17576ce84bd8SYongseok Koh return i; 17586ce84bd8SYongseok Koh } 17596ce84bd8SYongseok Koh 17606ce84bd8SYongseok Koh /** 176167fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 176267fa62bcSAdrien Mazarguil * 17636218063bSNélio Laranjeiro * @param[in] cqe 17646218063bSNélio Laranjeiro * Pointer to CQE. 176567fa62bcSAdrien Mazarguil * 176678a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 176778a38edfSJianfeng Tan * 176867fa62bcSAdrien Mazarguil * @return 176967fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 177067fa62bcSAdrien Mazarguil */ 177167fa62bcSAdrien Mazarguil static inline uint32_t 177297267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 177367fa62bcSAdrien Mazarguil { 177467fa62bcSAdrien Mazarguil uint32_t pkt_type; 17750603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 177667fa62bcSAdrien Mazarguil 17770603df73SNélio Laranjeiro if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) { 177867fa62bcSAdrien Mazarguil pkt_type = 177967fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1780350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV4_PACKET, 1781501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) | 178267fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1783350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV6_PACKET, 1784501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN); 17850603df73SNélio Laranjeiro pkt_type |= ((cqe->pkt_info & MLX5_CQE_RX_OUTER_PACKET) ? 17860603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV6_EXT_UNKNOWN : 17870603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 17880603df73SNélio Laranjeiro } else { 178967fa62bcSAdrien Mazarguil pkt_type = 179067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 17916218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 1792501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) | 179367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 17946218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 1795501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 17960603df73SNélio Laranjeiro } 179767fa62bcSAdrien Mazarguil return pkt_type; 179867fa62bcSAdrien Mazarguil } 179967fa62bcSAdrien Mazarguil 180067fa62bcSAdrien Mazarguil /** 180199c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 180299c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 180399c12dccSNélio Laranjeiro * been processed. 180499c12dccSNélio Laranjeiro * 180599c12dccSNélio Laranjeiro * @param rxq 180699c12dccSNélio Laranjeiro * Pointer to RX queue. 180799c12dccSNélio Laranjeiro * @param cqe 180899c12dccSNélio Laranjeiro * CQE to process. 1809ecf60761SNélio Laranjeiro * @param[out] rss_hash 1810ecf60761SNélio Laranjeiro * Packet RSS Hash result. 181199c12dccSNélio Laranjeiro * 181299c12dccSNélio Laranjeiro * @return 181399c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 181499c12dccSNélio Laranjeiro * with error. 181599c12dccSNélio Laranjeiro */ 181699c12dccSNélio Laranjeiro static inline int 181797267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 1818ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 181999c12dccSNélio Laranjeiro { 182099c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 182199c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 182299c12dccSNélio Laranjeiro int len = 0; 1823d2e842d0SYongseok Koh uint16_t idx, end; 182499c12dccSNélio Laranjeiro 182599c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 182699c12dccSNélio Laranjeiro if (zip->ai) { 182799c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 182899c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 182997267b8eSNelio Laranjeiro (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt]); 183099c12dccSNélio Laranjeiro 183199c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 1832ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result); 183399c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1834d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1835d2e842d0SYongseok Koh idx = zip->ca; 1836d2e842d0SYongseok Koh end = zip->na; 1837d2e842d0SYongseok Koh while (idx != end) { 1838d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1839d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1840d2e842d0SYongseok Koh ++idx; 1841d2e842d0SYongseok Koh } 184299c12dccSNélio Laranjeiro /* 184399c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 184499c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 184599c12dccSNélio Laranjeiro * ring for software use. 184699c12dccSNélio Laranjeiro */ 184799c12dccSNélio Laranjeiro zip->ca = zip->na; 184899c12dccSNélio Laranjeiro zip->na += 8; 184999c12dccSNélio Laranjeiro } 185099c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1851d2e842d0SYongseok Koh /* Invalidate the rest */ 1852d2e842d0SYongseok Koh idx = zip->ca; 1853d2e842d0SYongseok Koh end = zip->cq_ci; 185499c12dccSNélio Laranjeiro 185599c12dccSNélio Laranjeiro while (idx != end) { 185697267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 185799c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 185899c12dccSNélio Laranjeiro ++idx; 185999c12dccSNélio Laranjeiro } 186099c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 186199c12dccSNélio Laranjeiro zip->ai = 0; 186299c12dccSNélio Laranjeiro } 186399c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 186499c12dccSNélio Laranjeiro } else { 186599c12dccSNélio Laranjeiro int ret; 186699c12dccSNélio Laranjeiro int8_t op_own; 186799c12dccSNélio Laranjeiro 186897267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 186999c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 187099c12dccSNélio Laranjeiro return 0; 187199c12dccSNélio Laranjeiro ++rxq->cq_ci; 187299c12dccSNélio Laranjeiro op_own = cqe->op_own; 187399c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 187499c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 187599c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 187699c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 187797267b8eSNelio Laranjeiro cqe_cnt]); 187899c12dccSNélio Laranjeiro 187999c12dccSNélio Laranjeiro /* Fix endianness. */ 188099c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 188199c12dccSNélio Laranjeiro /* 188299c12dccSNélio Laranjeiro * Current mini array position is the one returned by 188399c12dccSNélio Laranjeiro * check_cqe64(). 188499c12dccSNélio Laranjeiro * 188599c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 188699c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 188799c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 188899c12dccSNélio Laranjeiro */ 1889d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 189099c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 189199c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 189299c12dccSNélio Laranjeiro --rxq->cq_ci; 189399c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 189499c12dccSNélio Laranjeiro /* Get packet size to return. */ 189599c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 1896ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[0].rx_hash_result); 189799c12dccSNélio Laranjeiro zip->ai = 1; 1898d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1899d2e842d0SYongseok Koh idx = zip->ca; 1900d2e842d0SYongseok Koh end = zip->cq_ci; 1901d2e842d0SYongseok Koh while (idx != end) { 1902d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1903d2e842d0SYongseok Koh ++idx; 1904d2e842d0SYongseok Koh } 190599c12dccSNélio Laranjeiro } else { 190699c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 1907ecf60761SNélio Laranjeiro *rss_hash = ntohl(cqe->rx_hash_res); 190899c12dccSNélio Laranjeiro } 190999c12dccSNélio Laranjeiro /* Error while receiving packet. */ 191099c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 191199c12dccSNélio Laranjeiro return -1; 191299c12dccSNélio Laranjeiro } 191399c12dccSNélio Laranjeiro return len; 191499c12dccSNélio Laranjeiro } 191599c12dccSNélio Laranjeiro 191699c12dccSNélio Laranjeiro /** 191767fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 191867fa62bcSAdrien Mazarguil * 191967fa62bcSAdrien Mazarguil * @param[in] rxq 192067fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 19216218063bSNélio Laranjeiro * @param[in] cqe 19226218063bSNélio Laranjeiro * Pointer to CQE. 192367fa62bcSAdrien Mazarguil * 192467fa62bcSAdrien Mazarguil * @return 192567fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 192667fa62bcSAdrien Mazarguil */ 192767fa62bcSAdrien Mazarguil static inline uint32_t 192897267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe) 192967fa62bcSAdrien Mazarguil { 193067fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 19310603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 193267fa62bcSAdrien Mazarguil 19330603df73SNélio Laranjeiro ol_flags = 19340603df73SNélio Laranjeiro TRANSPOSE(flags, 19350603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 19360603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 19370603df73SNélio Laranjeiro TRANSPOSE(flags, 19380603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 193983e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 194097267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 194167fa62bcSAdrien Mazarguil ol_flags |= 19420603df73SNélio Laranjeiro TRANSPOSE(flags, 19430603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 194483e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 19450603df73SNélio Laranjeiro TRANSPOSE(flags, 19460603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 194783e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 194867fa62bcSAdrien Mazarguil return ol_flags; 194967fa62bcSAdrien Mazarguil } 195067fa62bcSAdrien Mazarguil 195167fa62bcSAdrien Mazarguil /** 19522e22920bSAdrien Mazarguil * DPDK callback for RX. 19532e22920bSAdrien Mazarguil * 19542e22920bSAdrien Mazarguil * @param dpdk_rxq 19552e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 19562e22920bSAdrien Mazarguil * @param[out] pkts 19572e22920bSAdrien Mazarguil * Array to store received packets. 19582e22920bSAdrien Mazarguil * @param pkts_n 19592e22920bSAdrien Mazarguil * Maximum number of packets in array. 19602e22920bSAdrien Mazarguil * 19612e22920bSAdrien Mazarguil * @return 19622e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 19632e22920bSAdrien Mazarguil */ 19642e22920bSAdrien Mazarguil uint16_t 19652e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 19662e22920bSAdrien Mazarguil { 19676218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 1968b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1969e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 19709964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 19719964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 19729964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 197397267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 197497267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 19759964b965SNélio Laranjeiro unsigned int i = 0; 19769964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 19774e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 19782e22920bSAdrien Mazarguil 19799964b965SNélio Laranjeiro while (pkts_n) { 19809964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 19819964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 19829964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1983ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 19849964b965SNélio Laranjeiro 19859964b965SNélio Laranjeiro if (pkt) 19869964b965SNélio Laranjeiro NEXT(seg) = rep; 19879964b965SNélio Laranjeiro seg = rep; 19889964b965SNélio Laranjeiro rte_prefetch0(seg); 19896218063bSNélio Laranjeiro rte_prefetch0(cqe); 19909964b965SNélio Laranjeiro rte_prefetch0(wqe); 1991fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 19922e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 199315a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 199415a756b6SSagi Grimberg if (!pkt) { 199515a756b6SSagi Grimberg /* 199615a756b6SSagi Grimberg * no buffers before we even started, 199715a756b6SSagi Grimberg * bail out silently. 199815a756b6SSagi Grimberg */ 199915a756b6SSagi Grimberg break; 200015a756b6SSagi Grimberg } 2001a1bdb71aSNélio Laranjeiro while (pkt != seg) { 2002a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 2003fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 20048f094a9aSOlivier Matz NEXT(pkt) = NULL; 20058f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 20061f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 2007fe5fe382SNélio Laranjeiro pkt = rep; 20089964b965SNélio Laranjeiro } 20096218063bSNélio Laranjeiro break; 20102e22920bSAdrien Mazarguil } 20119964b965SNélio Laranjeiro if (!pkt) { 201297267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 2013ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 2014ecf60761SNélio Laranjeiro &rss_hash_res); 2015ecf60761SNélio Laranjeiro if (!len) { 20161f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 20176218063bSNélio Laranjeiro break; 20186218063bSNélio Laranjeiro } 201999c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 202099c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 20211f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 202299c12dccSNélio Laranjeiro ++rxq->stats.idropped; 202399c12dccSNélio Laranjeiro goto skip; 202499c12dccSNélio Laranjeiro } 20259964b965SNélio Laranjeiro pkt = seg; 20269964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 20279964b965SNélio Laranjeiro /* Update packet information. */ 20280ac64846SMaxime Leroy pkt->packet_type = 0; 20290ac64846SMaxime Leroy pkt->ol_flags = 0; 203036ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 2031ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 2032ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 2033ecf60761SNélio Laranjeiro } 2034c604f619SNélio Laranjeiro if (rxq->mark && 2035c604f619SNélio Laranjeiro MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 2036b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 2037b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 2038b268a3eeSNélio Laranjeiro htonl(MLX5_FLOW_MARK_DEFAULT)) { 2039b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 2040b268a3eeSNélio Laranjeiro 2041b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 2042ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 2043b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 2044b268a3eeSNélio Laranjeiro } 2045ea3bc3b1SNélio Laranjeiro } 20466703d836SNélio Laranjeiro if (rxq->csum | rxq->csum_l2tun) { 20476703d836SNélio Laranjeiro pkt->packet_type = rxq_cq_to_pkt_type(cqe); 20486703d836SNélio Laranjeiro pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe); 20496218063bSNélio Laranjeiro } 20506703d836SNélio Laranjeiro if (rxq->vlan_strip && 20516703d836SNélio Laranjeiro (cqe->hdr_type_etc & 20526703d836SNélio Laranjeiro htons(MLX5_CQE_VLAN_STRIPPED))) { 20536218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 2054b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 20556218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 2056f3db9489SYaacov Hazan } 20576218063bSNélio Laranjeiro if (rxq->crc_present) 20586218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 20596218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 20609964b965SNélio Laranjeiro } 20619964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 20629964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 20639964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 20649964b965SNélio Laranjeiro NB_SEGS(rep) = NB_SEGS(seg); 20659964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 20669964b965SNélio Laranjeiro NEXT(rep) = NULL; 20679964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 20689964b965SNélio Laranjeiro /* 20699964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 20709964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 20719964b965SNélio Laranjeiro * changes. 20729964b965SNélio Laranjeiro */ 20739964b965SNélio Laranjeiro wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t)); 20749964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 20759964b965SNélio Laranjeiro len -= DATA_LEN(seg); 20769964b965SNélio Laranjeiro ++NB_SEGS(pkt); 20779964b965SNélio Laranjeiro ++rq_ci; 20789964b965SNélio Laranjeiro continue; 20799964b965SNélio Laranjeiro } 20809964b965SNélio Laranjeiro DATA_LEN(seg) = len; 208187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 208287011737SAdrien Mazarguil /* Increment bytes counter. */ 20839964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 208487011737SAdrien Mazarguil #endif 20856218063bSNélio Laranjeiro /* Return packet. */ 20866218063bSNélio Laranjeiro *(pkts++) = pkt; 20879964b965SNélio Laranjeiro pkt = NULL; 20889964b965SNélio Laranjeiro --pkts_n; 20899964b965SNélio Laranjeiro ++i; 209099c12dccSNélio Laranjeiro skip: 20919964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 20929964b965SNélio Laranjeiro rq_ci >>= sges_n; 20936218063bSNélio Laranjeiro ++rq_ci; 20949964b965SNélio Laranjeiro rq_ci <<= sges_n; 20952e22920bSAdrien Mazarguil } 20969964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 20972e22920bSAdrien Mazarguil return 0; 20986218063bSNélio Laranjeiro /* Update the consumer index. */ 20999964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 21006218063bSNélio Laranjeiro rte_wmb(); 21016218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 21026218063bSNélio Laranjeiro rte_wmb(); 21036218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 210487011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 210587011737SAdrien Mazarguil /* Increment packets counter. */ 21069964b965SNélio Laranjeiro rxq->stats.ipackets += i; 210787011737SAdrien Mazarguil #endif 21089964b965SNélio Laranjeiro return i; 21092e22920bSAdrien Mazarguil } 21102e22920bSAdrien Mazarguil 21112e22920bSAdrien Mazarguil /** 21122e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 21132e22920bSAdrien Mazarguil * 21142e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 21152e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 21162e22920bSAdrien Mazarguil * 21172e22920bSAdrien Mazarguil * @param dpdk_txq 21182e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 21192e22920bSAdrien Mazarguil * @param[in] pkts 21202e22920bSAdrien Mazarguil * Packets to transmit. 21212e22920bSAdrien Mazarguil * @param pkts_n 21222e22920bSAdrien Mazarguil * Number of packets in array. 21232e22920bSAdrien Mazarguil * 21242e22920bSAdrien Mazarguil * @return 21252e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 21262e22920bSAdrien Mazarguil */ 21272e22920bSAdrien Mazarguil uint16_t 21282e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 21292e22920bSAdrien Mazarguil { 21302e22920bSAdrien Mazarguil (void)dpdk_txq; 21312e22920bSAdrien Mazarguil (void)pkts; 21322e22920bSAdrien Mazarguil (void)pkts_n; 21332e22920bSAdrien Mazarguil return 0; 21342e22920bSAdrien Mazarguil } 21352e22920bSAdrien Mazarguil 21362e22920bSAdrien Mazarguil /** 21372e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 21382e22920bSAdrien Mazarguil * 21392e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 21402e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 21412e22920bSAdrien Mazarguil * 21422e22920bSAdrien Mazarguil * @param dpdk_rxq 21432e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 21442e22920bSAdrien Mazarguil * @param[out] pkts 21452e22920bSAdrien Mazarguil * Array to store received packets. 21462e22920bSAdrien Mazarguil * @param pkts_n 21472e22920bSAdrien Mazarguil * Maximum number of packets in array. 21482e22920bSAdrien Mazarguil * 21492e22920bSAdrien Mazarguil * @return 21502e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 21512e22920bSAdrien Mazarguil */ 21522e22920bSAdrien Mazarguil uint16_t 21532e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 21542e22920bSAdrien Mazarguil { 21552e22920bSAdrien Mazarguil (void)dpdk_rxq; 21562e22920bSAdrien Mazarguil (void)pkts; 21572e22920bSAdrien Mazarguil (void)pkts_n; 21582e22920bSAdrien Mazarguil return 0; 21592e22920bSAdrien Mazarguil } 21603c7d44afSShahaf Shuler 21613c7d44afSShahaf Shuler /** 21623c7d44afSShahaf Shuler * DPDK callback for rx queue interrupt enable. 21633c7d44afSShahaf Shuler * 21643c7d44afSShahaf Shuler * @param dev 21653c7d44afSShahaf Shuler * Pointer to Ethernet device structure. 21663c7d44afSShahaf Shuler * @param rx_queue_id 21673c7d44afSShahaf Shuler * RX queue number 21683c7d44afSShahaf Shuler * 21693c7d44afSShahaf Shuler * @return 21703c7d44afSShahaf Shuler * 0 on success, negative on failure. 21713c7d44afSShahaf Shuler */ 21723c7d44afSShahaf Shuler int 21733c7d44afSShahaf Shuler mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id) 21743c7d44afSShahaf Shuler { 21753c7d44afSShahaf Shuler #ifdef HAVE_UPDATE_CQ_CI 21763c7d44afSShahaf Shuler struct priv *priv = mlx5_get_priv(dev); 21773c7d44afSShahaf Shuler struct rxq *rxq = (*priv->rxqs)[rx_queue_id]; 21783c7d44afSShahaf Shuler struct rxq_ctrl *rxq_ctrl = container_of(rxq, struct rxq_ctrl, rxq); 21793c7d44afSShahaf Shuler struct ibv_cq *cq = rxq_ctrl->cq; 21803c7d44afSShahaf Shuler uint16_t ci = rxq->cq_ci; 21813c7d44afSShahaf Shuler int ret = 0; 21823c7d44afSShahaf Shuler 21833c7d44afSShahaf Shuler ibv_mlx5_exp_update_cq_ci(cq, ci); 21843c7d44afSShahaf Shuler ret = ibv_req_notify_cq(cq, 0); 21853c7d44afSShahaf Shuler #else 21863c7d44afSShahaf Shuler int ret = -1; 21873c7d44afSShahaf Shuler (void)dev; 21883c7d44afSShahaf Shuler (void)rx_queue_id; 21893c7d44afSShahaf Shuler #endif 21903c7d44afSShahaf Shuler if (ret) 21913c7d44afSShahaf Shuler WARN("unable to arm interrupt on rx queue %d", rx_queue_id); 21923c7d44afSShahaf Shuler return ret; 21933c7d44afSShahaf Shuler } 21943c7d44afSShahaf Shuler 21953c7d44afSShahaf Shuler /** 21963c7d44afSShahaf Shuler * DPDK callback for rx queue interrupt disable. 21973c7d44afSShahaf Shuler * 21983c7d44afSShahaf Shuler * @param dev 21993c7d44afSShahaf Shuler * Pointer to Ethernet device structure. 22003c7d44afSShahaf Shuler * @param rx_queue_id 22013c7d44afSShahaf Shuler * RX queue number 22023c7d44afSShahaf Shuler * 22033c7d44afSShahaf Shuler * @return 22043c7d44afSShahaf Shuler * 0 on success, negative on failure. 22053c7d44afSShahaf Shuler */ 22063c7d44afSShahaf Shuler int 22073c7d44afSShahaf Shuler mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id) 22083c7d44afSShahaf Shuler { 22093c7d44afSShahaf Shuler #ifdef HAVE_UPDATE_CQ_CI 22103c7d44afSShahaf Shuler struct priv *priv = mlx5_get_priv(dev); 22113c7d44afSShahaf Shuler struct rxq *rxq = (*priv->rxqs)[rx_queue_id]; 22123c7d44afSShahaf Shuler struct rxq_ctrl *rxq_ctrl = container_of(rxq, struct rxq_ctrl, rxq); 22133c7d44afSShahaf Shuler struct ibv_cq *cq = rxq_ctrl->cq; 22143c7d44afSShahaf Shuler struct ibv_cq *ev_cq; 22153c7d44afSShahaf Shuler void *ev_ctx; 22163c7d44afSShahaf Shuler int ret = 0; 22173c7d44afSShahaf Shuler 22183c7d44afSShahaf Shuler ret = ibv_get_cq_event(cq->channel, &ev_cq, &ev_ctx); 22193c7d44afSShahaf Shuler if (ret || ev_cq != cq) 22203c7d44afSShahaf Shuler ret = -1; 22213c7d44afSShahaf Shuler else 22223c7d44afSShahaf Shuler ibv_ack_cq_events(cq, 1); 22233c7d44afSShahaf Shuler #else 22243c7d44afSShahaf Shuler int ret = -1; 22253c7d44afSShahaf Shuler (void)dev; 22263c7d44afSShahaf Shuler (void)rx_queue_id; 22273c7d44afSShahaf Shuler #endif 22283c7d44afSShahaf Shuler if (ret) 22293c7d44afSShahaf Shuler WARN("unable to disable interrupt on rx queue %d", 22303c7d44afSShahaf Shuler rx_queue_id); 22313c7d44afSShahaf Shuler return ret; 22323c7d44afSShahaf Shuler } 2233