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> 4543e9d979SShachar Beiser #include <infiniband/mlx5dv.h> 462e22920bSAdrien Mazarguil #ifdef PEDANTIC 47fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 482e22920bSAdrien Mazarguil #endif 492e22920bSAdrien Mazarguil 502e22920bSAdrien Mazarguil #include <rte_mbuf.h> 512e22920bSAdrien Mazarguil #include <rte_mempool.h> 522e22920bSAdrien Mazarguil #include <rte_prefetch.h> 532e22920bSAdrien Mazarguil #include <rte_common.h> 542e22920bSAdrien Mazarguil #include <rte_branch_prediction.h> 556218063bSNélio Laranjeiro #include <rte_ether.h> 562e22920bSAdrien Mazarguil 572e22920bSAdrien Mazarguil #include "mlx5.h" 582e22920bSAdrien Mazarguil #include "mlx5_utils.h" 592e22920bSAdrien Mazarguil #include "mlx5_rxtx.h" 60f3db9489SYaacov Hazan #include "mlx5_autoconf.h" 612e22920bSAdrien Mazarguil #include "mlx5_defs.h" 626218063bSNélio Laranjeiro #include "mlx5_prm.h" 636218063bSNélio Laranjeiro 64c0583d98SJerin Jacob static __rte_always_inline uint32_t 65c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe); 66ff1807a3SNélio Laranjeiro 67c0583d98SJerin Jacob static __rte_always_inline int 6878142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 69c0583d98SJerin Jacob uint16_t cqe_cnt, uint32_t *rss_hash); 70ff1807a3SNélio Laranjeiro 71c0583d98SJerin Jacob static __rte_always_inline uint32_t 7278142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe); 73ff1807a3SNélio Laranjeiro 74ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = { 75ea16068cSYongseok Koh [0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */ 76ea16068cSYongseok Koh }; 77ea16068cSYongseok Koh 78ea16068cSYongseok Koh /** 79ea16068cSYongseok Koh * Build a table to translate Rx completion flags to packet type. 80ea16068cSYongseok Koh * 81ea16068cSYongseok Koh * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 82ea16068cSYongseok Koh */ 83ea16068cSYongseok Koh void 84ea16068cSYongseok Koh mlx5_set_ptype_table(void) 85ea16068cSYongseok Koh { 86ea16068cSYongseok Koh unsigned int i; 87ea16068cSYongseok Koh uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table; 88ea16068cSYongseok Koh 899807f113SYongseok Koh /* Last entry must not be overwritten, reserved for errored packet. */ 909807f113SYongseok Koh for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i) 91ea16068cSYongseok Koh (*p)[i] = RTE_PTYPE_UNKNOWN; 926cb559d6SYongseok Koh /* 936cb559d6SYongseok Koh * The index to the array should have: 94ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 95ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 96ea16068cSYongseok Koh * bit[5] = ip_frag 97ea16068cSYongseok Koh * bit[6] = tunneled 98ea16068cSYongseok Koh * bit[7] = outer_l3_type 9999c12dccSNélio Laranjeiro */ 1003ca63b88SShahaf Shuler /* L2 */ 1013ca63b88SShahaf Shuler (*p)[0x00] = RTE_PTYPE_L2_ETHER; 102ea16068cSYongseok Koh /* L3 */ 103ea16068cSYongseok Koh (*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 104ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 105ea16068cSYongseok Koh (*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 106ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 107ea16068cSYongseok Koh /* Fragmented */ 108ea16068cSYongseok Koh (*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 109ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 110ea16068cSYongseok Koh (*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 111ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 112ea16068cSYongseok Koh /* TCP */ 113ea16068cSYongseok Koh (*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 114ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 115ea16068cSYongseok Koh (*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 116ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 117ea16068cSYongseok Koh /* UDP */ 118ea16068cSYongseok Koh (*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 119ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 120ea16068cSYongseok Koh (*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 121ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 122ea16068cSYongseok Koh /* Repeat with outer_l3_type being set. Just in case. */ 123ea16068cSYongseok Koh (*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 124ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 125ea16068cSYongseok Koh (*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 126ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 127ea16068cSYongseok Koh (*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 128ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 129ea16068cSYongseok Koh (*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 130ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 131ea16068cSYongseok Koh (*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 132ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 133ea16068cSYongseok Koh (*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 134ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 135ea16068cSYongseok Koh (*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 136ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 137ea16068cSYongseok Koh (*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 138ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 139ea16068cSYongseok Koh /* Tunneled - L3 */ 140ea16068cSYongseok Koh (*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 141ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 142ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 143ea16068cSYongseok Koh (*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 144ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 145ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 146ea16068cSYongseok Koh (*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 147ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 148ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 149ea16068cSYongseok Koh (*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 150ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 151ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 152ea16068cSYongseok Koh /* Tunneled - Fragmented */ 153ea16068cSYongseok Koh (*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 154ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 155ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 156ea16068cSYongseok Koh (*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 157ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 158ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 159ea16068cSYongseok Koh (*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 160ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 161ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 162ea16068cSYongseok Koh (*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 163ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 164ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 165ea16068cSYongseok Koh /* Tunneled - TCP */ 166ea16068cSYongseok Koh (*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 167ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1686c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 169ea16068cSYongseok Koh (*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 170ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1716c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 172ea16068cSYongseok Koh (*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 173ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1746c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 175ea16068cSYongseok Koh (*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 176ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1776c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 178ea16068cSYongseok Koh /* Tunneled - UDP */ 179ea16068cSYongseok Koh (*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 180ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1816c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 182ea16068cSYongseok Koh (*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 183ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1846c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 185ea16068cSYongseok Koh (*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 186ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1876c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 188ea16068cSYongseok Koh (*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 189ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1906c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 191ea16068cSYongseok Koh } 192fdcb0f53SNélio Laranjeiro 1932e22920bSAdrien Mazarguil /** 1946ce84bd8SYongseok Koh * Return the size of tailroom of WQ. 1956ce84bd8SYongseok Koh * 1966ce84bd8SYongseok Koh * @param txq 1976ce84bd8SYongseok Koh * Pointer to TX queue structure. 1986ce84bd8SYongseok Koh * @param addr 1996ce84bd8SYongseok Koh * Pointer to tail of WQ. 2006ce84bd8SYongseok Koh * 2016ce84bd8SYongseok Koh * @return 2026ce84bd8SYongseok Koh * Size of tailroom. 2036ce84bd8SYongseok Koh */ 2046ce84bd8SYongseok Koh static inline size_t 205991b04f6SNélio Laranjeiro tx_mlx5_wq_tailroom(struct mlx5_txq_data *txq, void *addr) 2066ce84bd8SYongseok Koh { 2076ce84bd8SYongseok Koh size_t tailroom; 2086ce84bd8SYongseok Koh tailroom = (uintptr_t)(txq->wqes) + 2096ce84bd8SYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE - 2106ce84bd8SYongseok Koh (uintptr_t)addr; 2116ce84bd8SYongseok Koh return tailroom; 2126ce84bd8SYongseok Koh } 2136ce84bd8SYongseok Koh 2146ce84bd8SYongseok Koh /** 2156ce84bd8SYongseok Koh * Copy data to tailroom of circular queue. 2166ce84bd8SYongseok Koh * 2176ce84bd8SYongseok Koh * @param dst 2186ce84bd8SYongseok Koh * Pointer to destination. 2196ce84bd8SYongseok Koh * @param src 2206ce84bd8SYongseok Koh * Pointer to source. 2216ce84bd8SYongseok Koh * @param n 2226ce84bd8SYongseok Koh * Number of bytes to copy. 2236ce84bd8SYongseok Koh * @param base 2246ce84bd8SYongseok Koh * Pointer to head of queue. 2256ce84bd8SYongseok Koh * @param tailroom 2266ce84bd8SYongseok Koh * Size of tailroom from dst. 2276ce84bd8SYongseok Koh * 2286ce84bd8SYongseok Koh * @return 2296ce84bd8SYongseok Koh * Pointer after copied data. 2306ce84bd8SYongseok Koh */ 2316ce84bd8SYongseok Koh static inline void * 2326ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n, 2336ce84bd8SYongseok Koh void *base, size_t tailroom) 2346ce84bd8SYongseok Koh { 2356ce84bd8SYongseok Koh void *ret; 2366ce84bd8SYongseok Koh 2376ce84bd8SYongseok Koh if (n > tailroom) { 2386ce84bd8SYongseok Koh rte_memcpy(dst, src, tailroom); 2396ce84bd8SYongseok Koh rte_memcpy(base, (void *)((uintptr_t)src + tailroom), 2406ce84bd8SYongseok Koh n - tailroom); 2416ce84bd8SYongseok Koh ret = (uint8_t *)base + n - tailroom; 2426ce84bd8SYongseok Koh } else { 2436ce84bd8SYongseok Koh rte_memcpy(dst, src, n); 2446ce84bd8SYongseok Koh ret = (n == tailroom) ? base : (uint8_t *)dst + n; 2456ce84bd8SYongseok Koh } 2466ce84bd8SYongseok Koh return ret; 2476ce84bd8SYongseok Koh } 2486ce84bd8SYongseok Koh 2496ce84bd8SYongseok Koh /** 2508788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 2518788fec1SOlivier Matz * 2528788fec1SOlivier Matz * @param tx_queue 2538788fec1SOlivier Matz * The tx queue. 2548788fec1SOlivier Matz * @param[in] offset 2558788fec1SOlivier Matz * The index of the descriptor in the ring. 2568788fec1SOlivier Matz * 2578788fec1SOlivier Matz * @return 2588788fec1SOlivier Matz * The status of the tx descriptor. 2598788fec1SOlivier Matz */ 2608788fec1SOlivier Matz int 2618788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 2628788fec1SOlivier Matz { 263991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = tx_queue; 2648c819a69SYongseok Koh uint16_t used; 2658788fec1SOlivier Matz 2666cb559d6SYongseok Koh mlx5_tx_complete(txq); 2678c819a69SYongseok Koh used = txq->elts_head - txq->elts_tail; 2688788fec1SOlivier Matz if (offset < used) 2698788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 2708788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 2718788fec1SOlivier Matz } 2728788fec1SOlivier Matz 2738788fec1SOlivier Matz /** 2748788fec1SOlivier Matz * DPDK callback to check the status of a rx descriptor. 2758788fec1SOlivier Matz * 2768788fec1SOlivier Matz * @param rx_queue 2778788fec1SOlivier Matz * The rx queue. 2788788fec1SOlivier Matz * @param[in] offset 2798788fec1SOlivier Matz * The index of the descriptor in the ring. 2808788fec1SOlivier Matz * 2818788fec1SOlivier Matz * @return 2828788fec1SOlivier Matz * The status of the tx descriptor. 2838788fec1SOlivier Matz */ 2848788fec1SOlivier Matz int 2858788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 2868788fec1SOlivier Matz { 28778142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = rx_queue; 2888788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 2898788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 2908788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 2918788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 2928788fec1SOlivier Matz unsigned int cq_ci; 2938788fec1SOlivier Matz unsigned int used; 2948788fec1SOlivier Matz 2958788fec1SOlivier Matz /* if we are processing a compressed cqe */ 2968788fec1SOlivier Matz if (zip->ai) { 2978788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 2988788fec1SOlivier Matz cq_ci = zip->cq_ci; 2998788fec1SOlivier Matz } else { 3008788fec1SOlivier Matz used = 0; 3018788fec1SOlivier Matz cq_ci = rxq->cq_ci; 3028788fec1SOlivier Matz } 3038788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 3048788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 3058788fec1SOlivier Matz int8_t op_own; 3068788fec1SOlivier Matz unsigned int n; 3078788fec1SOlivier Matz 3088788fec1SOlivier Matz op_own = cqe->op_own; 3098788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 3106b30a6a8SShachar Beiser n = rte_be_to_cpu_32(cqe->byte_cnt); 3118788fec1SOlivier Matz else 3128788fec1SOlivier Matz n = 1; 3138788fec1SOlivier Matz cq_ci += n; 3148788fec1SOlivier Matz used += n; 3158788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 3168788fec1SOlivier Matz } 3178788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 3188788fec1SOlivier Matz if (offset < used) 3198788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 3208788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 3218788fec1SOlivier Matz } 3228788fec1SOlivier Matz 3238788fec1SOlivier Matz /** 3242e22920bSAdrien Mazarguil * DPDK callback for TX. 3252e22920bSAdrien Mazarguil * 3262e22920bSAdrien Mazarguil * @param dpdk_txq 3272e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 3282e22920bSAdrien Mazarguil * @param[in] pkts 3292e22920bSAdrien Mazarguil * Packets to transmit. 3302e22920bSAdrien Mazarguil * @param pkts_n 3312e22920bSAdrien Mazarguil * Number of packets in array. 3322e22920bSAdrien Mazarguil * 3332e22920bSAdrien Mazarguil * @return 3342e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 3352e22920bSAdrien Mazarguil */ 3362e22920bSAdrien Mazarguil uint16_t 3372e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 3382e22920bSAdrien Mazarguil { 339991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 3401d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 3418c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 3428c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 343c3d62cc9SAdrien Mazarguil unsigned int i = 0; 344a5bf6af9SAdrien Mazarguil unsigned int j = 0; 3453f13f8c2SShahaf Shuler unsigned int k = 0; 3468c819a69SYongseok Koh uint16_t max_elts; 347f04f1d51SNélio Laranjeiro uint16_t max_wqe; 348c305090bSAdrien Mazarguil unsigned int comp; 349ac180a21SYongseok Koh volatile struct mlx5_wqe_ctrl *last_wqe = NULL; 3506579c27cSNélio Laranjeiro unsigned int segs_n = 0; 35127a6b2d6SNélio Laranjeiro const unsigned int max_inline = txq->max_inline; 3522e22920bSAdrien Mazarguil 3531d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 3541d88ba17SNélio Laranjeiro return 0; 3555e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 356c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 3571d88ba17SNélio Laranjeiro /* Start processing. */ 3586cb559d6SYongseok Koh mlx5_tx_complete(txq); 3598c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 3602eefbec5SYongseok Koh /* A CQE slot must always be available. */ 3612eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 362f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 363f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 364f04f1d51SNélio Laranjeiro return 0; 365c3d62cc9SAdrien Mazarguil do { 3663bbae1ebSNélio Laranjeiro struct rte_mbuf *buf = NULL; 3673bbae1ebSNélio Laranjeiro uint8_t *raw; 3683bbae1ebSNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 3699a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 370573f54afSNélio Laranjeiro uint32_t length; 3718688b2f8SNélio Laranjeiro unsigned int ds = 0; 372ac180a21SYongseok Koh unsigned int sg = 0; /* counter of additional segs attached. */ 3736579c27cSNélio Laranjeiro uintptr_t addr; 3740d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 3753f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 376eef822ddSNélio Laranjeiro uint16_t ehdr; 3774aa15eb1SNélio Laranjeiro uint8_t cs_flags; 3783f13f8c2SShahaf Shuler uint64_t tso = 0; 37983daf156SShahaf Shuler uint16_t tso_segsz = 0; 3806579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 3816579c27cSNélio Laranjeiro uint32_t total_length = 0; 3826579c27cSNélio Laranjeiro #endif 3832e22920bSAdrien Mazarguil 3846579c27cSNélio Laranjeiro /* first_seg */ 3853730e6c6SYongseok Koh buf = *pkts; 3866579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 387c3d62cc9SAdrien Mazarguil /* 388c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 389c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 390c3d62cc9SAdrien Mazarguil */ 391a5bf6af9SAdrien Mazarguil assert(segs_n); 3928c819a69SYongseok Koh if (max_elts < segs_n) 393c3d62cc9SAdrien Mazarguil break; 3948c819a69SYongseok Koh max_elts -= segs_n; 395f895536bSYongseok Koh sg = --segs_n; 396f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 397f04f1d51SNélio Laranjeiro break; 3989a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 399fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 400fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 4013730e6c6SYongseok Koh if (pkts_n - i > 1) 4023730e6c6SYongseok Koh rte_prefetch0(*(pkts + 1)); 4036579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 4042e22920bSAdrien Mazarguil length = DATA_LEN(buf); 405eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 406eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 4076579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 4086579c27cSNélio Laranjeiro total_length = length; 4096579c27cSNélio Laranjeiro #endif 41024c14430SShahaf Shuler if (length < (MLX5_WQE_DWORD_SIZE + 2)) { 41124c14430SShahaf Shuler txq->stats.oerrors++; 412959be52eSNélio Laranjeiro break; 41324c14430SShahaf Shuler } 4142e22920bSAdrien Mazarguil /* Update element. */ 4158c819a69SYongseok Koh (*txq->elts)[elts_head & elts_m] = buf; 4165e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 4173730e6c6SYongseok Koh if (pkts_n - i > 1) 4183730e6c6SYongseok Koh rte_prefetch0( 4193730e6c6SYongseok Koh rte_pktmbuf_mtod(*(pkts + 1), volatile void *)); 4204aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 421b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 4226579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 4236579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 4246b30a6a8SShachar Beiser uint32_t vlan = rte_cpu_to_be_32(0x81000000 | 4256b30a6a8SShachar Beiser buf->vlan_tci); 4260d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 4276579c27cSNélio Laranjeiro 4280d637a34SNélio Laranjeiro addr += 2; 4290d637a34SNélio Laranjeiro length -= 2; 4300d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 4310d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 4320d637a34SNélio Laranjeiro /* Copy VLAN. */ 4330d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 4340d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 4350d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 4360d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 4370d637a34SNélio Laranjeiro addr += len + 2; 4380d637a34SNélio Laranjeiro length -= (len + 2); 4390d637a34SNélio Laranjeiro } else { 4400d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 4410d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 4420d637a34SNélio Laranjeiro length -= pkt_inline_sz; 4430d637a34SNélio Laranjeiro addr += pkt_inline_sz; 4446579c27cSNélio Laranjeiro } 445d8292497SYongseok Koh raw += MLX5_WQE_DWORD_SIZE; 44636aa55eaSYongseok Koh tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG); 4473f13f8c2SShahaf Shuler if (tso) { 44836aa55eaSYongseok Koh uintptr_t end = 44936aa55eaSYongseok Koh (uintptr_t)(((uintptr_t)txq->wqes) + 45036aa55eaSYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE); 4513f13f8c2SShahaf Shuler unsigned int copy_b; 45236aa55eaSYongseok Koh uint8_t vlan_sz = 45336aa55eaSYongseok Koh (buf->ol_flags & PKT_TX_VLAN_PKT) ? 4 : 0; 454b247f346SShahaf Shuler const uint64_t is_tunneled = 45536aa55eaSYongseok Koh buf->ol_flags & (PKT_TX_TUNNEL_GRE | 456b247f346SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 4573f13f8c2SShahaf Shuler 4583f13f8c2SShahaf Shuler tso_header_sz = buf->l2_len + vlan_sz + 4593f13f8c2SShahaf Shuler buf->l3_len + buf->l4_len; 46083daf156SShahaf Shuler tso_segsz = buf->tso_segsz; 46196fc8d65SShahaf Shuler if (unlikely(tso_segsz == 0)) { 46296fc8d65SShahaf Shuler txq->stats.oerrors++; 46396fc8d65SShahaf Shuler break; 46496fc8d65SShahaf Shuler } 465b247f346SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 466b247f346SShahaf Shuler tso_header_sz += buf->outer_l2_len + 467b247f346SShahaf Shuler buf->outer_l3_len; 4682a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM; 4692a6c96beSShahaf Shuler } else { 4702a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_CSUM; 471b247f346SShahaf Shuler } 47236aa55eaSYongseok Koh if (unlikely(tso_header_sz > MLX5_MAX_TSO_HEADER)) { 47324c14430SShahaf Shuler txq->stats.oerrors++; 4743f13f8c2SShahaf Shuler break; 47524c14430SShahaf Shuler } 4763f13f8c2SShahaf Shuler copy_b = tso_header_sz - pkt_inline_sz; 4773f13f8c2SShahaf Shuler /* First seg must contain all headers. */ 4783f13f8c2SShahaf Shuler assert(copy_b <= length); 47936aa55eaSYongseok Koh if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 48036aa55eaSYongseok Koh uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 4813f13f8c2SShahaf Shuler 4823f13f8c2SShahaf Shuler if (unlikely(max_wqe < n)) 4833f13f8c2SShahaf Shuler break; 4843f13f8c2SShahaf Shuler max_wqe -= n; 48536aa55eaSYongseok Koh rte_memcpy((void *)raw, (void *)addr, copy_b); 4863f13f8c2SShahaf Shuler addr += copy_b; 4873f13f8c2SShahaf Shuler length -= copy_b; 488d8292497SYongseok Koh /* Include padding for TSO header. */ 489d8292497SYongseok Koh copy_b = MLX5_WQE_DS(copy_b) * 4903f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 491d8292497SYongseok Koh pkt_inline_sz += copy_b; 492d8292497SYongseok Koh raw += copy_b; 4933f13f8c2SShahaf Shuler } else { 4943f13f8c2SShahaf Shuler /* NOP WQE. */ 4953f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 49636aa55eaSYongseok Koh rte_cpu_to_be_32(txq->wqe_ci << 8), 49736aa55eaSYongseok Koh rte_cpu_to_be_32(txq->qp_num_8s | 1), 4983f13f8c2SShahaf Shuler 0, 4993f13f8c2SShahaf Shuler 0, 5003f13f8c2SShahaf Shuler }; 5013f13f8c2SShahaf Shuler ds = 1; 502cb98affeSThierry Herbelot #ifdef MLX5_PMD_SOFT_COUNTERS 5033f13f8c2SShahaf Shuler total_length = 0; 504cb98affeSThierry Herbelot #endif 5053f13f8c2SShahaf Shuler k++; 5063f13f8c2SShahaf Shuler goto next_wqe; 5073f13f8c2SShahaf Shuler } 5083f13f8c2SShahaf Shuler } 5096579c27cSNélio Laranjeiro /* Inline if enough room. */ 51027a6b2d6SNélio Laranjeiro if (max_inline || tso) { 511f895536bSYongseok Koh uint32_t inl = 0; 512fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 513fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 514fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 515ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 5168fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 517d8292497SYongseok Koh (pkt_inline_sz - 2) - 518d8292497SYongseok Koh !!tso * sizeof(inl); 519f895536bSYongseok Koh uintptr_t addr_end; 520f895536bSYongseok Koh unsigned int copy_b; 5216579c27cSNélio Laranjeiro 522f895536bSYongseok Koh pkt_inline: 523f895536bSYongseok Koh addr_end = RTE_ALIGN_FLOOR(addr + inline_room, 524f895536bSYongseok Koh RTE_CACHE_LINE_SIZE); 525f895536bSYongseok Koh copy_b = (addr_end > addr) ? 526f895536bSYongseok Koh RTE_MIN((addr_end - addr), length) : 0; 5278fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 528f04f1d51SNélio Laranjeiro /* 529f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 530f04f1d51SNélio Laranjeiro * keep the computation positive, it is 531f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 532f04f1d51SNélio Laranjeiro */ 5338fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 5348fcd6c2cSNélio Laranjeiro 535f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 536f04f1d51SNélio Laranjeiro break; 537f04f1d51SNélio Laranjeiro max_wqe -= n; 538f895536bSYongseok Koh if (tso && !inl) { 5396963ae8bSYongseok Koh inl = rte_cpu_to_be_32(copy_b | 5406b30a6a8SShachar Beiser MLX5_INLINE_SEG); 5413f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 5423f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 5433f13f8c2SShahaf Shuler raw += sizeof(inl); 5443f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 5453f13f8c2SShahaf Shuler } 5466579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 5476579c27cSNélio Laranjeiro addr += copy_b; 5486579c27cSNélio Laranjeiro length -= copy_b; 5496579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 5506579c27cSNélio Laranjeiro } 5516579c27cSNélio Laranjeiro /* 552786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 5536579c27cSNélio Laranjeiro * the size of the inline part of the packet. 5546579c27cSNélio Laranjeiro */ 5556579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 5566579c27cSNélio Laranjeiro if (length > 0) { 557f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 558f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 559f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 560f04f1d51SNélio Laranjeiro break; 561f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 562f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 563f04f1d51SNélio Laranjeiro ds / 4); 564f04f1d51SNélio Laranjeiro } else { 5659a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 5666579c27cSNélio Laranjeiro ((uintptr_t)wqe + 5676579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 568f04f1d51SNélio Laranjeiro } 5696579c27cSNélio Laranjeiro goto use_dseg; 5706579c27cSNélio Laranjeiro } else if (!segs_n) { 5716579c27cSNélio Laranjeiro goto next_pkt; 5726579c27cSNélio Laranjeiro } else { 573f895536bSYongseok Koh raw += copy_b; 574f895536bSYongseok Koh inline_room -= copy_b; 575f895536bSYongseok Koh --segs_n; 576f895536bSYongseok Koh buf = buf->next; 577f895536bSYongseok Koh assert(buf); 578f895536bSYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 579f895536bSYongseok Koh length = DATA_LEN(buf); 580f895536bSYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 581f895536bSYongseok Koh total_length += length; 582f895536bSYongseok Koh #endif 583f895536bSYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 584f895536bSYongseok Koh goto pkt_inline; 5856579c27cSNélio Laranjeiro } 5866579c27cSNélio Laranjeiro } else { 5876579c27cSNélio Laranjeiro /* 5886579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 5896579c27cSNélio Laranjeiro * Ethernet Header as been stored. 5906579c27cSNélio Laranjeiro */ 5919a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 5926579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 5936579c27cSNélio Laranjeiro ds = 3; 5946579c27cSNélio Laranjeiro use_dseg: 5956579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 596ebbb81ebSNélio Laranjeiro addr = rte_cpu_to_be_64(addr); 5979a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 5986b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 5996cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 600ebbb81ebSNélio Laranjeiro addr, 601ebbb81ebSNélio Laranjeiro addr >> 32, 6026579c27cSNélio Laranjeiro }; 6036579c27cSNélio Laranjeiro ++ds; 6046579c27cSNélio Laranjeiro if (!segs_n) 6056579c27cSNélio Laranjeiro goto next_pkt; 6066579c27cSNélio Laranjeiro } 6076579c27cSNélio Laranjeiro next_seg: 6086579c27cSNélio Laranjeiro assert(buf); 6096579c27cSNélio Laranjeiro assert(ds); 6106579c27cSNélio Laranjeiro assert(wqe); 611a5bf6af9SAdrien Mazarguil /* 612a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 613a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 614a5bf6af9SAdrien Mazarguil * of data segment size. 615a5bf6af9SAdrien Mazarguil */ 6168688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 6176579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 618f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 619f04f1d51SNélio Laranjeiro break; 6209a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 621f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 622f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 623f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 6246579c27cSNélio Laranjeiro } else { 625a5bf6af9SAdrien Mazarguil ++dseg; 6266579c27cSNélio Laranjeiro } 627a5bf6af9SAdrien Mazarguil ++ds; 628a5bf6af9SAdrien Mazarguil buf = buf->next; 629a5bf6af9SAdrien Mazarguil assert(buf); 6306579c27cSNélio Laranjeiro length = DATA_LEN(buf); 631a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 6326579c27cSNélio Laranjeiro total_length += length; 633a5bf6af9SAdrien Mazarguil #endif 6346579c27cSNélio Laranjeiro /* Store segment information. */ 635ebbb81ebSNélio Laranjeiro addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)); 6369a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6376b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 6386cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 639ebbb81ebSNélio Laranjeiro addr, 640ebbb81ebSNélio Laranjeiro addr >> 32, 6416579c27cSNélio Laranjeiro }; 6428c819a69SYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 643f895536bSYongseok Koh if (--segs_n) 6446579c27cSNélio Laranjeiro goto next_seg; 6456579c27cSNélio Laranjeiro next_pkt: 646883ce172SShahaf Shuler if (ds > MLX5_DSEG_MAX) { 647883ce172SShahaf Shuler txq->stats.oerrors++; 648883ce172SShahaf Shuler break; 649883ce172SShahaf Shuler } 6508c819a69SYongseok Koh ++elts_head; 6513730e6c6SYongseok Koh ++pkts; 6526579c27cSNélio Laranjeiro ++i; 653f895536bSYongseok Koh j += sg; 654b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 6553f13f8c2SShahaf Shuler if (tso) { 6563f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 6576b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 6586b30a6a8SShachar Beiser MLX5_OPCODE_TSO), 6596b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 6603f13f8c2SShahaf Shuler 0, 6613f13f8c2SShahaf Shuler 0, 6623f13f8c2SShahaf Shuler }; 6633f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 6643f13f8c2SShahaf Shuler 0, 6656b30a6a8SShachar Beiser cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16), 6663f13f8c2SShahaf Shuler 0, 6676b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(tso_header_sz), 6683f13f8c2SShahaf Shuler }; 6693f13f8c2SShahaf Shuler } else { 6709a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 6716b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 6726b30a6a8SShachar Beiser MLX5_OPCODE_SEND), 6736b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 6749a7fa9f7SNélio Laranjeiro 0, 6759a7fa9f7SNélio Laranjeiro 0, 6769a7fa9f7SNélio Laranjeiro }; 6779a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 6789a7fa9f7SNélio Laranjeiro 0, 6799a7fa9f7SNélio Laranjeiro cs_flags, 6809a7fa9f7SNélio Laranjeiro 0, 6816b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz), 6829a7fa9f7SNélio Laranjeiro }; 6833f13f8c2SShahaf Shuler } 6843f13f8c2SShahaf Shuler next_wqe: 6856579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 686ac180a21SYongseok Koh /* Save the last successful WQE for completion request */ 687ac180a21SYongseok Koh last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe; 68887011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 689573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 6906579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 69187011737SAdrien Mazarguil #endif 6923730e6c6SYongseok Koh } while (i < pkts_n); 6932e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 6943f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 6952e22920bSAdrien Mazarguil return 0; 6968c819a69SYongseok Koh txq->elts_head += (i + j); 697c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 6983f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 699c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 700c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 7016b30a6a8SShachar Beiser last_wqe->ctrl2 = rte_cpu_to_be_32(8); 702c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 703ac180a21SYongseok Koh last_wqe->ctrl3 = txq->elts_head; 704c305090bSAdrien Mazarguil txq->elts_comp = 0; 7052eefbec5SYongseok Koh #ifndef NDEBUG 7062eefbec5SYongseok Koh ++txq->cq_pi; 7072eefbec5SYongseok Koh #endif 708c305090bSAdrien Mazarguil } else { 709c305090bSAdrien Mazarguil txq->elts_comp = comp; 710c305090bSAdrien Mazarguil } 71187011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 71287011737SAdrien Mazarguil /* Increment sent packets counter. */ 71387011737SAdrien Mazarguil txq->stats.opackets += i; 71487011737SAdrien Mazarguil #endif 7152e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 716ac180a21SYongseok Koh mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe); 7172e22920bSAdrien Mazarguil return i; 7182e22920bSAdrien Mazarguil } 7192e22920bSAdrien Mazarguil 7202e22920bSAdrien Mazarguil /** 721230189d9SNélio Laranjeiro * Open a MPW session. 722230189d9SNélio Laranjeiro * 723230189d9SNélio Laranjeiro * @param txq 724230189d9SNélio Laranjeiro * Pointer to TX queue structure. 725230189d9SNélio Laranjeiro * @param mpw 726230189d9SNélio Laranjeiro * Pointer to MPW session structure. 727230189d9SNélio Laranjeiro * @param length 728230189d9SNélio Laranjeiro * Packet length. 729230189d9SNélio Laranjeiro */ 730230189d9SNélio Laranjeiro static inline void 731991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length) 732230189d9SNélio Laranjeiro { 733a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 734230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 735230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 736fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 737230189d9SNélio Laranjeiro 738230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 739230189d9SNélio Laranjeiro mpw->pkts_n = 0; 740230189d9SNélio Laranjeiro mpw->len = length; 741230189d9SNélio Laranjeiro mpw->total_len = 0; 742fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 7436b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 7448688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 7458688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 7468688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 7478688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 7486b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 7496b30a6a8SShachar Beiser (txq->wqe_ci << 8) | 7506b30a6a8SShachar Beiser MLX5_OPCODE_TSO); 7518688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 7528688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 7538688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 7548688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 7558688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 7568688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 757230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 758230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 759230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 760230189d9SNélio Laranjeiro } 761230189d9SNélio Laranjeiro 762230189d9SNélio Laranjeiro /** 763230189d9SNélio Laranjeiro * Close a MPW session. 764230189d9SNélio Laranjeiro * 765230189d9SNélio Laranjeiro * @param txq 766230189d9SNélio Laranjeiro * Pointer to TX queue structure. 767230189d9SNélio Laranjeiro * @param mpw 768230189d9SNélio Laranjeiro * Pointer to MPW session structure. 769230189d9SNélio Laranjeiro */ 770230189d9SNélio Laranjeiro static inline void 771991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 772230189d9SNélio Laranjeiro { 773230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 774230189d9SNélio Laranjeiro 775230189d9SNélio Laranjeiro /* 776230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 777230189d9SNélio Laranjeiro * count as 2. 778230189d9SNélio Laranjeiro */ 7796b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num)); 780230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 781230189d9SNélio Laranjeiro if (num < 3) 782230189d9SNélio Laranjeiro ++txq->wqe_ci; 783230189d9SNélio Laranjeiro else 784230189d9SNélio Laranjeiro txq->wqe_ci += 2; 785fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 786fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 787230189d9SNélio Laranjeiro } 788230189d9SNélio Laranjeiro 789230189d9SNélio Laranjeiro /** 790230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 791230189d9SNélio Laranjeiro * 792230189d9SNélio Laranjeiro * @param dpdk_txq 793230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 794230189d9SNélio Laranjeiro * @param[in] pkts 795230189d9SNélio Laranjeiro * Packets to transmit. 796230189d9SNélio Laranjeiro * @param pkts_n 797230189d9SNélio Laranjeiro * Number of packets in array. 798230189d9SNélio Laranjeiro * 799230189d9SNélio Laranjeiro * @return 800230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 801230189d9SNélio Laranjeiro */ 802230189d9SNélio Laranjeiro uint16_t 803230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 804230189d9SNélio Laranjeiro { 805991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 806230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 8078c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 8088c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 809c3d62cc9SAdrien Mazarguil unsigned int i = 0; 810a5bf6af9SAdrien Mazarguil unsigned int j = 0; 8118c819a69SYongseok Koh uint16_t max_elts; 812f04f1d51SNélio Laranjeiro uint16_t max_wqe; 813230189d9SNélio Laranjeiro unsigned int comp; 814230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 815230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 816230189d9SNélio Laranjeiro }; 817230189d9SNélio Laranjeiro 818c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 819c3d62cc9SAdrien Mazarguil return 0; 820230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 821fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 822fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 823230189d9SNélio Laranjeiro /* Start processing. */ 8246cb559d6SYongseok Koh mlx5_tx_complete(txq); 8258c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 8262eefbec5SYongseok Koh /* A CQE slot must always be available. */ 8272eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 828f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 829f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 830f04f1d51SNélio Laranjeiro return 0; 831c3d62cc9SAdrien Mazarguil do { 832a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 833230189d9SNélio Laranjeiro uint32_t length; 834a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 8354aa15eb1SNélio Laranjeiro uint32_t cs_flags; 836230189d9SNélio Laranjeiro 837c3d62cc9SAdrien Mazarguil /* 838c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 839c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 840c3d62cc9SAdrien Mazarguil */ 841a5bf6af9SAdrien Mazarguil assert(segs_n); 8428c819a69SYongseok Koh if (max_elts < segs_n) 843c3d62cc9SAdrien Mazarguil break; 844a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 84524c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 84624c14430SShahaf Shuler txq->stats.oerrors++; 847a5bf6af9SAdrien Mazarguil break; 84824c14430SShahaf Shuler } 8498c819a69SYongseok Koh max_elts -= segs_n; 850c3d62cc9SAdrien Mazarguil --pkts_n; 8514aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 852a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 853a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 854a5bf6af9SAdrien Mazarguil assert(length); 855230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 856230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 857230189d9SNélio Laranjeiro ((mpw.len != length) || 858a5bf6af9SAdrien Mazarguil (segs_n != 1) || 8598688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 860230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 861230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 862f04f1d51SNélio Laranjeiro /* 863f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 864f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 865f04f1d51SNélio Laranjeiro * resources. 866f04f1d51SNélio Laranjeiro */ 867f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 868f04f1d51SNélio Laranjeiro break; 869f04f1d51SNélio Laranjeiro max_wqe -= 2; 870230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 8718688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 872230189d9SNélio Laranjeiro } 873a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 874a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 875a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 876a5bf6af9SAdrien Mazarguil length = 0; 877a5bf6af9SAdrien Mazarguil #endif 878a5bf6af9SAdrien Mazarguil do { 879a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 880a5bf6af9SAdrien Mazarguil uintptr_t addr; 881a5bf6af9SAdrien Mazarguil 882a5bf6af9SAdrien Mazarguil assert(buf); 8838c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 884230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 885a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 886230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 8876b30a6a8SShachar Beiser .byte_count = rte_cpu_to_be_32(DATA_LEN(buf)), 8886cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 8896b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 890230189d9SNélio Laranjeiro }; 891a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 892a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 893a5bf6af9SAdrien Mazarguil #endif 894a5bf6af9SAdrien Mazarguil buf = buf->next; 895230189d9SNélio Laranjeiro ++mpw.pkts_n; 896a5bf6af9SAdrien Mazarguil ++j; 897a5bf6af9SAdrien Mazarguil } while (--segs_n); 898a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 899230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 900230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 901230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 902230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 903230189d9SNélio Laranjeiro txq->stats.obytes += length; 904230189d9SNélio Laranjeiro #endif 905c3d62cc9SAdrien Mazarguil ++i; 906c3d62cc9SAdrien Mazarguil } while (pkts_n); 907230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 908230189d9SNélio Laranjeiro if (unlikely(i == 0)) 909230189d9SNélio Laranjeiro return 0; 910230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 911a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 912a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 913230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 9148688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 915230189d9SNélio Laranjeiro 916230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 9176b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 918230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 9198688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 920230189d9SNélio Laranjeiro txq->elts_comp = 0; 9212eefbec5SYongseok Koh #ifndef NDEBUG 9222eefbec5SYongseok Koh ++txq->cq_pi; 9232eefbec5SYongseok Koh #endif 924230189d9SNélio Laranjeiro } else { 925230189d9SNélio Laranjeiro txq->elts_comp = comp; 926230189d9SNélio Laranjeiro } 927230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 928230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 929230189d9SNélio Laranjeiro txq->stats.opackets += i; 930230189d9SNélio Laranjeiro #endif 931230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 932230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 933230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 93430807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 935230189d9SNélio Laranjeiro txq->elts_head = elts_head; 936230189d9SNélio Laranjeiro return i; 937230189d9SNélio Laranjeiro } 938230189d9SNélio Laranjeiro 939230189d9SNélio Laranjeiro /** 940230189d9SNélio Laranjeiro * Open a MPW inline session. 941230189d9SNélio Laranjeiro * 942230189d9SNélio Laranjeiro * @param txq 943230189d9SNélio Laranjeiro * Pointer to TX queue structure. 944230189d9SNélio Laranjeiro * @param mpw 945230189d9SNélio Laranjeiro * Pointer to MPW session structure. 946230189d9SNélio Laranjeiro * @param length 947230189d9SNélio Laranjeiro * Packet length. 948230189d9SNélio Laranjeiro */ 949230189d9SNélio Laranjeiro static inline void 950991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, 951991b04f6SNélio Laranjeiro uint32_t length) 952230189d9SNélio Laranjeiro { 953a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 9548688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 955230189d9SNélio Laranjeiro 956230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 957230189d9SNélio Laranjeiro mpw->pkts_n = 0; 958230189d9SNélio Laranjeiro mpw->len = length; 959230189d9SNélio Laranjeiro mpw->total_len = 0; 960fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 9616b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 962230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 963c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 9648688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 9658688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 9666b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 9678688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 9688688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 9698688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 9708688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 9718688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 9728688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 9738688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 9748688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 975230189d9SNélio Laranjeiro } 976230189d9SNélio Laranjeiro 977230189d9SNélio Laranjeiro /** 978230189d9SNélio Laranjeiro * Close a MPW inline session. 979230189d9SNélio Laranjeiro * 980230189d9SNélio Laranjeiro * @param txq 981230189d9SNélio Laranjeiro * Pointer to TX queue structure. 982230189d9SNélio Laranjeiro * @param mpw 983230189d9SNélio Laranjeiro * Pointer to MPW session structure. 984230189d9SNélio Laranjeiro */ 985230189d9SNélio Laranjeiro static inline void 986991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 987230189d9SNélio Laranjeiro { 988230189d9SNélio Laranjeiro unsigned int size; 9898688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 9908688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 991230189d9SNélio Laranjeiro 9928688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 993230189d9SNélio Laranjeiro /* 994230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 995230189d9SNélio Laranjeiro * count as 2. 996230189d9SNélio Laranjeiro */ 9976b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 9986b30a6a8SShachar Beiser MLX5_WQE_DS(size)); 999230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 10006b30a6a8SShachar Beiser inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG); 10018688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1002230189d9SNélio Laranjeiro } 1003230189d9SNélio Laranjeiro 1004230189d9SNélio Laranjeiro /** 1005230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1006230189d9SNélio Laranjeiro * 1007230189d9SNélio Laranjeiro * @param dpdk_txq 1008230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1009230189d9SNélio Laranjeiro * @param[in] pkts 1010230189d9SNélio Laranjeiro * Packets to transmit. 1011230189d9SNélio Laranjeiro * @param pkts_n 1012230189d9SNélio Laranjeiro * Number of packets in array. 1013230189d9SNélio Laranjeiro * 1014230189d9SNélio Laranjeiro * @return 1015230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1016230189d9SNélio Laranjeiro */ 1017230189d9SNélio Laranjeiro uint16_t 1018230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1019230189d9SNélio Laranjeiro uint16_t pkts_n) 1020230189d9SNélio Laranjeiro { 1021991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 1022230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 10238c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 10248c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 1025c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1026a5bf6af9SAdrien Mazarguil unsigned int j = 0; 10278c819a69SYongseok Koh uint16_t max_elts; 1028f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1029230189d9SNélio Laranjeiro unsigned int comp; 10300e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1031230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1032230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1033230189d9SNélio Laranjeiro }; 1034f04f1d51SNélio Laranjeiro /* 1035f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1036f04f1d51SNélio Laranjeiro * code. 1037f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1038f04f1d51SNélio Laranjeiro * - 1 control segment, 1039f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1040f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1041f04f1d51SNélio Laranjeiro */ 1042f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1043f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1044f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1045f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1046230189d9SNélio Laranjeiro 1047c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1048c3d62cc9SAdrien Mazarguil return 0; 1049230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1050fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1051fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1052230189d9SNélio Laranjeiro /* Start processing. */ 10536cb559d6SYongseok Koh mlx5_tx_complete(txq); 10548c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 10552eefbec5SYongseok Koh /* A CQE slot must always be available. */ 10562eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 1057c3d62cc9SAdrien Mazarguil do { 1058a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1059230189d9SNélio Laranjeiro uintptr_t addr; 1060230189d9SNélio Laranjeiro uint32_t length; 1061a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 10624aa15eb1SNélio Laranjeiro uint8_t cs_flags; 1063230189d9SNélio Laranjeiro 1064c3d62cc9SAdrien Mazarguil /* 1065c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1066c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1067c3d62cc9SAdrien Mazarguil */ 1068a5bf6af9SAdrien Mazarguil assert(segs_n); 10698c819a69SYongseok Koh if (max_elts < segs_n) 1070c3d62cc9SAdrien Mazarguil break; 1071a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 107224c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 107324c14430SShahaf Shuler txq->stats.oerrors++; 1074a5bf6af9SAdrien Mazarguil break; 107524c14430SShahaf Shuler } 10768c819a69SYongseok Koh max_elts -= segs_n; 1077c3d62cc9SAdrien Mazarguil --pkts_n; 1078f04f1d51SNélio Laranjeiro /* 1079f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1080f04f1d51SNélio Laranjeiro * iteration. 1081f04f1d51SNélio Laranjeiro */ 1082f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 10834aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 1084a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1085a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1086230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1087230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1088230189d9SNélio Laranjeiro if ((mpw.len != length) || 1089a5bf6af9SAdrien Mazarguil (segs_n != 1) || 10908688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1091230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1092230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1093230189d9SNélio Laranjeiro if ((mpw.len != length) || 1094a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1095230189d9SNélio Laranjeiro (length > inline_room) || 10968688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1097230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 10980e8679fcSNélio Laranjeiro inline_room = 10990e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1100230189d9SNélio Laranjeiro } 1101230189d9SNélio Laranjeiro } 1102230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1103a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1104a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1105f04f1d51SNélio Laranjeiro /* 1106f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1107f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1108f04f1d51SNélio Laranjeiro * such resources. 1109f04f1d51SNélio Laranjeiro */ 1110f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1111f04f1d51SNélio Laranjeiro break; 1112f04f1d51SNélio Laranjeiro max_wqe -= 2; 1113230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 11148688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1115230189d9SNélio Laranjeiro } else { 1116f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1117f04f1d51SNélio Laranjeiro break; 1118f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1119230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 11208688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1121230189d9SNélio Laranjeiro } 1122230189d9SNélio Laranjeiro } 1123a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1124a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1125230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 11260e8679fcSNélio Laranjeiro assert(inline_room == 11270e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1128a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1129a5bf6af9SAdrien Mazarguil length = 0; 1130a5bf6af9SAdrien Mazarguil #endif 1131a5bf6af9SAdrien Mazarguil do { 1132230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1133230189d9SNélio Laranjeiro 1134a5bf6af9SAdrien Mazarguil assert(buf); 11358c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1136230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1137a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1138230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 11396b30a6a8SShachar Beiser .byte_count = 11406b30a6a8SShachar Beiser rte_cpu_to_be_32(DATA_LEN(buf)), 11416cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 11426b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 1143230189d9SNélio Laranjeiro }; 1144a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1145a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1146a5bf6af9SAdrien Mazarguil #endif 1147a5bf6af9SAdrien Mazarguil buf = buf->next; 1148230189d9SNélio Laranjeiro ++mpw.pkts_n; 1149a5bf6af9SAdrien Mazarguil ++j; 1150a5bf6af9SAdrien Mazarguil } while (--segs_n); 1151a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1152230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1153230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1154230189d9SNélio Laranjeiro } else { 1155230189d9SNélio Laranjeiro unsigned int max; 1156230189d9SNélio Laranjeiro 1157230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1158230189d9SNélio Laranjeiro assert(length <= inline_room); 1159a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1160a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 11618c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1162230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1163fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1164fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1165fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1166230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1167230189d9SNélio Laranjeiro if (length > max) { 1168230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1169230189d9SNélio Laranjeiro (void *)addr, 1170230189d9SNélio Laranjeiro max); 1171fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1172230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1173230189d9SNélio Laranjeiro (void *)(addr + max), 1174230189d9SNélio Laranjeiro length - max); 1175230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1176230189d9SNélio Laranjeiro } else { 1177230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1178230189d9SNélio Laranjeiro (void *)addr, 1179230189d9SNélio Laranjeiro length); 118016c64768SYongseok Koh 118116c64768SYongseok Koh if (length == max) 118216c64768SYongseok Koh mpw.data.raw = 118316c64768SYongseok Koh (volatile void *)txq->wqes; 118416c64768SYongseok Koh else 1185230189d9SNélio Laranjeiro mpw.data.raw += length; 1186230189d9SNélio Laranjeiro } 1187230189d9SNélio Laranjeiro ++mpw.pkts_n; 118876bf1574SYongseok Koh mpw.total_len += length; 1189a5bf6af9SAdrien Mazarguil ++j; 1190230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1191230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 11920e8679fcSNélio Laranjeiro inline_room = 11930e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1194230189d9SNélio Laranjeiro } else { 1195230189d9SNélio Laranjeiro inline_room -= length; 1196230189d9SNélio Laranjeiro } 1197230189d9SNélio Laranjeiro } 1198230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1199230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1200230189d9SNélio Laranjeiro txq->stats.obytes += length; 1201230189d9SNélio Laranjeiro #endif 1202c3d62cc9SAdrien Mazarguil ++i; 1203c3d62cc9SAdrien Mazarguil } while (pkts_n); 1204230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1205230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1206230189d9SNélio Laranjeiro return 0; 1207230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1208a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1209a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1210230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 12118688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1212230189d9SNélio Laranjeiro 1213230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 12146b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 1215230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 12168688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1217230189d9SNélio Laranjeiro txq->elts_comp = 0; 12182eefbec5SYongseok Koh #ifndef NDEBUG 12192eefbec5SYongseok Koh ++txq->cq_pi; 12202eefbec5SYongseok Koh #endif 1221230189d9SNélio Laranjeiro } else { 1222230189d9SNélio Laranjeiro txq->elts_comp = comp; 1223230189d9SNélio Laranjeiro } 1224230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1225230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1226230189d9SNélio Laranjeiro txq->stats.opackets += i; 1227230189d9SNélio Laranjeiro #endif 1228230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1229230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1230230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1231230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1232230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 123330807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1234230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1235230189d9SNélio Laranjeiro return i; 1236230189d9SNélio Laranjeiro } 1237230189d9SNélio Laranjeiro 1238230189d9SNélio Laranjeiro /** 12396ce84bd8SYongseok Koh * Open an Enhanced MPW session. 12406ce84bd8SYongseok Koh * 12416ce84bd8SYongseok Koh * @param txq 12426ce84bd8SYongseok Koh * Pointer to TX queue structure. 12436ce84bd8SYongseok Koh * @param mpw 12446ce84bd8SYongseok Koh * Pointer to MPW session structure. 12456ce84bd8SYongseok Koh * @param length 12466ce84bd8SYongseok Koh * Packet length. 12476ce84bd8SYongseok Koh */ 12486ce84bd8SYongseok Koh static inline void 1249991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding) 12506ce84bd8SYongseok Koh { 12516ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 12526ce84bd8SYongseok Koh 12536ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 12546ce84bd8SYongseok Koh mpw->pkts_n = 0; 12556ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 12566ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 12576b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = 12586b30a6a8SShachar Beiser rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 12596ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 12606ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 12616ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 12626ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 12636ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 12646ce84bd8SYongseok Koh if (unlikely(padding)) { 12656ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 12666ce84bd8SYongseok Koh 12676ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 12686b30a6a8SShachar Beiser *(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG); 12696ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 12706b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_INLINE_SEG); 12716ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 12726ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 12736ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 12746ce84bd8SYongseok Koh } else { 12756ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 12766ce84bd8SYongseok Koh } 12776ce84bd8SYongseok Koh } 12786ce84bd8SYongseok Koh 12796ce84bd8SYongseok Koh /** 12806ce84bd8SYongseok Koh * Close an Enhanced MPW session. 12816ce84bd8SYongseok Koh * 12826ce84bd8SYongseok Koh * @param txq 12836ce84bd8SYongseok Koh * Pointer to TX queue structure. 12846ce84bd8SYongseok Koh * @param mpw 12856ce84bd8SYongseok Koh * Pointer to MPW session structure. 12866ce84bd8SYongseok Koh * 12876ce84bd8SYongseok Koh * @return 12886ce84bd8SYongseok Koh * Number of consumed WQEs. 12896ce84bd8SYongseok Koh */ 12906ce84bd8SYongseok Koh static inline uint16_t 1291991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 12926ce84bd8SYongseok Koh { 12936ce84bd8SYongseok Koh uint16_t ret; 12946ce84bd8SYongseok Koh 12956ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 12966ce84bd8SYongseok Koh * count as 2. 12976ce84bd8SYongseok Koh */ 12986b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 12996b30a6a8SShachar Beiser MLX5_WQE_DS(mpw->total_len)); 13006ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 13016ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 13026ce84bd8SYongseok Koh txq->wqe_ci += ret; 13036ce84bd8SYongseok Koh return ret; 13046ce84bd8SYongseok Koh } 13056ce84bd8SYongseok Koh 13066ce84bd8SYongseok Koh /** 13074b0d7b7fSYongseok Koh * TX with Enhanced MPW support. 13086ce84bd8SYongseok Koh * 13094b0d7b7fSYongseok Koh * @param txq 13104b0d7b7fSYongseok Koh * Pointer to TX queue structure. 13116ce84bd8SYongseok Koh * @param[in] pkts 13126ce84bd8SYongseok Koh * Packets to transmit. 13136ce84bd8SYongseok Koh * @param pkts_n 13146ce84bd8SYongseok Koh * Number of packets in array. 13156ce84bd8SYongseok Koh * 13166ce84bd8SYongseok Koh * @return 13176ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 13186ce84bd8SYongseok Koh */ 13194b0d7b7fSYongseok Koh static inline uint16_t 13204b0d7b7fSYongseok Koh txq_burst_empw(struct mlx5_txq_data *txq, struct rte_mbuf **pkts, 13214b0d7b7fSYongseok Koh uint16_t pkts_n) 13226ce84bd8SYongseok Koh { 13236ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 13248c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 13258c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 13266ce84bd8SYongseok Koh unsigned int i = 0; 13276ce84bd8SYongseok Koh unsigned int j = 0; 13288c819a69SYongseok Koh uint16_t max_elts; 13296ce84bd8SYongseok Koh uint16_t max_wqe; 13306ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 13316ce84bd8SYongseok Koh unsigned int mpw_room = 0; 13326ce84bd8SYongseok Koh unsigned int inl_pad = 0; 13336ce84bd8SYongseok Koh uint32_t inl_hdr; 13346ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 13356ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 13366ce84bd8SYongseok Koh }; 13376ce84bd8SYongseok Koh 13386ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 13396ce84bd8SYongseok Koh return 0; 13406ce84bd8SYongseok Koh /* Start processing. */ 13416cb559d6SYongseok Koh mlx5_tx_complete(txq); 13426ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 13436ce84bd8SYongseok Koh /* A CQE slot must always be available. */ 13446ce84bd8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 13456ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 13466ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 13476ce84bd8SYongseok Koh return 0; 13486ce84bd8SYongseok Koh do { 13496ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 13506ce84bd8SYongseok Koh uintptr_t addr; 13516ce84bd8SYongseok Koh unsigned int n; 13526ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 13536ce84bd8SYongseok Koh uint32_t length; 13544aa15eb1SNélio Laranjeiro uint8_t cs_flags; 13556ce84bd8SYongseok Koh 135648642ec5SYongseok Koh /* Multi-segmented packet is handled in slow-path outside. */ 135748642ec5SYongseok Koh assert(NB_SEGS(buf) == 1); 135848642ec5SYongseok Koh /* Make sure there is enough room to store this packet. */ 135948642ec5SYongseok Koh if (max_elts - j == 0) 13606ce84bd8SYongseok Koh break; 13614aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 13626ce84bd8SYongseok Koh /* Retrieve packet information. */ 13636ce84bd8SYongseok Koh length = PKT_LEN(buf); 13646ce84bd8SYongseok Koh /* Start new session if: 13656ce84bd8SYongseok Koh * - multi-segment packet 13666ce84bd8SYongseok Koh * - no space left even for a dseg 13676ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 13686ce84bd8SYongseok Koh * - cs_flag differs 13696ce84bd8SYongseok Koh */ 13706ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 137148642ec5SYongseok Koh if ((inl_pad + sizeof(struct mlx5_wqe_data_seg) > 13726ce84bd8SYongseok Koh mpw_room) || 13736ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 13746ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 13756ce84bd8SYongseok Koh mpw_room) || 13766ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 13776ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 13786ce84bd8SYongseok Koh } 13796ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 138048642ec5SYongseok Koh /* In Enhanced MPW, inline as much as the budget is 138148642ec5SYongseok Koh * allowed. The remaining space is to be filled with 138248642ec5SYongseok Koh * dsegs. If the title WQEBB isn't padded, it will have 138348642ec5SYongseok Koh * 2 dsegs there. 13846ce84bd8SYongseok Koh */ 13856ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 13866ce84bd8SYongseok Koh (max_inline ? max_inline : 13876ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 13886ce84bd8SYongseok Koh MLX5_WQE_SIZE); 138948642ec5SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < mpw_room)) 13906ce84bd8SYongseok Koh break; 13916ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 13926ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 13936ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 13946ce84bd8SYongseok Koh inl_pad = 0; 139548642ec5SYongseok Koh do_inline = length <= txq->inline_max_packet_sz && 13966ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 13976ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 13986ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 13996ce84bd8SYongseok Koh } else { 14006ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 14016ce84bd8SYongseok Koh * Inlininig is possible when: 14026ce84bd8SYongseok Koh * - length is less than configured value 14036ce84bd8SYongseok Koh * - length fits for remaining space 14046ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 14056ce84bd8SYongseok Koh */ 14066ce84bd8SYongseok Koh do_inline = 14076ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 14086ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 14096ce84bd8SYongseok Koh mpw_room && 14106ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 14116ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 14126ce84bd8SYongseok Koh } 141348642ec5SYongseok Koh if (do_inline) { 14146ce84bd8SYongseok Koh /* Inline packet into WQE. */ 14156ce84bd8SYongseok Koh unsigned int max; 14166ce84bd8SYongseok Koh 14176ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14186ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14196b30a6a8SShachar Beiser inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG); 14206ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14216ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14226ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 14236ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 14246ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 14256ce84bd8SYongseok Koh /* Copy inline header. */ 14266ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14276ce84bd8SYongseok Koh mlx5_copy_to_wq( 14286ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 14296ce84bd8SYongseok Koh &inl_hdr, 14306ce84bd8SYongseok Koh sizeof(inl_hdr), 14316ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 14326ce84bd8SYongseok Koh max); 14336ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 14346ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 14356ce84bd8SYongseok Koh /* Copy packet data. */ 14366ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14376ce84bd8SYongseok Koh mlx5_copy_to_wq( 14386ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 14396ce84bd8SYongseok Koh (void *)addr, 14406ce84bd8SYongseok Koh length, 14416ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 14426ce84bd8SYongseok Koh max); 14436ce84bd8SYongseok Koh ++mpw.pkts_n; 14446ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 14456ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 14466ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 14476ce84bd8SYongseok Koh */ 14486ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 14496ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 14506ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 14516ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 14526ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 14536ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 14546ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 14556ce84bd8SYongseok Koh } else { 14566ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 14576ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 14586ce84bd8SYongseok Koh 14596ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14606ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 14616ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14626ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 14636ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 14646ce84bd8SYongseok Koh + inl_pad))) 14656ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 14666ce84bd8SYongseok Koh else 14676ce84bd8SYongseok Koh dseg = (volatile void *) 14686ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 14696ce84bd8SYongseok Koh inl_pad); 14708c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 14716ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14726ce84bd8SYongseok Koh for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++) 14736ce84bd8SYongseok Koh rte_prefetch2((void *)(addr + 14746ce84bd8SYongseok Koh n * RTE_CACHE_LINE_SIZE)); 1475ebbb81ebSNélio Laranjeiro addr = rte_cpu_to_be_64(addr); 14766ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 14776b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 14786cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 1479ebbb81ebSNélio Laranjeiro addr, 1480ebbb81ebSNélio Laranjeiro addr >> 32, 14816ce84bd8SYongseok Koh }; 14826ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 14836ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 14846ce84bd8SYongseok Koh ++j; 14856ce84bd8SYongseok Koh ++mpw.pkts_n; 14866ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 14876ce84bd8SYongseok Koh inl_pad = 0; 14886ce84bd8SYongseok Koh } 14896ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 14906ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 14916ce84bd8SYongseok Koh txq->stats.obytes += length; 14926ce84bd8SYongseok Koh #endif 14936ce84bd8SYongseok Koh ++i; 14946ce84bd8SYongseok Koh } while (i < pkts_n); 14956ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 14966ce84bd8SYongseok Koh if (unlikely(i == 0)) 14976ce84bd8SYongseok Koh return 0; 14986ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 14996ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 15006ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 15016ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 15026ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 15036ce84bd8SYongseok Koh 15046ce84bd8SYongseok Koh /* Request completion on last WQE. */ 15056b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 15066ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 15076ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 15086ce84bd8SYongseok Koh txq->elts_comp = 0; 15096ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 15102eefbec5SYongseok Koh #ifndef NDEBUG 15112eefbec5SYongseok Koh ++txq->cq_pi; 15122eefbec5SYongseok Koh #endif 15136ce84bd8SYongseok Koh } else { 15146ce84bd8SYongseok Koh txq->elts_comp += j; 15156ce84bd8SYongseok Koh } 15166ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 15176ce84bd8SYongseok Koh /* Increment sent packets counter. */ 15186ce84bd8SYongseok Koh txq->stats.opackets += i; 15196ce84bd8SYongseok Koh #endif 15206ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 15216ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 15226ce84bd8SYongseok Koh /* Ring QP doorbell. */ 15236ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 15246ce84bd8SYongseok Koh txq->elts_head = elts_head; 15256ce84bd8SYongseok Koh return i; 15266ce84bd8SYongseok Koh } 15276ce84bd8SYongseok Koh 15286ce84bd8SYongseok Koh /** 15294b0d7b7fSYongseok Koh * DPDK callback for TX with Enhanced MPW support. 15304b0d7b7fSYongseok Koh * 15314b0d7b7fSYongseok Koh * @param dpdk_txq 15324b0d7b7fSYongseok Koh * Generic pointer to TX queue structure. 15334b0d7b7fSYongseok Koh * @param[in] pkts 15344b0d7b7fSYongseok Koh * Packets to transmit. 15354b0d7b7fSYongseok Koh * @param pkts_n 15364b0d7b7fSYongseok Koh * Number of packets in array. 15374b0d7b7fSYongseok Koh * 15384b0d7b7fSYongseok Koh * @return 15394b0d7b7fSYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 15404b0d7b7fSYongseok Koh */ 15414b0d7b7fSYongseok Koh uint16_t 15424b0d7b7fSYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 15434b0d7b7fSYongseok Koh { 15444b0d7b7fSYongseok Koh struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 15454b0d7b7fSYongseok Koh uint16_t nb_tx = 0; 15464b0d7b7fSYongseok Koh 15474b0d7b7fSYongseok Koh while (pkts_n > nb_tx) { 15484b0d7b7fSYongseok Koh uint16_t n; 15494b0d7b7fSYongseok Koh uint16_t ret; 15504b0d7b7fSYongseok Koh 15514b0d7b7fSYongseok Koh n = txq_count_contig_multi_seg(&pkts[nb_tx], pkts_n - nb_tx); 15524b0d7b7fSYongseok Koh if (n) { 15534b0d7b7fSYongseok Koh ret = mlx5_tx_burst(dpdk_txq, &pkts[nb_tx], n); 15544b0d7b7fSYongseok Koh if (!ret) 15554b0d7b7fSYongseok Koh break; 15564b0d7b7fSYongseok Koh nb_tx += ret; 15574b0d7b7fSYongseok Koh } 15584b0d7b7fSYongseok Koh n = txq_count_contig_single_seg(&pkts[nb_tx], pkts_n - nb_tx); 15594b0d7b7fSYongseok Koh if (n) { 15604b0d7b7fSYongseok Koh ret = txq_burst_empw(txq, &pkts[nb_tx], n); 15614b0d7b7fSYongseok Koh if (!ret) 15624b0d7b7fSYongseok Koh break; 15634b0d7b7fSYongseok Koh nb_tx += ret; 15644b0d7b7fSYongseok Koh } 15654b0d7b7fSYongseok Koh } 15664b0d7b7fSYongseok Koh return nb_tx; 15674b0d7b7fSYongseok Koh } 15684b0d7b7fSYongseok Koh 15694b0d7b7fSYongseok Koh /** 157067fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 157167fa62bcSAdrien Mazarguil * 15726218063bSNélio Laranjeiro * @param[in] cqe 15736218063bSNélio Laranjeiro * Pointer to CQE. 157467fa62bcSAdrien Mazarguil * 157578a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 157678a38edfSJianfeng Tan * 157767fa62bcSAdrien Mazarguil * @return 157867fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 157967fa62bcSAdrien Mazarguil */ 158067fa62bcSAdrien Mazarguil static inline uint32_t 158197267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 158267fa62bcSAdrien Mazarguil { 1583ea16068cSYongseok Koh uint8_t idx; 1584ea16068cSYongseok Koh uint8_t pinfo = cqe->pkt_info; 1585ea16068cSYongseok Koh uint16_t ptype = cqe->hdr_type_etc; 158667fa62bcSAdrien Mazarguil 1587ea16068cSYongseok Koh /* 1588ea16068cSYongseok Koh * The index to the array should have: 1589ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 1590ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 1591ea16068cSYongseok Koh * bit[5] = ip_frag 1592ea16068cSYongseok Koh * bit[6] = tunneled 1593ea16068cSYongseok Koh * bit[7] = outer_l3_type 1594ea16068cSYongseok Koh */ 1595ea16068cSYongseok Koh idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10); 1596ea16068cSYongseok Koh return mlx5_ptype_table[idx]; 159767fa62bcSAdrien Mazarguil } 159867fa62bcSAdrien Mazarguil 159967fa62bcSAdrien Mazarguil /** 160099c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 160199c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 160299c12dccSNélio Laranjeiro * been processed. 160399c12dccSNélio Laranjeiro * 160499c12dccSNélio Laranjeiro * @param rxq 160599c12dccSNélio Laranjeiro * Pointer to RX queue. 160699c12dccSNélio Laranjeiro * @param cqe 160799c12dccSNélio Laranjeiro * CQE to process. 1608ecf60761SNélio Laranjeiro * @param[out] rss_hash 1609ecf60761SNélio Laranjeiro * Packet RSS Hash result. 161099c12dccSNélio Laranjeiro * 161199c12dccSNélio Laranjeiro * @return 161299c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 161399c12dccSNélio Laranjeiro * with error. 161499c12dccSNélio Laranjeiro */ 161599c12dccSNélio Laranjeiro static inline int 161678142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 1617ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 161899c12dccSNélio Laranjeiro { 161999c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 162099c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 162199c12dccSNélio Laranjeiro int len = 0; 1622d2e842d0SYongseok Koh uint16_t idx, end; 162399c12dccSNélio Laranjeiro 162499c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 162599c12dccSNélio Laranjeiro if (zip->ai) { 162699c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 162799c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 16284aff4bcbSYongseok Koh (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info); 162999c12dccSNélio Laranjeiro 16306b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt); 16316b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result); 163299c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1633d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1634d2e842d0SYongseok Koh idx = zip->ca; 1635d2e842d0SYongseok Koh end = zip->na; 1636d2e842d0SYongseok Koh while (idx != end) { 1637d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1638d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1639d2e842d0SYongseok Koh ++idx; 1640d2e842d0SYongseok Koh } 164199c12dccSNélio Laranjeiro /* 164299c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 164399c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 164499c12dccSNélio Laranjeiro * ring for software use. 164599c12dccSNélio Laranjeiro */ 164699c12dccSNélio Laranjeiro zip->ca = zip->na; 164799c12dccSNélio Laranjeiro zip->na += 8; 164899c12dccSNélio Laranjeiro } 164999c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1650d2e842d0SYongseok Koh /* Invalidate the rest */ 1651d2e842d0SYongseok Koh idx = zip->ca; 1652d2e842d0SYongseok Koh end = zip->cq_ci; 165399c12dccSNélio Laranjeiro 165499c12dccSNélio Laranjeiro while (idx != end) { 165597267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 165699c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 165799c12dccSNélio Laranjeiro ++idx; 165899c12dccSNélio Laranjeiro } 165999c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 166099c12dccSNélio Laranjeiro zip->ai = 0; 166199c12dccSNélio Laranjeiro } 166299c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 166399c12dccSNélio Laranjeiro } else { 166499c12dccSNélio Laranjeiro int ret; 166599c12dccSNélio Laranjeiro int8_t op_own; 166699c12dccSNélio Laranjeiro 166797267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 166899c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 166999c12dccSNélio Laranjeiro return 0; 167099c12dccSNélio Laranjeiro ++rxq->cq_ci; 167199c12dccSNélio Laranjeiro op_own = cqe->op_own; 167299c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 167399c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 167499c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 167599c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 16764aff4bcbSYongseok Koh cqe_cnt].pkt_info); 167799c12dccSNélio Laranjeiro 167899c12dccSNélio Laranjeiro /* Fix endianness. */ 16796b30a6a8SShachar Beiser zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt); 168099c12dccSNélio Laranjeiro /* 168199c12dccSNélio Laranjeiro * Current mini array position is the one returned by 168299c12dccSNélio Laranjeiro * check_cqe64(). 168399c12dccSNélio Laranjeiro * 168499c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 168599c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 168699c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 168799c12dccSNélio Laranjeiro */ 1688d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 168999c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 169099c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 169199c12dccSNélio Laranjeiro --rxq->cq_ci; 169299c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 169399c12dccSNélio Laranjeiro /* Get packet size to return. */ 16946b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[0].byte_cnt); 16956b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result); 169699c12dccSNélio Laranjeiro zip->ai = 1; 1697d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1698d2e842d0SYongseok Koh idx = zip->ca; 1699d2e842d0SYongseok Koh end = zip->cq_ci; 1700d2e842d0SYongseok Koh while (idx != end) { 1701d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1702d2e842d0SYongseok Koh ++idx; 1703d2e842d0SYongseok Koh } 170499c12dccSNélio Laranjeiro } else { 17056b30a6a8SShachar Beiser len = rte_be_to_cpu_32(cqe->byte_cnt); 17066b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res); 170799c12dccSNélio Laranjeiro } 170899c12dccSNélio Laranjeiro /* Error while receiving packet. */ 170999c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 171099c12dccSNélio Laranjeiro return -1; 171199c12dccSNélio Laranjeiro } 171299c12dccSNélio Laranjeiro return len; 171399c12dccSNélio Laranjeiro } 171499c12dccSNélio Laranjeiro 171599c12dccSNélio Laranjeiro /** 171667fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 171767fa62bcSAdrien Mazarguil * 171867fa62bcSAdrien Mazarguil * @param[in] rxq 171967fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 17206218063bSNélio Laranjeiro * @param[in] cqe 17216218063bSNélio Laranjeiro * Pointer to CQE. 172267fa62bcSAdrien Mazarguil * 172367fa62bcSAdrien Mazarguil * @return 172467fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 172567fa62bcSAdrien Mazarguil */ 172667fa62bcSAdrien Mazarguil static inline uint32_t 172778142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe) 172867fa62bcSAdrien Mazarguil { 172967fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 17306b30a6a8SShachar Beiser uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 173167fa62bcSAdrien Mazarguil 17320603df73SNélio Laranjeiro ol_flags = 17330603df73SNélio Laranjeiro TRANSPOSE(flags, 17340603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 17350603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17360603df73SNélio Laranjeiro TRANSPOSE(flags, 17370603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 173883e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 173997267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 174067fa62bcSAdrien Mazarguil ol_flags |= 17410603df73SNélio Laranjeiro TRANSPOSE(flags, 17420603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 174383e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17440603df73SNélio Laranjeiro TRANSPOSE(flags, 17450603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 174683e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 174767fa62bcSAdrien Mazarguil return ol_flags; 174867fa62bcSAdrien Mazarguil } 174967fa62bcSAdrien Mazarguil 175067fa62bcSAdrien Mazarguil /** 17512e22920bSAdrien Mazarguil * DPDK callback for RX. 17522e22920bSAdrien Mazarguil * 17532e22920bSAdrien Mazarguil * @param dpdk_rxq 17542e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 17552e22920bSAdrien Mazarguil * @param[out] pkts 17562e22920bSAdrien Mazarguil * Array to store received packets. 17572e22920bSAdrien Mazarguil * @param pkts_n 17582e22920bSAdrien Mazarguil * Maximum number of packets in array. 17592e22920bSAdrien Mazarguil * 17602e22920bSAdrien Mazarguil * @return 17612e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 17622e22920bSAdrien Mazarguil */ 17632e22920bSAdrien Mazarguil uint16_t 17642e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 17652e22920bSAdrien Mazarguil { 176678142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = dpdk_rxq; 1767b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1768e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 17699964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 17709964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 17719964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 177297267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 177397267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 17749964b965SNélio Laranjeiro unsigned int i = 0; 17759964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 17764e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 17772e22920bSAdrien Mazarguil 17789964b965SNélio Laranjeiro while (pkts_n) { 17799964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 17809964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 17819964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1782ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 17839964b965SNélio Laranjeiro 17849964b965SNélio Laranjeiro if (pkt) 17859964b965SNélio Laranjeiro NEXT(seg) = rep; 17869964b965SNélio Laranjeiro seg = rep; 17879964b965SNélio Laranjeiro rte_prefetch0(seg); 17886218063bSNélio Laranjeiro rte_prefetch0(cqe); 17899964b965SNélio Laranjeiro rte_prefetch0(wqe); 1790fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 17912e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 179215a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 179315a756b6SSagi Grimberg if (!pkt) { 179415a756b6SSagi Grimberg /* 179515a756b6SSagi Grimberg * no buffers before we even started, 179615a756b6SSagi Grimberg * bail out silently. 179715a756b6SSagi Grimberg */ 179815a756b6SSagi Grimberg break; 179915a756b6SSagi Grimberg } 1800a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1801a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1802fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 18038f094a9aSOlivier Matz NEXT(pkt) = NULL; 18048f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 18051f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 1806fe5fe382SNélio Laranjeiro pkt = rep; 18079964b965SNélio Laranjeiro } 18086218063bSNélio Laranjeiro break; 18092e22920bSAdrien Mazarguil } 18109964b965SNélio Laranjeiro if (!pkt) { 181197267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1812ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1813ecf60761SNélio Laranjeiro &rss_hash_res); 1814ecf60761SNélio Laranjeiro if (!len) { 18151f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 18166218063bSNélio Laranjeiro break; 18176218063bSNélio Laranjeiro } 181899c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 181999c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 18201f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 182199c12dccSNélio Laranjeiro ++rxq->stats.idropped; 182299c12dccSNélio Laranjeiro goto skip; 182399c12dccSNélio Laranjeiro } 18249964b965SNélio Laranjeiro pkt = seg; 18259964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 18269964b965SNélio Laranjeiro /* Update packet information. */ 182748dfc20fSYongseok Koh pkt->packet_type = rxq_cq_to_pkt_type(cqe); 18280ac64846SMaxime Leroy pkt->ol_flags = 0; 182936ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1830ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1831ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1832ecf60761SNélio Laranjeiro } 1833c604f619SNélio Laranjeiro if (rxq->mark && 1834c604f619SNélio Laranjeiro MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 1835b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 1836b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 18376b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) { 1838b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 1839b268a3eeSNélio Laranjeiro 1840b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 1841ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1842b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 1843b268a3eeSNélio Laranjeiro } 1844ea3bc3b1SNélio Laranjeiro } 184548dfc20fSYongseok Koh if (rxq->csum | rxq->csum_l2tun) 18466703d836SNélio Laranjeiro pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe); 18476703d836SNélio Laranjeiro if (rxq->vlan_strip && 18486703d836SNélio Laranjeiro (cqe->hdr_type_etc & 18496b30a6a8SShachar Beiser rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) { 1850380a7aabSOlivier Matz pkt->ol_flags |= PKT_RX_VLAN | 1851b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 18526b30a6a8SShachar Beiser pkt->vlan_tci = 18536b30a6a8SShachar Beiser rte_be_to_cpu_16(cqe->vlan_info); 1854f3db9489SYaacov Hazan } 185578c7406bSRaslan Darawsheh if (rxq->hw_timestamp) { 185678c7406bSRaslan Darawsheh pkt->timestamp = 185778c7406bSRaslan Darawsheh rte_be_to_cpu_64(cqe->timestamp); 185878c7406bSRaslan Darawsheh pkt->ol_flags |= PKT_RX_TIMESTAMP; 185978c7406bSRaslan Darawsheh } 18606218063bSNélio Laranjeiro if (rxq->crc_present) 18616218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 18626218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 18639964b965SNélio Laranjeiro } 18649964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 18659964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 18669964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 18679964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 18689964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 18699964b965SNélio Laranjeiro /* 18709964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 18719964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 18729964b965SNélio Laranjeiro * changes. 18739964b965SNélio Laranjeiro */ 18746b30a6a8SShachar Beiser wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 18759964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 18769964b965SNélio Laranjeiro len -= DATA_LEN(seg); 18779964b965SNélio Laranjeiro ++NB_SEGS(pkt); 18789964b965SNélio Laranjeiro ++rq_ci; 18799964b965SNélio Laranjeiro continue; 18809964b965SNélio Laranjeiro } 18819964b965SNélio Laranjeiro DATA_LEN(seg) = len; 188287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 188387011737SAdrien Mazarguil /* Increment bytes counter. */ 18849964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 188587011737SAdrien Mazarguil #endif 18866218063bSNélio Laranjeiro /* Return packet. */ 18876218063bSNélio Laranjeiro *(pkts++) = pkt; 18889964b965SNélio Laranjeiro pkt = NULL; 18899964b965SNélio Laranjeiro --pkts_n; 18909964b965SNélio Laranjeiro ++i; 189199c12dccSNélio Laranjeiro skip: 18929964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 18939964b965SNélio Laranjeiro rq_ci >>= sges_n; 18946218063bSNélio Laranjeiro ++rq_ci; 18959964b965SNélio Laranjeiro rq_ci <<= sges_n; 18962e22920bSAdrien Mazarguil } 18979964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 18982e22920bSAdrien Mazarguil return 0; 18996218063bSNélio Laranjeiro /* Update the consumer index. */ 19009964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 1901*4fe7f662SYongseok Koh rte_cio_wmb(); 19026b30a6a8SShachar Beiser *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 1903*4fe7f662SYongseok Koh rte_cio_wmb(); 19046b30a6a8SShachar Beiser *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 190587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 190687011737SAdrien Mazarguil /* Increment packets counter. */ 19079964b965SNélio Laranjeiro rxq->stats.ipackets += i; 190887011737SAdrien Mazarguil #endif 19099964b965SNélio Laranjeiro return i; 19102e22920bSAdrien Mazarguil } 19112e22920bSAdrien Mazarguil 19122e22920bSAdrien Mazarguil /** 19132e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 19142e22920bSAdrien Mazarguil * 19152e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19162e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19172e22920bSAdrien Mazarguil * 19182e22920bSAdrien Mazarguil * @param dpdk_txq 19192e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 19202e22920bSAdrien Mazarguil * @param[in] pkts 19212e22920bSAdrien Mazarguil * Packets to transmit. 19222e22920bSAdrien Mazarguil * @param pkts_n 19232e22920bSAdrien Mazarguil * Number of packets in array. 19242e22920bSAdrien Mazarguil * 19252e22920bSAdrien Mazarguil * @return 19262e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 19272e22920bSAdrien Mazarguil */ 19282e22920bSAdrien Mazarguil uint16_t 19292e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 19302e22920bSAdrien Mazarguil { 19312e22920bSAdrien Mazarguil (void)dpdk_txq; 19322e22920bSAdrien Mazarguil (void)pkts; 19332e22920bSAdrien Mazarguil (void)pkts_n; 19342e22920bSAdrien Mazarguil return 0; 19352e22920bSAdrien Mazarguil } 19362e22920bSAdrien Mazarguil 19372e22920bSAdrien Mazarguil /** 19382e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 19392e22920bSAdrien Mazarguil * 19402e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19412e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19422e22920bSAdrien Mazarguil * 19432e22920bSAdrien Mazarguil * @param dpdk_rxq 19442e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 19452e22920bSAdrien Mazarguil * @param[out] pkts 19462e22920bSAdrien Mazarguil * Array to store received packets. 19472e22920bSAdrien Mazarguil * @param pkts_n 19482e22920bSAdrien Mazarguil * Maximum number of packets in array. 19492e22920bSAdrien Mazarguil * 19502e22920bSAdrien Mazarguil * @return 19512e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 19522e22920bSAdrien Mazarguil */ 19532e22920bSAdrien Mazarguil uint16_t 19542e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 19552e22920bSAdrien Mazarguil { 19562e22920bSAdrien Mazarguil (void)dpdk_rxq; 19572e22920bSAdrien Mazarguil (void)pkts; 19582e22920bSAdrien Mazarguil (void)pkts_n; 19592e22920bSAdrien Mazarguil return 0; 19602e22920bSAdrien Mazarguil } 19616cb559d6SYongseok Koh 19626cb559d6SYongseok Koh /* 19636cb559d6SYongseok Koh * Vectorized Rx/Tx routines are not compiled in when required vector 19646cb559d6SYongseok Koh * instructions are not supported on a target architecture. The following null 19656cb559d6SYongseok Koh * stubs are needed for linkage when those are not included outside of this file 19666cb559d6SYongseok Koh * (e.g. mlx5_rxtx_vec_sse.c for x86). 19676cb559d6SYongseok Koh */ 19686cb559d6SYongseok Koh 19696cb559d6SYongseok Koh uint16_t __attribute__((weak)) 19706cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 19716cb559d6SYongseok Koh { 19726cb559d6SYongseok Koh (void)dpdk_txq; 19736cb559d6SYongseok Koh (void)pkts; 19746cb559d6SYongseok Koh (void)pkts_n; 19756cb559d6SYongseok Koh return 0; 19766cb559d6SYongseok Koh } 19776cb559d6SYongseok Koh 19786cb559d6SYongseok Koh uint16_t __attribute__((weak)) 19796cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 19806cb559d6SYongseok Koh { 19816cb559d6SYongseok Koh (void)dpdk_txq; 19826cb559d6SYongseok Koh (void)pkts; 19836cb559d6SYongseok Koh (void)pkts_n; 19846cb559d6SYongseok Koh return 0; 19856cb559d6SYongseok Koh } 19866cb559d6SYongseok Koh 19876cb559d6SYongseok Koh uint16_t __attribute__((weak)) 19886cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 19896cb559d6SYongseok Koh { 19906cb559d6SYongseok Koh (void)dpdk_rxq; 19916cb559d6SYongseok Koh (void)pkts; 19926cb559d6SYongseok Koh (void)pkts_n; 19936cb559d6SYongseok Koh return 0; 19946cb559d6SYongseok Koh } 19956cb559d6SYongseok Koh 19966cb559d6SYongseok Koh int __attribute__((weak)) 1997dbccb4cdSShahaf Shuler priv_check_raw_vec_tx_support(struct priv *priv, struct rte_eth_dev *dev) 19986cb559d6SYongseok Koh { 19996cb559d6SYongseok Koh (void)priv; 2000dbccb4cdSShahaf Shuler (void)dev; 20016cb559d6SYongseok Koh return -ENOTSUP; 20026cb559d6SYongseok Koh } 20036cb559d6SYongseok Koh 20046cb559d6SYongseok Koh int __attribute__((weak)) 2005dbccb4cdSShahaf Shuler priv_check_vec_tx_support(struct priv *priv, struct rte_eth_dev *dev) 20066cb559d6SYongseok Koh { 20076cb559d6SYongseok Koh (void)priv; 2008dbccb4cdSShahaf Shuler (void)dev; 20096cb559d6SYongseok Koh return -ENOTSUP; 20106cb559d6SYongseok Koh } 20116cb559d6SYongseok Koh 20126cb559d6SYongseok Koh int __attribute__((weak)) 201378142aacSNélio Laranjeiro rxq_check_vec_support(struct mlx5_rxq_data *rxq) 20146cb559d6SYongseok Koh { 20156cb559d6SYongseok Koh (void)rxq; 20166cb559d6SYongseok Koh return -ENOTSUP; 20176cb559d6SYongseok Koh } 20186cb559d6SYongseok Koh 20196cb559d6SYongseok Koh int __attribute__((weak)) 20206cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv) 20216cb559d6SYongseok Koh { 20226cb559d6SYongseok Koh (void)priv; 20236cb559d6SYongseok Koh return -ENOTSUP; 20246cb559d6SYongseok Koh } 2025