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 */ 100*3ca63b88SShahaf Shuler /* L2 */ 101*3ca63b88SShahaf 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 | 168ea16068cSYongseok Koh RTE_PTYPE_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 | 171ea16068cSYongseok Koh RTE_PTYPE_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 | 174ea16068cSYongseok Koh RTE_PTYPE_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 | 177ea16068cSYongseok Koh RTE_PTYPE_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 | 181ea16068cSYongseok Koh RTE_PTYPE_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 | 184ea16068cSYongseok Koh RTE_PTYPE_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 | 187ea16068cSYongseok Koh RTE_PTYPE_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 | 190ea16068cSYongseok Koh RTE_PTYPE_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; 347ab76eab3SYongseok Koh unsigned int max_inline = txq->max_inline; 348ab76eab3SYongseok Koh const unsigned int inline_en = !!max_inline && txq->inline_en; 349f04f1d51SNélio Laranjeiro uint16_t max_wqe; 350c305090bSAdrien Mazarguil unsigned int comp; 3519a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 352ac180a21SYongseok Koh volatile struct mlx5_wqe_ctrl *last_wqe = NULL; 3536579c27cSNélio Laranjeiro unsigned int segs_n = 0; 3546579c27cSNélio Laranjeiro struct rte_mbuf *buf = NULL; 3556579c27cSNélio Laranjeiro uint8_t *raw; 3562e22920bSAdrien Mazarguil 3571d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 3581d88ba17SNélio Laranjeiro return 0; 3595e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 360c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 3611d88ba17SNélio Laranjeiro /* Start processing. */ 3626cb559d6SYongseok Koh mlx5_tx_complete(txq); 3638c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 364f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 365f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 366f04f1d51SNélio Laranjeiro return 0; 367c3d62cc9SAdrien Mazarguil do { 3689a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 369573f54afSNélio Laranjeiro uint32_t length; 3708688b2f8SNélio Laranjeiro unsigned int ds = 0; 371ac180a21SYongseok Koh unsigned int sg = 0; /* counter of additional segs attached. */ 3726579c27cSNélio Laranjeiro uintptr_t addr; 3739a7fa9f7SNélio Laranjeiro uint64_t naddr; 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; 3779a7fa9f7SNélio Laranjeiro uint8_t cs_flags = 0; 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; 3956579c27cSNélio Laranjeiro --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 *)); 4201d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 4211d88ba17SNélio Laranjeiro if (buf->ol_flags & 4221d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 423f5fde520SShahaf Shuler const uint64_t is_tunneled = buf->ol_flags & 424f5fde520SShahaf Shuler (PKT_TX_TUNNEL_GRE | 425f5fde520SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 426f5fde520SShahaf Shuler 427f5fde520SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 428f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM | 429f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_INNER_CSUM; 430f5fde520SShahaf Shuler if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM) 431f5fde520SShahaf Shuler cs_flags |= MLX5_ETH_WQE_L3_CSUM; 432f5fde520SShahaf Shuler } else { 433f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_CSUM | 434f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_CSUM; 435f5fde520SShahaf Shuler } 4361d88ba17SNélio Laranjeiro } 437b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 4386579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 4396579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 4406b30a6a8SShachar Beiser uint32_t vlan = rte_cpu_to_be_32(0x81000000 | 4416b30a6a8SShachar Beiser buf->vlan_tci); 4420d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 4436579c27cSNélio Laranjeiro 4440d637a34SNélio Laranjeiro addr += 2; 4450d637a34SNélio Laranjeiro length -= 2; 4460d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 4470d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 4480d637a34SNélio Laranjeiro /* Copy VLAN. */ 4490d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 4500d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 4510d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 4520d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 4530d637a34SNélio Laranjeiro addr += len + 2; 4540d637a34SNélio Laranjeiro length -= (len + 2); 4550d637a34SNélio Laranjeiro } else { 4560d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 4570d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 4580d637a34SNélio Laranjeiro length -= pkt_inline_sz; 4590d637a34SNélio Laranjeiro addr += pkt_inline_sz; 4606579c27cSNélio Laranjeiro } 461d8292497SYongseok Koh raw += MLX5_WQE_DWORD_SIZE; 4623f13f8c2SShahaf Shuler if (txq->tso_en) { 4633f13f8c2SShahaf Shuler tso = buf->ol_flags & PKT_TX_TCP_SEG; 4643f13f8c2SShahaf Shuler if (tso) { 4653f13f8c2SShahaf Shuler uintptr_t end = (uintptr_t) 4663f13f8c2SShahaf Shuler (((uintptr_t)txq->wqes) + 4673f13f8c2SShahaf Shuler (1 << txq->wqe_n) * 4683f13f8c2SShahaf Shuler MLX5_WQE_SIZE); 4693f13f8c2SShahaf Shuler unsigned int copy_b; 4703f13f8c2SShahaf Shuler uint8_t vlan_sz = (buf->ol_flags & 4713f13f8c2SShahaf Shuler PKT_TX_VLAN_PKT) ? 4 : 0; 472b247f346SShahaf Shuler const uint64_t is_tunneled = 473b247f346SShahaf Shuler buf->ol_flags & 474b247f346SShahaf Shuler (PKT_TX_TUNNEL_GRE | 475b247f346SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 4763f13f8c2SShahaf Shuler 4773f13f8c2SShahaf Shuler tso_header_sz = buf->l2_len + vlan_sz + 4783f13f8c2SShahaf Shuler buf->l3_len + buf->l4_len; 47983daf156SShahaf Shuler tso_segsz = buf->tso_segsz; 48096fc8d65SShahaf Shuler if (unlikely(tso_segsz == 0)) { 48196fc8d65SShahaf Shuler txq->stats.oerrors++; 48296fc8d65SShahaf Shuler break; 48396fc8d65SShahaf Shuler } 484b247f346SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 485b247f346SShahaf Shuler tso_header_sz += buf->outer_l2_len + 486b247f346SShahaf Shuler buf->outer_l3_len; 4872a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM; 4882a6c96beSShahaf Shuler } else { 4892a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_CSUM; 490b247f346SShahaf Shuler } 4913f13f8c2SShahaf Shuler if (unlikely(tso_header_sz > 49224c14430SShahaf Shuler MLX5_MAX_TSO_HEADER)) { 49324c14430SShahaf Shuler txq->stats.oerrors++; 4943f13f8c2SShahaf Shuler break; 49524c14430SShahaf Shuler } 4963f13f8c2SShahaf Shuler copy_b = tso_header_sz - pkt_inline_sz; 4973f13f8c2SShahaf Shuler /* First seg must contain all headers. */ 4983f13f8c2SShahaf Shuler assert(copy_b <= length); 4993f13f8c2SShahaf Shuler if (copy_b && 5003f13f8c2SShahaf Shuler ((end - (uintptr_t)raw) > copy_b)) { 5013f13f8c2SShahaf Shuler uint16_t n = (MLX5_WQE_DS(copy_b) - 5023f13f8c2SShahaf Shuler 1 + 3) / 4; 5033f13f8c2SShahaf Shuler 5043f13f8c2SShahaf Shuler if (unlikely(max_wqe < n)) 5053f13f8c2SShahaf Shuler break; 5063f13f8c2SShahaf Shuler max_wqe -= n; 5073f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 5083f13f8c2SShahaf Shuler (void *)addr, copy_b); 5093f13f8c2SShahaf Shuler addr += copy_b; 5103f13f8c2SShahaf Shuler length -= copy_b; 511d8292497SYongseok Koh /* Include padding for TSO header. */ 512d8292497SYongseok Koh copy_b = MLX5_WQE_DS(copy_b) * 5133f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 514d8292497SYongseok Koh pkt_inline_sz += copy_b; 515d8292497SYongseok Koh raw += copy_b; 5163f13f8c2SShahaf Shuler } else { 5173f13f8c2SShahaf Shuler /* NOP WQE. */ 5183f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 5196b30a6a8SShachar Beiser rte_cpu_to_be_32( 5206b30a6a8SShachar Beiser txq->wqe_ci << 8), 5216b30a6a8SShachar Beiser rte_cpu_to_be_32( 5226b30a6a8SShachar Beiser txq->qp_num_8s | 1), 5233f13f8c2SShahaf Shuler 0, 5243f13f8c2SShahaf Shuler 0, 5253f13f8c2SShahaf Shuler }; 5263f13f8c2SShahaf Shuler ds = 1; 5273f13f8c2SShahaf Shuler total_length = 0; 5283f13f8c2SShahaf Shuler k++; 5293f13f8c2SShahaf Shuler goto next_wqe; 5303f13f8c2SShahaf Shuler } 5313f13f8c2SShahaf Shuler } 5323f13f8c2SShahaf Shuler } 5336579c27cSNélio Laranjeiro /* Inline if enough room. */ 534ab76eab3SYongseok Koh if (inline_en || tso) { 535d8292497SYongseok Koh uint32_t inl; 536fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 537fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 538fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 539ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 5408fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 541d8292497SYongseok Koh (pkt_inline_sz - 2) - 542d8292497SYongseok Koh !!tso * sizeof(inl); 543ab76eab3SYongseok Koh uintptr_t addr_end = (addr + inline_room) & 5446579c27cSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 5458fcd6c2cSNélio Laranjeiro unsigned int copy_b = (addr_end > addr) ? 5468fcd6c2cSNélio Laranjeiro RTE_MIN((addr_end - addr), length) : 5478fcd6c2cSNélio Laranjeiro 0; 5486579c27cSNélio Laranjeiro 5498fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 550f04f1d51SNélio Laranjeiro /* 551f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 552f04f1d51SNélio Laranjeiro * keep the computation positive, it is 553f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 554f04f1d51SNélio Laranjeiro */ 5558fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 5568fcd6c2cSNélio Laranjeiro 557f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 558f04f1d51SNélio Laranjeiro break; 559f04f1d51SNélio Laranjeiro max_wqe -= n; 5603f13f8c2SShahaf Shuler if (tso) { 5616b30a6a8SShachar Beiser uint32_t inl = 5626b30a6a8SShachar Beiser rte_cpu_to_be_32(copy_b | 5636b30a6a8SShachar Beiser MLX5_INLINE_SEG); 5646b30a6a8SShachar Beiser 5656b30a6a8SShachar Beiser pkt_inline_sz = 5666b30a6a8SShachar Beiser MLX5_WQE_DS(tso_header_sz) * 5676b30a6a8SShachar Beiser MLX5_WQE_DWORD_SIZE; 5686b30a6a8SShachar Beiser 5693f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 5703f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 5713f13f8c2SShahaf Shuler raw += sizeof(inl); 5723f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 5733f13f8c2SShahaf Shuler } 5746579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 5756579c27cSNélio Laranjeiro addr += copy_b; 5766579c27cSNélio Laranjeiro length -= copy_b; 5776579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 5786579c27cSNélio Laranjeiro } 5796579c27cSNélio Laranjeiro /* 580786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 5816579c27cSNélio Laranjeiro * the size of the inline part of the packet. 5826579c27cSNélio Laranjeiro */ 5836579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 5846579c27cSNélio Laranjeiro if (length > 0) { 585f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 586f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 587f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 588f04f1d51SNélio Laranjeiro break; 589f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 590f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 591f04f1d51SNélio Laranjeiro ds / 4); 592f04f1d51SNélio Laranjeiro } else { 5939a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 5946579c27cSNélio Laranjeiro ((uintptr_t)wqe + 5956579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 596f04f1d51SNélio Laranjeiro } 5976579c27cSNélio Laranjeiro goto use_dseg; 5986579c27cSNélio Laranjeiro } else if (!segs_n) { 5996579c27cSNélio Laranjeiro goto next_pkt; 6006579c27cSNélio Laranjeiro } else { 601786b5c2dSShahaf Shuler /* dseg will be advance as part of next_seg */ 602786b5c2dSShahaf Shuler dseg = (volatile rte_v128u32_t *) 603786b5c2dSShahaf Shuler ((uintptr_t)wqe + 604786b5c2dSShahaf Shuler ((ds - 1) * MLX5_WQE_DWORD_SIZE)); 6056579c27cSNélio Laranjeiro goto next_seg; 6066579c27cSNélio Laranjeiro } 6076579c27cSNélio Laranjeiro } else { 6086579c27cSNélio Laranjeiro /* 6096579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 6106579c27cSNélio Laranjeiro * Ethernet Header as been stored. 6116579c27cSNélio Laranjeiro */ 6129a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 6136579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 6146579c27cSNélio Laranjeiro ds = 3; 6156579c27cSNélio Laranjeiro use_dseg: 6166579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 6176b30a6a8SShachar Beiser naddr = rte_cpu_to_be_64(addr); 6189a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6196b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 6206cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 6219a7fa9f7SNélio Laranjeiro naddr, 6229a7fa9f7SNélio Laranjeiro naddr >> 32, 6236579c27cSNélio Laranjeiro }; 6246579c27cSNélio Laranjeiro ++ds; 6256579c27cSNélio Laranjeiro if (!segs_n) 6266579c27cSNélio Laranjeiro goto next_pkt; 6276579c27cSNélio Laranjeiro } 6286579c27cSNélio Laranjeiro next_seg: 6296579c27cSNélio Laranjeiro assert(buf); 6306579c27cSNélio Laranjeiro assert(ds); 6316579c27cSNélio Laranjeiro assert(wqe); 632a5bf6af9SAdrien Mazarguil /* 633a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 634a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 635a5bf6af9SAdrien Mazarguil * of data segment size. 636a5bf6af9SAdrien Mazarguil */ 6378688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 6386579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 639f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 640f04f1d51SNélio Laranjeiro break; 6419a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 642f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 643f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 644f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 6456579c27cSNélio Laranjeiro } else { 646a5bf6af9SAdrien Mazarguil ++dseg; 6476579c27cSNélio Laranjeiro } 648a5bf6af9SAdrien Mazarguil ++ds; 649a5bf6af9SAdrien Mazarguil buf = buf->next; 650a5bf6af9SAdrien Mazarguil assert(buf); 6516579c27cSNélio Laranjeiro length = DATA_LEN(buf); 652a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 6536579c27cSNélio Laranjeiro total_length += length; 654a5bf6af9SAdrien Mazarguil #endif 6556579c27cSNélio Laranjeiro /* Store segment information. */ 6566b30a6a8SShachar Beiser naddr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)); 6579a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6586b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 6596cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 6609a7fa9f7SNélio Laranjeiro naddr, 6619a7fa9f7SNélio Laranjeiro naddr >> 32, 6626579c27cSNélio Laranjeiro }; 6638c819a69SYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 664ac180a21SYongseok Koh ++sg; 665ac180a21SYongseok Koh /* Advance counter only if all segs are successfully posted. */ 6663730e6c6SYongseok Koh if (sg < segs_n) 6676579c27cSNélio Laranjeiro goto next_seg; 6683730e6c6SYongseok Koh else 669ac180a21SYongseok Koh j += sg; 6706579c27cSNélio Laranjeiro next_pkt: 671883ce172SShahaf Shuler if (ds > MLX5_DSEG_MAX) { 672883ce172SShahaf Shuler txq->stats.oerrors++; 673883ce172SShahaf Shuler break; 674883ce172SShahaf Shuler } 6758c819a69SYongseok Koh ++elts_head; 6763730e6c6SYongseok Koh ++pkts; 6776579c27cSNélio Laranjeiro ++i; 678b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 6793f13f8c2SShahaf Shuler if (tso) { 6803f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 6816b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 6826b30a6a8SShachar Beiser MLX5_OPCODE_TSO), 6836b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 6843f13f8c2SShahaf Shuler 0, 6853f13f8c2SShahaf Shuler 0, 6863f13f8c2SShahaf Shuler }; 6873f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 6883f13f8c2SShahaf Shuler 0, 6896b30a6a8SShachar Beiser cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16), 6903f13f8c2SShahaf Shuler 0, 6916b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(tso_header_sz), 6923f13f8c2SShahaf Shuler }; 6933f13f8c2SShahaf Shuler } else { 6949a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 6956b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 6966b30a6a8SShachar Beiser MLX5_OPCODE_SEND), 6976b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 6989a7fa9f7SNélio Laranjeiro 0, 6999a7fa9f7SNélio Laranjeiro 0, 7009a7fa9f7SNélio Laranjeiro }; 7019a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 7029a7fa9f7SNélio Laranjeiro 0, 7039a7fa9f7SNélio Laranjeiro cs_flags, 7049a7fa9f7SNélio Laranjeiro 0, 7056b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz), 7069a7fa9f7SNélio Laranjeiro }; 7073f13f8c2SShahaf Shuler } 7083f13f8c2SShahaf Shuler next_wqe: 7096579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 710ac180a21SYongseok Koh /* Save the last successful WQE for completion request */ 711ac180a21SYongseok Koh last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe; 71287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 713573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 7146579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 71587011737SAdrien Mazarguil #endif 7163730e6c6SYongseok Koh } while (i < pkts_n); 7172e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 7183f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 7192e22920bSAdrien Mazarguil return 0; 7208c819a69SYongseok Koh txq->elts_head += (i + j); 721c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 7223f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 723c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 724c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 7256b30a6a8SShachar Beiser last_wqe->ctrl2 = rte_cpu_to_be_32(8); 726c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 727ac180a21SYongseok Koh last_wqe->ctrl3 = txq->elts_head; 728c305090bSAdrien Mazarguil txq->elts_comp = 0; 729c305090bSAdrien Mazarguil } else { 730c305090bSAdrien Mazarguil txq->elts_comp = comp; 731c305090bSAdrien Mazarguil } 73287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 73387011737SAdrien Mazarguil /* Increment sent packets counter. */ 73487011737SAdrien Mazarguil txq->stats.opackets += i; 73587011737SAdrien Mazarguil #endif 7362e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 737ac180a21SYongseok Koh mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe); 7382e22920bSAdrien Mazarguil return i; 7392e22920bSAdrien Mazarguil } 7402e22920bSAdrien Mazarguil 7412e22920bSAdrien Mazarguil /** 742230189d9SNélio Laranjeiro * Open a MPW session. 743230189d9SNélio Laranjeiro * 744230189d9SNélio Laranjeiro * @param txq 745230189d9SNélio Laranjeiro * Pointer to TX queue structure. 746230189d9SNélio Laranjeiro * @param mpw 747230189d9SNélio Laranjeiro * Pointer to MPW session structure. 748230189d9SNélio Laranjeiro * @param length 749230189d9SNélio Laranjeiro * Packet length. 750230189d9SNélio Laranjeiro */ 751230189d9SNélio Laranjeiro static inline void 752991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length) 753230189d9SNélio Laranjeiro { 754a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 755230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 756230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 757fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 758230189d9SNélio Laranjeiro 759230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 760230189d9SNélio Laranjeiro mpw->pkts_n = 0; 761230189d9SNélio Laranjeiro mpw->len = length; 762230189d9SNélio Laranjeiro mpw->total_len = 0; 763fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 7646b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 7658688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 7668688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 7678688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 7688688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 7696b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 7706b30a6a8SShachar Beiser (txq->wqe_ci << 8) | 7716b30a6a8SShachar Beiser MLX5_OPCODE_TSO); 7728688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 7738688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 7748688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 7758688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 7768688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 7778688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 778230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 779230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 780230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 781230189d9SNélio Laranjeiro } 782230189d9SNélio Laranjeiro 783230189d9SNélio Laranjeiro /** 784230189d9SNélio Laranjeiro * Close a MPW session. 785230189d9SNélio Laranjeiro * 786230189d9SNélio Laranjeiro * @param txq 787230189d9SNélio Laranjeiro * Pointer to TX queue structure. 788230189d9SNélio Laranjeiro * @param mpw 789230189d9SNélio Laranjeiro * Pointer to MPW session structure. 790230189d9SNélio Laranjeiro */ 791230189d9SNélio Laranjeiro static inline void 792991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 793230189d9SNélio Laranjeiro { 794230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 795230189d9SNélio Laranjeiro 796230189d9SNélio Laranjeiro /* 797230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 798230189d9SNélio Laranjeiro * count as 2. 799230189d9SNélio Laranjeiro */ 8006b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num)); 801230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 802230189d9SNélio Laranjeiro if (num < 3) 803230189d9SNélio Laranjeiro ++txq->wqe_ci; 804230189d9SNélio Laranjeiro else 805230189d9SNélio Laranjeiro txq->wqe_ci += 2; 806fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 807fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 808230189d9SNélio Laranjeiro } 809230189d9SNélio Laranjeiro 810230189d9SNélio Laranjeiro /** 811230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 812230189d9SNélio Laranjeiro * 813230189d9SNélio Laranjeiro * @param dpdk_txq 814230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 815230189d9SNélio Laranjeiro * @param[in] pkts 816230189d9SNélio Laranjeiro * Packets to transmit. 817230189d9SNélio Laranjeiro * @param pkts_n 818230189d9SNélio Laranjeiro * Number of packets in array. 819230189d9SNélio Laranjeiro * 820230189d9SNélio Laranjeiro * @return 821230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 822230189d9SNélio Laranjeiro */ 823230189d9SNélio Laranjeiro uint16_t 824230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 825230189d9SNélio Laranjeiro { 826991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 827230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 8288c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 8298c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 830c3d62cc9SAdrien Mazarguil unsigned int i = 0; 831a5bf6af9SAdrien Mazarguil unsigned int j = 0; 8328c819a69SYongseok Koh uint16_t max_elts; 833f04f1d51SNélio Laranjeiro uint16_t max_wqe; 834230189d9SNélio Laranjeiro unsigned int comp; 835230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 836230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 837230189d9SNélio Laranjeiro }; 838230189d9SNélio Laranjeiro 839c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 840c3d62cc9SAdrien Mazarguil return 0; 841230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 842fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 843fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 844230189d9SNélio Laranjeiro /* Start processing. */ 8456cb559d6SYongseok Koh mlx5_tx_complete(txq); 8468c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 847f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 848f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 849f04f1d51SNélio Laranjeiro return 0; 850c3d62cc9SAdrien Mazarguil do { 851a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 852230189d9SNélio Laranjeiro uint32_t length; 853a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 854230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 855230189d9SNélio Laranjeiro 856c3d62cc9SAdrien Mazarguil /* 857c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 858c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 859c3d62cc9SAdrien Mazarguil */ 860a5bf6af9SAdrien Mazarguil assert(segs_n); 8618c819a69SYongseok Koh if (max_elts < segs_n) 862c3d62cc9SAdrien Mazarguil break; 863a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 86424c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 86524c14430SShahaf Shuler txq->stats.oerrors++; 866a5bf6af9SAdrien Mazarguil break; 86724c14430SShahaf Shuler } 8688c819a69SYongseok Koh max_elts -= segs_n; 869c3d62cc9SAdrien Mazarguil --pkts_n; 870230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 871230189d9SNélio Laranjeiro if (buf->ol_flags & 872230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 873230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 874a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 875a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 876a5bf6af9SAdrien Mazarguil assert(length); 877230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 878230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 879230189d9SNélio Laranjeiro ((mpw.len != length) || 880a5bf6af9SAdrien Mazarguil (segs_n != 1) || 8818688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 882230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 883230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 884f04f1d51SNélio Laranjeiro /* 885f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 886f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 887f04f1d51SNélio Laranjeiro * resources. 888f04f1d51SNélio Laranjeiro */ 889f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 890f04f1d51SNélio Laranjeiro break; 891f04f1d51SNélio Laranjeiro max_wqe -= 2; 892230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 8938688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 894230189d9SNélio Laranjeiro } 895a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 896a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 897a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 898a5bf6af9SAdrien Mazarguil length = 0; 899a5bf6af9SAdrien Mazarguil #endif 900a5bf6af9SAdrien Mazarguil do { 901a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 902a5bf6af9SAdrien Mazarguil uintptr_t addr; 903a5bf6af9SAdrien Mazarguil 904a5bf6af9SAdrien Mazarguil assert(buf); 9058c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 906230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 907a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 908230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 9096b30a6a8SShachar Beiser .byte_count = rte_cpu_to_be_32(DATA_LEN(buf)), 9106cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 9116b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 912230189d9SNélio Laranjeiro }; 913a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 914a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 915a5bf6af9SAdrien Mazarguil #endif 916a5bf6af9SAdrien Mazarguil buf = buf->next; 917230189d9SNélio Laranjeiro ++mpw.pkts_n; 918a5bf6af9SAdrien Mazarguil ++j; 919a5bf6af9SAdrien Mazarguil } while (--segs_n); 920a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 921230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 922230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 923230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 924230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 925230189d9SNélio Laranjeiro txq->stats.obytes += length; 926230189d9SNélio Laranjeiro #endif 927c3d62cc9SAdrien Mazarguil ++i; 928c3d62cc9SAdrien Mazarguil } while (pkts_n); 929230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 930230189d9SNélio Laranjeiro if (unlikely(i == 0)) 931230189d9SNélio Laranjeiro return 0; 932230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 933a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 934a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 935230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 9368688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 937230189d9SNélio Laranjeiro 938230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 9396b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 940230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 9418688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 942230189d9SNélio Laranjeiro txq->elts_comp = 0; 943230189d9SNélio Laranjeiro } else { 944230189d9SNélio Laranjeiro txq->elts_comp = comp; 945230189d9SNélio Laranjeiro } 946230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 947230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 948230189d9SNélio Laranjeiro txq->stats.opackets += i; 949230189d9SNélio Laranjeiro #endif 950230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 951230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 952230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 95330807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 954230189d9SNélio Laranjeiro txq->elts_head = elts_head; 955230189d9SNélio Laranjeiro return i; 956230189d9SNélio Laranjeiro } 957230189d9SNélio Laranjeiro 958230189d9SNélio Laranjeiro /** 959230189d9SNélio Laranjeiro * Open a MPW inline session. 960230189d9SNélio Laranjeiro * 961230189d9SNélio Laranjeiro * @param txq 962230189d9SNélio Laranjeiro * Pointer to TX queue structure. 963230189d9SNélio Laranjeiro * @param mpw 964230189d9SNélio Laranjeiro * Pointer to MPW session structure. 965230189d9SNélio Laranjeiro * @param length 966230189d9SNélio Laranjeiro * Packet length. 967230189d9SNélio Laranjeiro */ 968230189d9SNélio Laranjeiro static inline void 969991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, 970991b04f6SNélio Laranjeiro uint32_t length) 971230189d9SNélio Laranjeiro { 972a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 9738688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 974230189d9SNélio Laranjeiro 975230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 976230189d9SNélio Laranjeiro mpw->pkts_n = 0; 977230189d9SNélio Laranjeiro mpw->len = length; 978230189d9SNélio Laranjeiro mpw->total_len = 0; 979fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 9806b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 981230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 982c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 9838688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 9848688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 9856b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 9868688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 9878688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 9888688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 9898688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 9908688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 9918688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 9928688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 9938688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 994230189d9SNélio Laranjeiro } 995230189d9SNélio Laranjeiro 996230189d9SNélio Laranjeiro /** 997230189d9SNélio Laranjeiro * Close a MPW inline session. 998230189d9SNélio Laranjeiro * 999230189d9SNélio Laranjeiro * @param txq 1000230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1001230189d9SNélio Laranjeiro * @param mpw 1002230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1003230189d9SNélio Laranjeiro */ 1004230189d9SNélio Laranjeiro static inline void 1005991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 1006230189d9SNélio Laranjeiro { 1007230189d9SNélio Laranjeiro unsigned int size; 10088688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 10098688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 1010230189d9SNélio Laranjeiro 10118688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 1012230189d9SNélio Laranjeiro /* 1013230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1014230189d9SNélio Laranjeiro * count as 2. 1015230189d9SNélio Laranjeiro */ 10166b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 10176b30a6a8SShachar Beiser MLX5_WQE_DS(size)); 1018230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 10196b30a6a8SShachar Beiser inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG); 10208688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1021230189d9SNélio Laranjeiro } 1022230189d9SNélio Laranjeiro 1023230189d9SNélio Laranjeiro /** 1024230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1025230189d9SNélio Laranjeiro * 1026230189d9SNélio Laranjeiro * @param dpdk_txq 1027230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1028230189d9SNélio Laranjeiro * @param[in] pkts 1029230189d9SNélio Laranjeiro * Packets to transmit. 1030230189d9SNélio Laranjeiro * @param pkts_n 1031230189d9SNélio Laranjeiro * Number of packets in array. 1032230189d9SNélio Laranjeiro * 1033230189d9SNélio Laranjeiro * @return 1034230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1035230189d9SNélio Laranjeiro */ 1036230189d9SNélio Laranjeiro uint16_t 1037230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1038230189d9SNélio Laranjeiro uint16_t pkts_n) 1039230189d9SNélio Laranjeiro { 1040991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 1041230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 10428c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 10438c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 1044c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1045a5bf6af9SAdrien Mazarguil unsigned int j = 0; 10468c819a69SYongseok Koh uint16_t max_elts; 1047f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1048230189d9SNélio Laranjeiro unsigned int comp; 10490e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1050230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1051230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1052230189d9SNélio Laranjeiro }; 1053f04f1d51SNélio Laranjeiro /* 1054f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1055f04f1d51SNélio Laranjeiro * code. 1056f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1057f04f1d51SNélio Laranjeiro * - 1 control segment, 1058f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1059f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1060f04f1d51SNélio Laranjeiro */ 1061f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1062f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1063f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1064f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1065230189d9SNélio Laranjeiro 1066c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1067c3d62cc9SAdrien Mazarguil return 0; 1068230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1069fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1070fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1071230189d9SNélio Laranjeiro /* Start processing. */ 10726cb559d6SYongseok Koh mlx5_tx_complete(txq); 10738c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 1074c3d62cc9SAdrien Mazarguil do { 1075a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1076230189d9SNélio Laranjeiro uintptr_t addr; 1077230189d9SNélio Laranjeiro uint32_t length; 1078a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 1079230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 1080230189d9SNélio Laranjeiro 1081c3d62cc9SAdrien Mazarguil /* 1082c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1083c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1084c3d62cc9SAdrien Mazarguil */ 1085a5bf6af9SAdrien Mazarguil assert(segs_n); 10868c819a69SYongseok Koh if (max_elts < segs_n) 1087c3d62cc9SAdrien Mazarguil break; 1088a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 108924c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 109024c14430SShahaf Shuler txq->stats.oerrors++; 1091a5bf6af9SAdrien Mazarguil break; 109224c14430SShahaf Shuler } 10938c819a69SYongseok Koh max_elts -= segs_n; 1094c3d62cc9SAdrien Mazarguil --pkts_n; 1095f04f1d51SNélio Laranjeiro /* 1096f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1097f04f1d51SNélio Laranjeiro * iteration. 1098f04f1d51SNélio Laranjeiro */ 1099f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 1100230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 1101230189d9SNélio Laranjeiro if (buf->ol_flags & 1102230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 1103230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 1104a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1105a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1106230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1107230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1108230189d9SNélio Laranjeiro if ((mpw.len != length) || 1109a5bf6af9SAdrien Mazarguil (segs_n != 1) || 11108688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1111230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1112230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1113230189d9SNélio Laranjeiro if ((mpw.len != length) || 1114a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1115230189d9SNélio Laranjeiro (length > inline_room) || 11168688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1117230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 11180e8679fcSNélio Laranjeiro inline_room = 11190e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1120230189d9SNélio Laranjeiro } 1121230189d9SNélio Laranjeiro } 1122230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1123a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1124a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1125f04f1d51SNélio Laranjeiro /* 1126f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1127f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1128f04f1d51SNélio Laranjeiro * such resources. 1129f04f1d51SNélio Laranjeiro */ 1130f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1131f04f1d51SNélio Laranjeiro break; 1132f04f1d51SNélio Laranjeiro max_wqe -= 2; 1133230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 11348688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1135230189d9SNélio Laranjeiro } else { 1136f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1137f04f1d51SNélio Laranjeiro break; 1138f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1139230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 11408688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1141230189d9SNélio Laranjeiro } 1142230189d9SNélio Laranjeiro } 1143a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1144a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1145230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 11460e8679fcSNélio Laranjeiro assert(inline_room == 11470e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1148a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1149a5bf6af9SAdrien Mazarguil length = 0; 1150a5bf6af9SAdrien Mazarguil #endif 1151a5bf6af9SAdrien Mazarguil do { 1152230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1153230189d9SNélio Laranjeiro 1154a5bf6af9SAdrien Mazarguil assert(buf); 11558c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1156230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1157a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1158230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 11596b30a6a8SShachar Beiser .byte_count = 11606b30a6a8SShachar Beiser rte_cpu_to_be_32(DATA_LEN(buf)), 11616cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 11626b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 1163230189d9SNélio Laranjeiro }; 1164a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1165a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1166a5bf6af9SAdrien Mazarguil #endif 1167a5bf6af9SAdrien Mazarguil buf = buf->next; 1168230189d9SNélio Laranjeiro ++mpw.pkts_n; 1169a5bf6af9SAdrien Mazarguil ++j; 1170a5bf6af9SAdrien Mazarguil } while (--segs_n); 1171a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1172230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1173230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1174230189d9SNélio Laranjeiro } else { 1175230189d9SNélio Laranjeiro unsigned int max; 1176230189d9SNélio Laranjeiro 1177230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1178230189d9SNélio Laranjeiro assert(length <= inline_room); 1179a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1180a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 11818c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1182230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1183fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1184fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1185fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1186230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1187230189d9SNélio Laranjeiro if (length > max) { 1188230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1189230189d9SNélio Laranjeiro (void *)addr, 1190230189d9SNélio Laranjeiro max); 1191fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1192230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1193230189d9SNélio Laranjeiro (void *)(addr + max), 1194230189d9SNélio Laranjeiro length - max); 1195230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1196230189d9SNélio Laranjeiro } else { 1197230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1198230189d9SNélio Laranjeiro (void *)addr, 1199230189d9SNélio Laranjeiro length); 120016c64768SYongseok Koh 120116c64768SYongseok Koh if (length == max) 120216c64768SYongseok Koh mpw.data.raw = 120316c64768SYongseok Koh (volatile void *)txq->wqes; 120416c64768SYongseok Koh else 1205230189d9SNélio Laranjeiro mpw.data.raw += length; 1206230189d9SNélio Laranjeiro } 1207230189d9SNélio Laranjeiro ++mpw.pkts_n; 120876bf1574SYongseok Koh mpw.total_len += length; 1209a5bf6af9SAdrien Mazarguil ++j; 1210230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1211230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 12120e8679fcSNélio Laranjeiro inline_room = 12130e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1214230189d9SNélio Laranjeiro } else { 1215230189d9SNélio Laranjeiro inline_room -= length; 1216230189d9SNélio Laranjeiro } 1217230189d9SNélio Laranjeiro } 1218230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1219230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1220230189d9SNélio Laranjeiro txq->stats.obytes += length; 1221230189d9SNélio Laranjeiro #endif 1222c3d62cc9SAdrien Mazarguil ++i; 1223c3d62cc9SAdrien Mazarguil } while (pkts_n); 1224230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1225230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1226230189d9SNélio Laranjeiro return 0; 1227230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1228a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1229a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1230230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 12318688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1232230189d9SNélio Laranjeiro 1233230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 12346b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 1235230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 12368688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1237230189d9SNélio Laranjeiro txq->elts_comp = 0; 1238230189d9SNélio Laranjeiro } else { 1239230189d9SNélio Laranjeiro txq->elts_comp = comp; 1240230189d9SNélio Laranjeiro } 1241230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1242230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1243230189d9SNélio Laranjeiro txq->stats.opackets += i; 1244230189d9SNélio Laranjeiro #endif 1245230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1246230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1247230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1248230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1249230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 125030807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1251230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1252230189d9SNélio Laranjeiro return i; 1253230189d9SNélio Laranjeiro } 1254230189d9SNélio Laranjeiro 1255230189d9SNélio Laranjeiro /** 12566ce84bd8SYongseok Koh * Open an Enhanced MPW session. 12576ce84bd8SYongseok Koh * 12586ce84bd8SYongseok Koh * @param txq 12596ce84bd8SYongseok Koh * Pointer to TX queue structure. 12606ce84bd8SYongseok Koh * @param mpw 12616ce84bd8SYongseok Koh * Pointer to MPW session structure. 12626ce84bd8SYongseok Koh * @param length 12636ce84bd8SYongseok Koh * Packet length. 12646ce84bd8SYongseok Koh */ 12656ce84bd8SYongseok Koh static inline void 1266991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding) 12676ce84bd8SYongseok Koh { 12686ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 12696ce84bd8SYongseok Koh 12706ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 12716ce84bd8SYongseok Koh mpw->pkts_n = 0; 12726ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 12736ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 12746b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = 12756b30a6a8SShachar Beiser rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 12766ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 12776ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 12786ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 12796ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 12806ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 12816ce84bd8SYongseok Koh if (unlikely(padding)) { 12826ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 12836ce84bd8SYongseok Koh 12846ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 12856b30a6a8SShachar Beiser *(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG); 12866ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 12876b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_INLINE_SEG); 12886ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 12896ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 12906ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 12916ce84bd8SYongseok Koh } else { 12926ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 12936ce84bd8SYongseok Koh } 12946ce84bd8SYongseok Koh } 12956ce84bd8SYongseok Koh 12966ce84bd8SYongseok Koh /** 12976ce84bd8SYongseok Koh * Close an Enhanced MPW session. 12986ce84bd8SYongseok Koh * 12996ce84bd8SYongseok Koh * @param txq 13006ce84bd8SYongseok Koh * Pointer to TX queue structure. 13016ce84bd8SYongseok Koh * @param mpw 13026ce84bd8SYongseok Koh * Pointer to MPW session structure. 13036ce84bd8SYongseok Koh * 13046ce84bd8SYongseok Koh * @return 13056ce84bd8SYongseok Koh * Number of consumed WQEs. 13066ce84bd8SYongseok Koh */ 13076ce84bd8SYongseok Koh static inline uint16_t 1308991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 13096ce84bd8SYongseok Koh { 13106ce84bd8SYongseok Koh uint16_t ret; 13116ce84bd8SYongseok Koh 13126ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 13136ce84bd8SYongseok Koh * count as 2. 13146ce84bd8SYongseok Koh */ 13156b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 13166b30a6a8SShachar Beiser MLX5_WQE_DS(mpw->total_len)); 13176ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 13186ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 13196ce84bd8SYongseok Koh txq->wqe_ci += ret; 13206ce84bd8SYongseok Koh return ret; 13216ce84bd8SYongseok Koh } 13226ce84bd8SYongseok Koh 13236ce84bd8SYongseok Koh /** 13246ce84bd8SYongseok Koh * DPDK callback for TX with Enhanced MPW support. 13256ce84bd8SYongseok Koh * 13266ce84bd8SYongseok Koh * @param dpdk_txq 13276ce84bd8SYongseok Koh * Generic pointer to TX queue structure. 13286ce84bd8SYongseok Koh * @param[in] pkts 13296ce84bd8SYongseok Koh * Packets to transmit. 13306ce84bd8SYongseok Koh * @param pkts_n 13316ce84bd8SYongseok Koh * Number of packets in array. 13326ce84bd8SYongseok Koh * 13336ce84bd8SYongseok Koh * @return 13346ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 13356ce84bd8SYongseok Koh */ 13366ce84bd8SYongseok Koh uint16_t 13376ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 13386ce84bd8SYongseok Koh { 1339991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 13406ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 13418c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 13428c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 13436ce84bd8SYongseok Koh unsigned int i = 0; 13446ce84bd8SYongseok Koh unsigned int j = 0; 13458c819a69SYongseok Koh uint16_t max_elts; 13466ce84bd8SYongseok Koh uint16_t max_wqe; 13476ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 13486ce84bd8SYongseok Koh unsigned int mpw_room = 0; 13496ce84bd8SYongseok Koh unsigned int inl_pad = 0; 13506ce84bd8SYongseok Koh uint32_t inl_hdr; 13516ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 13526ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 13536ce84bd8SYongseok Koh }; 13546ce84bd8SYongseok Koh 13556ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 13566ce84bd8SYongseok Koh return 0; 13576ce84bd8SYongseok Koh /* Start processing. */ 13586cb559d6SYongseok Koh mlx5_tx_complete(txq); 13596ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 13606ce84bd8SYongseok Koh /* A CQE slot must always be available. */ 13616ce84bd8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 13626ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 13636ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 13646ce84bd8SYongseok Koh return 0; 13656ce84bd8SYongseok Koh do { 13666ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 13676ce84bd8SYongseok Koh uintptr_t addr; 13686ce84bd8SYongseok Koh uint64_t naddr; 13696ce84bd8SYongseok Koh unsigned int n; 13706ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 13716ce84bd8SYongseok Koh uint32_t length; 13726ce84bd8SYongseok Koh unsigned int segs_n = buf->nb_segs; 13736ce84bd8SYongseok Koh uint32_t cs_flags = 0; 13746ce84bd8SYongseok Koh 13756ce84bd8SYongseok Koh /* 13766ce84bd8SYongseok Koh * Make sure there is enough room to store this packet and 13776ce84bd8SYongseok Koh * that one ring entry remains unused. 13786ce84bd8SYongseok Koh */ 13796ce84bd8SYongseok Koh assert(segs_n); 13808c819a69SYongseok Koh if (max_elts - j < segs_n) 13816ce84bd8SYongseok Koh break; 13826ce84bd8SYongseok Koh /* Do not bother with large packets MPW cannot handle. */ 138324c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 138424c14430SShahaf Shuler txq->stats.oerrors++; 13856ce84bd8SYongseok Koh break; 138624c14430SShahaf Shuler } 13876ce84bd8SYongseok Koh /* Should we enable HW CKSUM offload. */ 13886ce84bd8SYongseok Koh if (buf->ol_flags & 13896ce84bd8SYongseok Koh (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 13906ce84bd8SYongseok Koh cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 13916ce84bd8SYongseok Koh /* Retrieve packet information. */ 13926ce84bd8SYongseok Koh length = PKT_LEN(buf); 13936ce84bd8SYongseok Koh /* Start new session if: 13946ce84bd8SYongseok Koh * - multi-segment packet 13956ce84bd8SYongseok Koh * - no space left even for a dseg 13966ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 13976ce84bd8SYongseok Koh * - cs_flag differs 13986ce84bd8SYongseok Koh * It can't be MLX5_MPW_STATE_OPENED as always have a single 13996ce84bd8SYongseok Koh * segmented packet. 14006ce84bd8SYongseok Koh */ 14016ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 14026ce84bd8SYongseok Koh if ((segs_n != 1) || 14036ce84bd8SYongseok Koh (inl_pad + sizeof(struct mlx5_wqe_data_seg) > 14046ce84bd8SYongseok Koh mpw_room) || 14056ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 14066ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 14076ce84bd8SYongseok Koh mpw_room) || 14086ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 14096ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 14106ce84bd8SYongseok Koh } 14116ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 14126ce84bd8SYongseok Koh if (unlikely(segs_n != 1)) { 14136ce84bd8SYongseok Koh /* Fall back to legacy MPW. 14146ce84bd8SYongseok Koh * A MPW session consumes 2 WQEs at most to 14156ce84bd8SYongseok Koh * include MLX5_MPW_DSEG_MAX pointers. 14166ce84bd8SYongseok Koh */ 14176ce84bd8SYongseok Koh if (unlikely(max_wqe < 2)) 14186ce84bd8SYongseok Koh break; 14196ce84bd8SYongseok Koh mlx5_mpw_new(txq, &mpw, length); 14206ce84bd8SYongseok Koh } else { 14216ce84bd8SYongseok Koh /* In Enhanced MPW, inline as much as the budget 14226ce84bd8SYongseok Koh * is allowed. The remaining space is to be 14236ce84bd8SYongseok Koh * filled with dsegs. If the title WQEBB isn't 14246ce84bd8SYongseok Koh * padded, it will have 2 dsegs there. 14256ce84bd8SYongseok Koh */ 14266ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 14276ce84bd8SYongseok Koh (max_inline ? max_inline : 14286ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 14296ce84bd8SYongseok Koh MLX5_WQE_SIZE); 14306ce84bd8SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < 14316ce84bd8SYongseok Koh mpw_room)) 14326ce84bd8SYongseok Koh break; 14336ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 14346ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 14356ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 14366ce84bd8SYongseok Koh inl_pad = 0; 14376ce84bd8SYongseok Koh do_inline = 14386ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 14396ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 14406ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 14416ce84bd8SYongseok Koh } 14426ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 14436ce84bd8SYongseok Koh } else { 14446ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 14456ce84bd8SYongseok Koh * Inlininig is possible when: 14466ce84bd8SYongseok Koh * - length is less than configured value 14476ce84bd8SYongseok Koh * - length fits for remaining space 14486ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 14496ce84bd8SYongseok Koh */ 14506ce84bd8SYongseok Koh do_inline = 14516ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 14526ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 14536ce84bd8SYongseok Koh mpw_room && 14546ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 14556ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 14566ce84bd8SYongseok Koh } 14576ce84bd8SYongseok Koh /* Multi-segment packets must be alone in their MPW. */ 14586ce84bd8SYongseok Koh assert((segs_n == 1) || (mpw.pkts_n == 0)); 14596ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) { 14606ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 14616ce84bd8SYongseok Koh length = 0; 14626ce84bd8SYongseok Koh #endif 14636ce84bd8SYongseok Koh do { 14646ce84bd8SYongseok Koh volatile struct mlx5_wqe_data_seg *dseg; 14656ce84bd8SYongseok Koh 14666ce84bd8SYongseok Koh assert(buf); 14678c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 14686ce84bd8SYongseok Koh dseg = mpw.data.dseg[mpw.pkts_n]; 14696ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14706ce84bd8SYongseok Koh *dseg = (struct mlx5_wqe_data_seg){ 14716b30a6a8SShachar Beiser .byte_count = rte_cpu_to_be_32( 14726b30a6a8SShachar Beiser DATA_LEN(buf)), 14736cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 14746b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 14756ce84bd8SYongseok Koh }; 14766ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 14776ce84bd8SYongseok Koh length += DATA_LEN(buf); 14786ce84bd8SYongseok Koh #endif 14796ce84bd8SYongseok Koh buf = buf->next; 14806ce84bd8SYongseok Koh ++j; 14816ce84bd8SYongseok Koh ++mpw.pkts_n; 14826ce84bd8SYongseok Koh } while (--segs_n); 14836ce84bd8SYongseok Koh /* A multi-segmented packet takes one MPW session. 14846ce84bd8SYongseok Koh * TODO: Pack more multi-segmented packets if possible. 14856ce84bd8SYongseok Koh */ 14866ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 14876ce84bd8SYongseok Koh if (mpw.pkts_n < 3) 14886ce84bd8SYongseok Koh max_wqe--; 14896ce84bd8SYongseok Koh else 14906ce84bd8SYongseok Koh max_wqe -= 2; 14916ce84bd8SYongseok Koh } else if (do_inline) { 14926ce84bd8SYongseok Koh /* Inline packet into WQE. */ 14936ce84bd8SYongseok Koh unsigned int max; 14946ce84bd8SYongseok Koh 14956ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14966ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14976b30a6a8SShachar Beiser inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG); 14986ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14996ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 15006ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 15016ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 15026ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 15036ce84bd8SYongseok Koh /* Copy inline header. */ 15046ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 15056ce84bd8SYongseok Koh mlx5_copy_to_wq( 15066ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 15076ce84bd8SYongseok Koh &inl_hdr, 15086ce84bd8SYongseok Koh sizeof(inl_hdr), 15096ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 15106ce84bd8SYongseok Koh max); 15116ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 15126ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 15136ce84bd8SYongseok Koh /* Copy packet data. */ 15146ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 15156ce84bd8SYongseok Koh mlx5_copy_to_wq( 15166ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 15176ce84bd8SYongseok Koh (void *)addr, 15186ce84bd8SYongseok Koh length, 15196ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 15206ce84bd8SYongseok Koh max); 15216ce84bd8SYongseok Koh ++mpw.pkts_n; 15226ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 15236ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 15246ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 15256ce84bd8SYongseok Koh */ 15266ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 15276ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 15286ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 15296ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 15306ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 15316ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 15326ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 15336ce84bd8SYongseok Koh } else { 15346ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 15356ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 15366ce84bd8SYongseok Koh 15376ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 15386ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 15396ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 15406ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 15416ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 15426ce84bd8SYongseok Koh + inl_pad))) 15436ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 15446ce84bd8SYongseok Koh else 15456ce84bd8SYongseok Koh dseg = (volatile void *) 15466ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 15476ce84bd8SYongseok Koh inl_pad); 15488c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 15496ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 15506ce84bd8SYongseok Koh for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++) 15516ce84bd8SYongseok Koh rte_prefetch2((void *)(addr + 15526ce84bd8SYongseok Koh n * RTE_CACHE_LINE_SIZE)); 15536b30a6a8SShachar Beiser naddr = rte_cpu_to_be_64(addr); 15546ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 15556b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 15566cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 15576ce84bd8SYongseok Koh naddr, 15586ce84bd8SYongseok Koh naddr >> 32, 15596ce84bd8SYongseok Koh }; 15606ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 15616ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 15626ce84bd8SYongseok Koh ++j; 15636ce84bd8SYongseok Koh ++mpw.pkts_n; 15646ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 15656ce84bd8SYongseok Koh inl_pad = 0; 15666ce84bd8SYongseok Koh } 15676ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 15686ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 15696ce84bd8SYongseok Koh txq->stats.obytes += length; 15706ce84bd8SYongseok Koh #endif 15716ce84bd8SYongseok Koh ++i; 15726ce84bd8SYongseok Koh } while (i < pkts_n); 15736ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 15746ce84bd8SYongseok Koh if (unlikely(i == 0)) 15756ce84bd8SYongseok Koh return 0; 15766ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 15776ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 15786ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 15796ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 15806ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 15816ce84bd8SYongseok Koh 15826ce84bd8SYongseok Koh /* Request completion on last WQE. */ 15836b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 15846ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 15856ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 15866ce84bd8SYongseok Koh txq->elts_comp = 0; 15876ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 15886ce84bd8SYongseok Koh txq->cq_pi++; 15896ce84bd8SYongseok Koh } else { 15906ce84bd8SYongseok Koh txq->elts_comp += j; 15916ce84bd8SYongseok Koh } 15926ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 15936ce84bd8SYongseok Koh /* Increment sent packets counter. */ 15946ce84bd8SYongseok Koh txq->stats.opackets += i; 15956ce84bd8SYongseok Koh #endif 15966ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 15976ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 15986ce84bd8SYongseok Koh else if (mpw.state == MLX5_MPW_STATE_OPENED) 15996ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 16006ce84bd8SYongseok Koh /* Ring QP doorbell. */ 16016ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 16026ce84bd8SYongseok Koh txq->elts_head = elts_head; 16036ce84bd8SYongseok Koh return i; 16046ce84bd8SYongseok Koh } 16056ce84bd8SYongseok Koh 16066ce84bd8SYongseok Koh /** 160767fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 160867fa62bcSAdrien Mazarguil * 16096218063bSNélio Laranjeiro * @param[in] cqe 16106218063bSNélio Laranjeiro * Pointer to CQE. 161167fa62bcSAdrien Mazarguil * 161278a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 161378a38edfSJianfeng Tan * 161467fa62bcSAdrien Mazarguil * @return 161567fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 161667fa62bcSAdrien Mazarguil */ 161767fa62bcSAdrien Mazarguil static inline uint32_t 161897267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 161967fa62bcSAdrien Mazarguil { 1620ea16068cSYongseok Koh uint8_t idx; 1621ea16068cSYongseok Koh uint8_t pinfo = cqe->pkt_info; 1622ea16068cSYongseok Koh uint16_t ptype = cqe->hdr_type_etc; 162367fa62bcSAdrien Mazarguil 1624ea16068cSYongseok Koh /* 1625ea16068cSYongseok Koh * The index to the array should have: 1626ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 1627ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 1628ea16068cSYongseok Koh * bit[5] = ip_frag 1629ea16068cSYongseok Koh * bit[6] = tunneled 1630ea16068cSYongseok Koh * bit[7] = outer_l3_type 1631ea16068cSYongseok Koh */ 1632ea16068cSYongseok Koh idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10); 1633ea16068cSYongseok Koh return mlx5_ptype_table[idx]; 163467fa62bcSAdrien Mazarguil } 163567fa62bcSAdrien Mazarguil 163667fa62bcSAdrien Mazarguil /** 163799c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 163899c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 163999c12dccSNélio Laranjeiro * been processed. 164099c12dccSNélio Laranjeiro * 164199c12dccSNélio Laranjeiro * @param rxq 164299c12dccSNélio Laranjeiro * Pointer to RX queue. 164399c12dccSNélio Laranjeiro * @param cqe 164499c12dccSNélio Laranjeiro * CQE to process. 1645ecf60761SNélio Laranjeiro * @param[out] rss_hash 1646ecf60761SNélio Laranjeiro * Packet RSS Hash result. 164799c12dccSNélio Laranjeiro * 164899c12dccSNélio Laranjeiro * @return 164999c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 165099c12dccSNélio Laranjeiro * with error. 165199c12dccSNélio Laranjeiro */ 165299c12dccSNélio Laranjeiro static inline int 165378142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 1654ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 165599c12dccSNélio Laranjeiro { 165699c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 165799c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 165899c12dccSNélio Laranjeiro int len = 0; 1659d2e842d0SYongseok Koh uint16_t idx, end; 166099c12dccSNélio Laranjeiro 166199c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 166299c12dccSNélio Laranjeiro if (zip->ai) { 166399c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 166499c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 16654aff4bcbSYongseok Koh (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info); 166699c12dccSNélio Laranjeiro 16676b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt); 16686b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result); 166999c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1670d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1671d2e842d0SYongseok Koh idx = zip->ca; 1672d2e842d0SYongseok Koh end = zip->na; 1673d2e842d0SYongseok Koh while (idx != end) { 1674d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1675d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1676d2e842d0SYongseok Koh ++idx; 1677d2e842d0SYongseok Koh } 167899c12dccSNélio Laranjeiro /* 167999c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 168099c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 168199c12dccSNélio Laranjeiro * ring for software use. 168299c12dccSNélio Laranjeiro */ 168399c12dccSNélio Laranjeiro zip->ca = zip->na; 168499c12dccSNélio Laranjeiro zip->na += 8; 168599c12dccSNélio Laranjeiro } 168699c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1687d2e842d0SYongseok Koh /* Invalidate the rest */ 1688d2e842d0SYongseok Koh idx = zip->ca; 1689d2e842d0SYongseok Koh end = zip->cq_ci; 169099c12dccSNélio Laranjeiro 169199c12dccSNélio Laranjeiro while (idx != end) { 169297267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 169399c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 169499c12dccSNélio Laranjeiro ++idx; 169599c12dccSNélio Laranjeiro } 169699c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 169799c12dccSNélio Laranjeiro zip->ai = 0; 169899c12dccSNélio Laranjeiro } 169999c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 170099c12dccSNélio Laranjeiro } else { 170199c12dccSNélio Laranjeiro int ret; 170299c12dccSNélio Laranjeiro int8_t op_own; 170399c12dccSNélio Laranjeiro 170497267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 170599c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 170699c12dccSNélio Laranjeiro return 0; 170799c12dccSNélio Laranjeiro ++rxq->cq_ci; 170899c12dccSNélio Laranjeiro op_own = cqe->op_own; 170999c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 171099c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 171199c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 171299c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 17134aff4bcbSYongseok Koh cqe_cnt].pkt_info); 171499c12dccSNélio Laranjeiro 171599c12dccSNélio Laranjeiro /* Fix endianness. */ 17166b30a6a8SShachar Beiser zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt); 171799c12dccSNélio Laranjeiro /* 171899c12dccSNélio Laranjeiro * Current mini array position is the one returned by 171999c12dccSNélio Laranjeiro * check_cqe64(). 172099c12dccSNélio Laranjeiro * 172199c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 172299c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 172399c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 172499c12dccSNélio Laranjeiro */ 1725d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 172699c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 172799c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 172899c12dccSNélio Laranjeiro --rxq->cq_ci; 172999c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 173099c12dccSNélio Laranjeiro /* Get packet size to return. */ 17316b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[0].byte_cnt); 17326b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result); 173399c12dccSNélio Laranjeiro zip->ai = 1; 1734d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1735d2e842d0SYongseok Koh idx = zip->ca; 1736d2e842d0SYongseok Koh end = zip->cq_ci; 1737d2e842d0SYongseok Koh while (idx != end) { 1738d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1739d2e842d0SYongseok Koh ++idx; 1740d2e842d0SYongseok Koh } 174199c12dccSNélio Laranjeiro } else { 17426b30a6a8SShachar Beiser len = rte_be_to_cpu_32(cqe->byte_cnt); 17436b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res); 174499c12dccSNélio Laranjeiro } 174599c12dccSNélio Laranjeiro /* Error while receiving packet. */ 174699c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 174799c12dccSNélio Laranjeiro return -1; 174899c12dccSNélio Laranjeiro } 174999c12dccSNélio Laranjeiro return len; 175099c12dccSNélio Laranjeiro } 175199c12dccSNélio Laranjeiro 175299c12dccSNélio Laranjeiro /** 175367fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 175467fa62bcSAdrien Mazarguil * 175567fa62bcSAdrien Mazarguil * @param[in] rxq 175667fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 17576218063bSNélio Laranjeiro * @param[in] cqe 17586218063bSNélio Laranjeiro * Pointer to CQE. 175967fa62bcSAdrien Mazarguil * 176067fa62bcSAdrien Mazarguil * @return 176167fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 176267fa62bcSAdrien Mazarguil */ 176367fa62bcSAdrien Mazarguil static inline uint32_t 176478142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe) 176567fa62bcSAdrien Mazarguil { 176667fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 17676b30a6a8SShachar Beiser uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 176867fa62bcSAdrien Mazarguil 17690603df73SNélio Laranjeiro ol_flags = 17700603df73SNélio Laranjeiro TRANSPOSE(flags, 17710603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 17720603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17730603df73SNélio Laranjeiro TRANSPOSE(flags, 17740603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 177583e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 177697267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 177767fa62bcSAdrien Mazarguil ol_flags |= 17780603df73SNélio Laranjeiro TRANSPOSE(flags, 17790603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 178083e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17810603df73SNélio Laranjeiro TRANSPOSE(flags, 17820603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 178383e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 178467fa62bcSAdrien Mazarguil return ol_flags; 178567fa62bcSAdrien Mazarguil } 178667fa62bcSAdrien Mazarguil 178767fa62bcSAdrien Mazarguil /** 17882e22920bSAdrien Mazarguil * DPDK callback for RX. 17892e22920bSAdrien Mazarguil * 17902e22920bSAdrien Mazarguil * @param dpdk_rxq 17912e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 17922e22920bSAdrien Mazarguil * @param[out] pkts 17932e22920bSAdrien Mazarguil * Array to store received packets. 17942e22920bSAdrien Mazarguil * @param pkts_n 17952e22920bSAdrien Mazarguil * Maximum number of packets in array. 17962e22920bSAdrien Mazarguil * 17972e22920bSAdrien Mazarguil * @return 17982e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 17992e22920bSAdrien Mazarguil */ 18002e22920bSAdrien Mazarguil uint16_t 18012e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 18022e22920bSAdrien Mazarguil { 180378142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = dpdk_rxq; 1804b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1805e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 18069964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 18079964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 18089964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 180997267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 181097267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 18119964b965SNélio Laranjeiro unsigned int i = 0; 18129964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 18134e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 18142e22920bSAdrien Mazarguil 18159964b965SNélio Laranjeiro while (pkts_n) { 18169964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 18179964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 18189964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1819ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 18209964b965SNélio Laranjeiro 18219964b965SNélio Laranjeiro if (pkt) 18229964b965SNélio Laranjeiro NEXT(seg) = rep; 18239964b965SNélio Laranjeiro seg = rep; 18249964b965SNélio Laranjeiro rte_prefetch0(seg); 18256218063bSNélio Laranjeiro rte_prefetch0(cqe); 18269964b965SNélio Laranjeiro rte_prefetch0(wqe); 1827fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 18282e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 182915a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 183015a756b6SSagi Grimberg if (!pkt) { 183115a756b6SSagi Grimberg /* 183215a756b6SSagi Grimberg * no buffers before we even started, 183315a756b6SSagi Grimberg * bail out silently. 183415a756b6SSagi Grimberg */ 183515a756b6SSagi Grimberg break; 183615a756b6SSagi Grimberg } 1837a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1838a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1839fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 18408f094a9aSOlivier Matz NEXT(pkt) = NULL; 18418f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 18421f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 1843fe5fe382SNélio Laranjeiro pkt = rep; 18449964b965SNélio Laranjeiro } 18456218063bSNélio Laranjeiro break; 18462e22920bSAdrien Mazarguil } 18479964b965SNélio Laranjeiro if (!pkt) { 184897267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1849ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1850ecf60761SNélio Laranjeiro &rss_hash_res); 1851ecf60761SNélio Laranjeiro if (!len) { 18521f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 18536218063bSNélio Laranjeiro break; 18546218063bSNélio Laranjeiro } 185599c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 185699c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 18571f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 185899c12dccSNélio Laranjeiro ++rxq->stats.idropped; 185999c12dccSNélio Laranjeiro goto skip; 186099c12dccSNélio Laranjeiro } 18619964b965SNélio Laranjeiro pkt = seg; 18629964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 18639964b965SNélio Laranjeiro /* Update packet information. */ 186448dfc20fSYongseok Koh pkt->packet_type = rxq_cq_to_pkt_type(cqe); 18650ac64846SMaxime Leroy pkt->ol_flags = 0; 186636ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1867ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1868ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1869ecf60761SNélio Laranjeiro } 1870c604f619SNélio Laranjeiro if (rxq->mark && 1871c604f619SNélio Laranjeiro MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 1872b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 1873b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 18746b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) { 1875b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 1876b268a3eeSNélio Laranjeiro 1877b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 1878ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1879b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 1880b268a3eeSNélio Laranjeiro } 1881ea3bc3b1SNélio Laranjeiro } 188248dfc20fSYongseok Koh if (rxq->csum | rxq->csum_l2tun) 18836703d836SNélio Laranjeiro pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe); 18846703d836SNélio Laranjeiro if (rxq->vlan_strip && 18856703d836SNélio Laranjeiro (cqe->hdr_type_etc & 18866b30a6a8SShachar Beiser rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) { 18876218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1888b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 18896b30a6a8SShachar Beiser pkt->vlan_tci = 18906b30a6a8SShachar Beiser rte_be_to_cpu_16(cqe->vlan_info); 1891f3db9489SYaacov Hazan } 189278c7406bSRaslan Darawsheh if (rxq->hw_timestamp) { 189378c7406bSRaslan Darawsheh pkt->timestamp = 189478c7406bSRaslan Darawsheh rte_be_to_cpu_64(cqe->timestamp); 189578c7406bSRaslan Darawsheh pkt->ol_flags |= PKT_RX_TIMESTAMP; 189678c7406bSRaslan Darawsheh } 18976218063bSNélio Laranjeiro if (rxq->crc_present) 18986218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 18996218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 19009964b965SNélio Laranjeiro } 19019964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 19029964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 19039964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 19049964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 19059964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 19069964b965SNélio Laranjeiro /* 19079964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 19089964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 19099964b965SNélio Laranjeiro * changes. 19109964b965SNélio Laranjeiro */ 19116b30a6a8SShachar Beiser wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 19129964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 19139964b965SNélio Laranjeiro len -= DATA_LEN(seg); 19149964b965SNélio Laranjeiro ++NB_SEGS(pkt); 19159964b965SNélio Laranjeiro ++rq_ci; 19169964b965SNélio Laranjeiro continue; 19179964b965SNélio Laranjeiro } 19189964b965SNélio Laranjeiro DATA_LEN(seg) = len; 191987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 192087011737SAdrien Mazarguil /* Increment bytes counter. */ 19219964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 192287011737SAdrien Mazarguil #endif 19236218063bSNélio Laranjeiro /* Return packet. */ 19246218063bSNélio Laranjeiro *(pkts++) = pkt; 19259964b965SNélio Laranjeiro pkt = NULL; 19269964b965SNélio Laranjeiro --pkts_n; 19279964b965SNélio Laranjeiro ++i; 192899c12dccSNélio Laranjeiro skip: 19299964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 19309964b965SNélio Laranjeiro rq_ci >>= sges_n; 19316218063bSNélio Laranjeiro ++rq_ci; 19329964b965SNélio Laranjeiro rq_ci <<= sges_n; 19332e22920bSAdrien Mazarguil } 19349964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 19352e22920bSAdrien Mazarguil return 0; 19366218063bSNélio Laranjeiro /* Update the consumer index. */ 19379964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 19389afa3f74SYongseok Koh rte_io_wmb(); 19396b30a6a8SShachar Beiser *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 19409afa3f74SYongseok Koh rte_io_wmb(); 19416b30a6a8SShachar Beiser *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 194287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 194387011737SAdrien Mazarguil /* Increment packets counter. */ 19449964b965SNélio Laranjeiro rxq->stats.ipackets += i; 194587011737SAdrien Mazarguil #endif 19469964b965SNélio Laranjeiro return i; 19472e22920bSAdrien Mazarguil } 19482e22920bSAdrien Mazarguil 19492e22920bSAdrien Mazarguil /** 19502e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 19512e22920bSAdrien Mazarguil * 19522e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19532e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19542e22920bSAdrien Mazarguil * 19552e22920bSAdrien Mazarguil * @param dpdk_txq 19562e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 19572e22920bSAdrien Mazarguil * @param[in] pkts 19582e22920bSAdrien Mazarguil * Packets to transmit. 19592e22920bSAdrien Mazarguil * @param pkts_n 19602e22920bSAdrien Mazarguil * Number of packets in array. 19612e22920bSAdrien Mazarguil * 19622e22920bSAdrien Mazarguil * @return 19632e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 19642e22920bSAdrien Mazarguil */ 19652e22920bSAdrien Mazarguil uint16_t 19662e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 19672e22920bSAdrien Mazarguil { 19682e22920bSAdrien Mazarguil (void)dpdk_txq; 19692e22920bSAdrien Mazarguil (void)pkts; 19702e22920bSAdrien Mazarguil (void)pkts_n; 19712e22920bSAdrien Mazarguil return 0; 19722e22920bSAdrien Mazarguil } 19732e22920bSAdrien Mazarguil 19742e22920bSAdrien Mazarguil /** 19752e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 19762e22920bSAdrien Mazarguil * 19772e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19782e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19792e22920bSAdrien Mazarguil * 19802e22920bSAdrien Mazarguil * @param dpdk_rxq 19812e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 19822e22920bSAdrien Mazarguil * @param[out] pkts 19832e22920bSAdrien Mazarguil * Array to store received packets. 19842e22920bSAdrien Mazarguil * @param pkts_n 19852e22920bSAdrien Mazarguil * Maximum number of packets in array. 19862e22920bSAdrien Mazarguil * 19872e22920bSAdrien Mazarguil * @return 19882e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 19892e22920bSAdrien Mazarguil */ 19902e22920bSAdrien Mazarguil uint16_t 19912e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 19922e22920bSAdrien Mazarguil { 19932e22920bSAdrien Mazarguil (void)dpdk_rxq; 19942e22920bSAdrien Mazarguil (void)pkts; 19952e22920bSAdrien Mazarguil (void)pkts_n; 19962e22920bSAdrien Mazarguil return 0; 19972e22920bSAdrien Mazarguil } 19986cb559d6SYongseok Koh 19996cb559d6SYongseok Koh /* 20006cb559d6SYongseok Koh * Vectorized Rx/Tx routines are not compiled in when required vector 20016cb559d6SYongseok Koh * instructions are not supported on a target architecture. The following null 20026cb559d6SYongseok Koh * stubs are needed for linkage when those are not included outside of this file 20036cb559d6SYongseok Koh * (e.g. mlx5_rxtx_vec_sse.c for x86). 20046cb559d6SYongseok Koh */ 20056cb559d6SYongseok Koh 20066cb559d6SYongseok Koh uint16_t __attribute__((weak)) 20076cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 20086cb559d6SYongseok Koh { 20096cb559d6SYongseok Koh (void)dpdk_txq; 20106cb559d6SYongseok Koh (void)pkts; 20116cb559d6SYongseok Koh (void)pkts_n; 20126cb559d6SYongseok Koh return 0; 20136cb559d6SYongseok Koh } 20146cb559d6SYongseok Koh 20156cb559d6SYongseok Koh uint16_t __attribute__((weak)) 20166cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 20176cb559d6SYongseok Koh { 20186cb559d6SYongseok Koh (void)dpdk_txq; 20196cb559d6SYongseok Koh (void)pkts; 20206cb559d6SYongseok Koh (void)pkts_n; 20216cb559d6SYongseok Koh return 0; 20226cb559d6SYongseok Koh } 20236cb559d6SYongseok Koh 20246cb559d6SYongseok Koh uint16_t __attribute__((weak)) 20256cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 20266cb559d6SYongseok Koh { 20276cb559d6SYongseok Koh (void)dpdk_rxq; 20286cb559d6SYongseok Koh (void)pkts; 20296cb559d6SYongseok Koh (void)pkts_n; 20306cb559d6SYongseok Koh return 0; 20316cb559d6SYongseok Koh } 20326cb559d6SYongseok Koh 20336cb559d6SYongseok Koh int __attribute__((weak)) 20346cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv) 20356cb559d6SYongseok Koh { 20366cb559d6SYongseok Koh (void)priv; 20376cb559d6SYongseok Koh return -ENOTSUP; 20386cb559d6SYongseok Koh } 20396cb559d6SYongseok Koh 20406cb559d6SYongseok Koh int __attribute__((weak)) 20416cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv) 20426cb559d6SYongseok Koh { 20436cb559d6SYongseok Koh (void)priv; 20446cb559d6SYongseok Koh return -ENOTSUP; 20456cb559d6SYongseok Koh } 20466cb559d6SYongseok Koh 20476cb559d6SYongseok Koh int __attribute__((weak)) 204878142aacSNélio Laranjeiro rxq_check_vec_support(struct mlx5_rxq_data *rxq) 20496cb559d6SYongseok Koh { 20506cb559d6SYongseok Koh (void)rxq; 20516cb559d6SYongseok Koh return -ENOTSUP; 20526cb559d6SYongseok Koh } 20536cb559d6SYongseok Koh 20546cb559d6SYongseok Koh int __attribute__((weak)) 20556cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv) 20566cb559d6SYongseok Koh { 20576cb559d6SYongseok Koh (void)priv; 20586cb559d6SYongseok Koh return -ENOTSUP; 20596cb559d6SYongseok Koh } 2060