18fd92a66SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause 22e22920bSAdrien Mazarguil * Copyright 2015 6WIND S.A. 35feecc57SShahaf Shuler * Copyright 2015 Mellanox Technologies, Ltd 42e22920bSAdrien Mazarguil */ 52e22920bSAdrien Mazarguil 62e22920bSAdrien Mazarguil #include <assert.h> 72e22920bSAdrien Mazarguil #include <stdint.h> 82e22920bSAdrien Mazarguil #include <string.h> 92e22920bSAdrien Mazarguil #include <stdlib.h> 102e22920bSAdrien Mazarguil 112e22920bSAdrien Mazarguil /* Verbs header. */ 122e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 132e22920bSAdrien Mazarguil #ifdef PEDANTIC 14fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic" 152e22920bSAdrien Mazarguil #endif 162e22920bSAdrien Mazarguil #include <infiniband/verbs.h> 1743e9d979SShachar Beiser #include <infiniband/mlx5dv.h> 182e22920bSAdrien Mazarguil #ifdef PEDANTIC 19fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 202e22920bSAdrien Mazarguil #endif 212e22920bSAdrien Mazarguil 222e22920bSAdrien Mazarguil #include <rte_mbuf.h> 232e22920bSAdrien Mazarguil #include <rte_mempool.h> 242e22920bSAdrien Mazarguil #include <rte_prefetch.h> 252e22920bSAdrien Mazarguil #include <rte_common.h> 262e22920bSAdrien Mazarguil #include <rte_branch_prediction.h> 276218063bSNélio Laranjeiro #include <rte_ether.h> 282e22920bSAdrien Mazarguil 292e22920bSAdrien Mazarguil #include "mlx5.h" 302e22920bSAdrien Mazarguil #include "mlx5_utils.h" 312e22920bSAdrien Mazarguil #include "mlx5_rxtx.h" 32f3db9489SYaacov Hazan #include "mlx5_autoconf.h" 332e22920bSAdrien Mazarguil #include "mlx5_defs.h" 346218063bSNélio Laranjeiro #include "mlx5_prm.h" 356218063bSNélio Laranjeiro 36c0583d98SJerin Jacob static __rte_always_inline uint32_t 37c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe); 38ff1807a3SNélio Laranjeiro 39c0583d98SJerin Jacob static __rte_always_inline int 4078142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 41c0583d98SJerin Jacob uint16_t cqe_cnt, uint32_t *rss_hash); 42ff1807a3SNélio Laranjeiro 43c0583d98SJerin Jacob static __rte_always_inline uint32_t 4478142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe); 45ff1807a3SNélio Laranjeiro 46ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = { 47ea16068cSYongseok Koh [0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */ 48ea16068cSYongseok Koh }; 49ea16068cSYongseok Koh 50ea16068cSYongseok Koh /** 51ea16068cSYongseok Koh * Build a table to translate Rx completion flags to packet type. 52ea16068cSYongseok Koh * 53ea16068cSYongseok Koh * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 54ea16068cSYongseok Koh */ 55ea16068cSYongseok Koh void 56ea16068cSYongseok Koh mlx5_set_ptype_table(void) 57ea16068cSYongseok Koh { 58ea16068cSYongseok Koh unsigned int i; 59ea16068cSYongseok Koh uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table; 60ea16068cSYongseok Koh 619807f113SYongseok Koh /* Last entry must not be overwritten, reserved for errored packet. */ 629807f113SYongseok Koh for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i) 63ea16068cSYongseok Koh (*p)[i] = RTE_PTYPE_UNKNOWN; 646cb559d6SYongseok Koh /* 656cb559d6SYongseok Koh * The index to the array should have: 66ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 67ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 68ea16068cSYongseok Koh * bit[5] = ip_frag 69ea16068cSYongseok Koh * bit[6] = tunneled 70ea16068cSYongseok Koh * bit[7] = outer_l3_type 7199c12dccSNélio Laranjeiro */ 723ca63b88SShahaf Shuler /* L2 */ 733ca63b88SShahaf Shuler (*p)[0x00] = RTE_PTYPE_L2_ETHER; 74ea16068cSYongseok Koh /* L3 */ 75ea16068cSYongseok Koh (*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 76ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 77ea16068cSYongseok Koh (*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 78ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 79ea16068cSYongseok Koh /* Fragmented */ 80ea16068cSYongseok Koh (*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 81ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 82ea16068cSYongseok Koh (*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 83ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 84ea16068cSYongseok Koh /* TCP */ 85ea16068cSYongseok Koh (*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 86ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 87ea16068cSYongseok Koh (*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 88ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 890915e287SBin Huang (*p)[0x0d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 900915e287SBin Huang RTE_PTYPE_L4_TCP; 910915e287SBin Huang (*p)[0x0e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 920915e287SBin Huang RTE_PTYPE_L4_TCP; 930915e287SBin Huang (*p)[0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 940915e287SBin Huang RTE_PTYPE_L4_TCP; 950915e287SBin Huang (*p)[0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 960915e287SBin Huang RTE_PTYPE_L4_TCP; 97ea16068cSYongseok Koh /* UDP */ 98ea16068cSYongseok Koh (*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 99ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 100ea16068cSYongseok Koh (*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 101ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 102ea16068cSYongseok Koh /* Repeat with outer_l3_type being set. Just in case. */ 103ea16068cSYongseok Koh (*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 104ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 105ea16068cSYongseok Koh (*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 106ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 107ea16068cSYongseok Koh (*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 108ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 109ea16068cSYongseok Koh (*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 110ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 111ea16068cSYongseok Koh (*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 112ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 113ea16068cSYongseok Koh (*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 114ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 1150915e287SBin Huang (*p)[0x8d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1160915e287SBin Huang RTE_PTYPE_L4_TCP; 1170915e287SBin Huang (*p)[0x8e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1180915e287SBin Huang RTE_PTYPE_L4_TCP; 1190915e287SBin Huang (*p)[0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1200915e287SBin Huang RTE_PTYPE_L4_TCP; 1210915e287SBin Huang (*p)[0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1220915e287SBin Huang RTE_PTYPE_L4_TCP; 123ea16068cSYongseok Koh (*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 124ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 125ea16068cSYongseok Koh (*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 126ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 127ea16068cSYongseok Koh /* Tunneled - L3 */ 128ea16068cSYongseok Koh (*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 129ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 130ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 131ea16068cSYongseok Koh (*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 132ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 133ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 134ea16068cSYongseok Koh (*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 135ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 136ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 137ea16068cSYongseok Koh (*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 138ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 139ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 140ea16068cSYongseok Koh /* Tunneled - Fragmented */ 141ea16068cSYongseok Koh (*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 142ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 143ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 144ea16068cSYongseok Koh (*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 145ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 146ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 147ea16068cSYongseok Koh (*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 148ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 149ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 150ea16068cSYongseok Koh (*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 151ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 152ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 153ea16068cSYongseok Koh /* Tunneled - TCP */ 154ea16068cSYongseok Koh (*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 155ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1566c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 157ea16068cSYongseok Koh (*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 158ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1596c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 1600915e287SBin Huang (*p)[0x4d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1610915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1620915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1630915e287SBin Huang (*p)[0x4e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1640915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1650915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1660915e287SBin Huang (*p)[0x51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1670915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1680915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1690915e287SBin Huang (*p)[0x52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1700915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1710915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 172ea16068cSYongseok Koh (*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 173ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1746c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 175ea16068cSYongseok Koh (*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 176ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1776c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 1780915e287SBin Huang (*p)[0xcd] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1790915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1800915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1810915e287SBin Huang (*p)[0xce] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1820915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1830915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1840915e287SBin Huang (*p)[0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1850915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1860915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1870915e287SBin Huang (*p)[0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1880915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1890915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 190ea16068cSYongseok Koh /* Tunneled - UDP */ 191ea16068cSYongseok Koh (*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 192ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1936c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 194ea16068cSYongseok Koh (*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 195ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1966c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 197ea16068cSYongseok Koh (*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 198ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1996c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 200ea16068cSYongseok Koh (*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 201ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 2026c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 203ea16068cSYongseok Koh } 204fdcb0f53SNélio Laranjeiro 2052e22920bSAdrien Mazarguil /** 2066ce84bd8SYongseok Koh * Return the size of tailroom of WQ. 2076ce84bd8SYongseok Koh * 2086ce84bd8SYongseok Koh * @param txq 2096ce84bd8SYongseok Koh * Pointer to TX queue structure. 2106ce84bd8SYongseok Koh * @param addr 2116ce84bd8SYongseok Koh * Pointer to tail of WQ. 2126ce84bd8SYongseok Koh * 2136ce84bd8SYongseok Koh * @return 2146ce84bd8SYongseok Koh * Size of tailroom. 2156ce84bd8SYongseok Koh */ 2166ce84bd8SYongseok Koh static inline size_t 217991b04f6SNélio Laranjeiro tx_mlx5_wq_tailroom(struct mlx5_txq_data *txq, void *addr) 2186ce84bd8SYongseok Koh { 2196ce84bd8SYongseok Koh size_t tailroom; 2206ce84bd8SYongseok Koh tailroom = (uintptr_t)(txq->wqes) + 2216ce84bd8SYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE - 2226ce84bd8SYongseok Koh (uintptr_t)addr; 2236ce84bd8SYongseok Koh return tailroom; 2246ce84bd8SYongseok Koh } 2256ce84bd8SYongseok Koh 2266ce84bd8SYongseok Koh /** 2276ce84bd8SYongseok Koh * Copy data to tailroom of circular queue. 2286ce84bd8SYongseok Koh * 2296ce84bd8SYongseok Koh * @param dst 2306ce84bd8SYongseok Koh * Pointer to destination. 2316ce84bd8SYongseok Koh * @param src 2326ce84bd8SYongseok Koh * Pointer to source. 2336ce84bd8SYongseok Koh * @param n 2346ce84bd8SYongseok Koh * Number of bytes to copy. 2356ce84bd8SYongseok Koh * @param base 2366ce84bd8SYongseok Koh * Pointer to head of queue. 2376ce84bd8SYongseok Koh * @param tailroom 2386ce84bd8SYongseok Koh * Size of tailroom from dst. 2396ce84bd8SYongseok Koh * 2406ce84bd8SYongseok Koh * @return 2416ce84bd8SYongseok Koh * Pointer after copied data. 2426ce84bd8SYongseok Koh */ 2436ce84bd8SYongseok Koh static inline void * 2446ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n, 2456ce84bd8SYongseok Koh void *base, size_t tailroom) 2466ce84bd8SYongseok Koh { 2476ce84bd8SYongseok Koh void *ret; 2486ce84bd8SYongseok Koh 2496ce84bd8SYongseok Koh if (n > tailroom) { 2506ce84bd8SYongseok Koh rte_memcpy(dst, src, tailroom); 2516ce84bd8SYongseok Koh rte_memcpy(base, (void *)((uintptr_t)src + tailroom), 2526ce84bd8SYongseok Koh n - tailroom); 2536ce84bd8SYongseok Koh ret = (uint8_t *)base + n - tailroom; 2546ce84bd8SYongseok Koh } else { 2556ce84bd8SYongseok Koh rte_memcpy(dst, src, n); 2566ce84bd8SYongseok Koh ret = (n == tailroom) ? base : (uint8_t *)dst + n; 2576ce84bd8SYongseok Koh } 2586ce84bd8SYongseok Koh return ret; 2596ce84bd8SYongseok Koh } 2606ce84bd8SYongseok Koh 2616ce84bd8SYongseok Koh /** 262*593f472cSXueming Li * Inline TSO headers into WQE. 263*593f472cSXueming Li * 264*593f472cSXueming Li * @return 265*593f472cSXueming Li * 0 on success, negative errno value on failure. 266*593f472cSXueming Li */ 267*593f472cSXueming Li static int 268*593f472cSXueming Li inline_tso(struct mlx5_txq_data *txq, struct rte_mbuf *buf, 269*593f472cSXueming Li uint32_t *length, 270*593f472cSXueming Li uint8_t *cs_flags, 271*593f472cSXueming Li uintptr_t *addr, 272*593f472cSXueming Li uint16_t *pkt_inline_sz, 273*593f472cSXueming Li uint8_t **raw, 274*593f472cSXueming Li uint16_t *max_wqe, 275*593f472cSXueming Li uint16_t *tso_segsz, 276*593f472cSXueming Li uint16_t *tso_header_sz) 277*593f472cSXueming Li { 278*593f472cSXueming Li uintptr_t end = (uintptr_t)(((uintptr_t)txq->wqes) + 279*593f472cSXueming Li (1 << txq->wqe_n) * MLX5_WQE_SIZE); 280*593f472cSXueming Li unsigned int copy_b; 281*593f472cSXueming Li uint8_t vlan_sz = (buf->ol_flags & PKT_TX_VLAN_PKT) ? 4 : 0; 282*593f472cSXueming Li const uint8_t tunneled = txq->tunnel_en && 283*593f472cSXueming Li (buf->ol_flags & (PKT_TX_TUNNEL_GRE | 284*593f472cSXueming Li PKT_TX_TUNNEL_VXLAN)); 285*593f472cSXueming Li uint16_t n_wqe; 286*593f472cSXueming Li 287*593f472cSXueming Li *tso_segsz = buf->tso_segsz; 288*593f472cSXueming Li *tso_header_sz = buf->l2_len + vlan_sz + buf->l3_len + buf->l4_len; 289*593f472cSXueming Li if (unlikely(*tso_segsz == 0 || *tso_header_sz == 0)) { 290*593f472cSXueming Li txq->stats.oerrors++; 291*593f472cSXueming Li return -EINVAL; 292*593f472cSXueming Li } 293*593f472cSXueming Li if (tunneled) { 294*593f472cSXueming Li *tso_header_sz += buf->outer_l2_len + buf->outer_l3_len; 295*593f472cSXueming Li *cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM; 296*593f472cSXueming Li } else { 297*593f472cSXueming Li *cs_flags |= MLX5_ETH_WQE_L4_CSUM; 298*593f472cSXueming Li } 299*593f472cSXueming Li if (unlikely(*tso_header_sz > MLX5_MAX_TSO_HEADER)) { 300*593f472cSXueming Li txq->stats.oerrors++; 301*593f472cSXueming Li return -EINVAL; 302*593f472cSXueming Li } 303*593f472cSXueming Li copy_b = *tso_header_sz - *pkt_inline_sz; 304*593f472cSXueming Li /* First seg must contain all TSO headers. */ 305*593f472cSXueming Li assert(copy_b <= *length); 306*593f472cSXueming Li if (!copy_b || ((end - (uintptr_t)*raw) < copy_b)) 307*593f472cSXueming Li return -EAGAIN; 308*593f472cSXueming Li n_wqe = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 309*593f472cSXueming Li if (unlikely(*max_wqe < n_wqe)) 310*593f472cSXueming Li return -EINVAL; 311*593f472cSXueming Li *max_wqe -= n_wqe; 312*593f472cSXueming Li rte_memcpy((void *)*raw, (void *)*addr, copy_b); 313*593f472cSXueming Li *length -= copy_b; 314*593f472cSXueming Li *addr += copy_b; 315*593f472cSXueming Li copy_b = MLX5_WQE_DS(copy_b) * MLX5_WQE_DWORD_SIZE; 316*593f472cSXueming Li *pkt_inline_sz += copy_b; 317*593f472cSXueming Li *raw += copy_b; 318*593f472cSXueming Li return 0; 319*593f472cSXueming Li } 320*593f472cSXueming Li 321*593f472cSXueming Li /** 3228788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 3238788fec1SOlivier Matz * 3248788fec1SOlivier Matz * @param tx_queue 3258788fec1SOlivier Matz * The tx queue. 3268788fec1SOlivier Matz * @param[in] offset 3278788fec1SOlivier Matz * The index of the descriptor in the ring. 3288788fec1SOlivier Matz * 3298788fec1SOlivier Matz * @return 3308788fec1SOlivier Matz * The status of the tx descriptor. 3318788fec1SOlivier Matz */ 3328788fec1SOlivier Matz int 3338788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 3348788fec1SOlivier Matz { 335991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = tx_queue; 3368c819a69SYongseok Koh uint16_t used; 3378788fec1SOlivier Matz 3386cb559d6SYongseok Koh mlx5_tx_complete(txq); 3398c819a69SYongseok Koh used = txq->elts_head - txq->elts_tail; 3408788fec1SOlivier Matz if (offset < used) 3418788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 3428788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 3438788fec1SOlivier Matz } 3448788fec1SOlivier Matz 3458788fec1SOlivier Matz /** 3468788fec1SOlivier Matz * DPDK callback to check the status of a rx descriptor. 3478788fec1SOlivier Matz * 3488788fec1SOlivier Matz * @param rx_queue 3498788fec1SOlivier Matz * The rx queue. 3508788fec1SOlivier Matz * @param[in] offset 3518788fec1SOlivier Matz * The index of the descriptor in the ring. 3528788fec1SOlivier Matz * 3538788fec1SOlivier Matz * @return 3548788fec1SOlivier Matz * The status of the tx descriptor. 3558788fec1SOlivier Matz */ 3568788fec1SOlivier Matz int 3578788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 3588788fec1SOlivier Matz { 35978142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = rx_queue; 3608788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 3618788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 3628788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 3638788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 3648788fec1SOlivier Matz unsigned int cq_ci; 3658788fec1SOlivier Matz unsigned int used; 3668788fec1SOlivier Matz 3678788fec1SOlivier Matz /* if we are processing a compressed cqe */ 3688788fec1SOlivier Matz if (zip->ai) { 3698788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 3708788fec1SOlivier Matz cq_ci = zip->cq_ci; 3718788fec1SOlivier Matz } else { 3728788fec1SOlivier Matz used = 0; 3738788fec1SOlivier Matz cq_ci = rxq->cq_ci; 3748788fec1SOlivier Matz } 3758788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 3768788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 3778788fec1SOlivier Matz int8_t op_own; 3788788fec1SOlivier Matz unsigned int n; 3798788fec1SOlivier Matz 3808788fec1SOlivier Matz op_own = cqe->op_own; 3818788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 3826b30a6a8SShachar Beiser n = rte_be_to_cpu_32(cqe->byte_cnt); 3838788fec1SOlivier Matz else 3848788fec1SOlivier Matz n = 1; 3858788fec1SOlivier Matz cq_ci += n; 3868788fec1SOlivier Matz used += n; 3878788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 3888788fec1SOlivier Matz } 3898788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 3908788fec1SOlivier Matz if (offset < used) 3918788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 3928788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 3938788fec1SOlivier Matz } 3948788fec1SOlivier Matz 3958788fec1SOlivier Matz /** 3962e22920bSAdrien Mazarguil * DPDK callback for TX. 3972e22920bSAdrien Mazarguil * 3982e22920bSAdrien Mazarguil * @param dpdk_txq 3992e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 4002e22920bSAdrien Mazarguil * @param[in] pkts 4012e22920bSAdrien Mazarguil * Packets to transmit. 4022e22920bSAdrien Mazarguil * @param pkts_n 4032e22920bSAdrien Mazarguil * Number of packets in array. 4042e22920bSAdrien Mazarguil * 4052e22920bSAdrien Mazarguil * @return 4062e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 4072e22920bSAdrien Mazarguil */ 4082e22920bSAdrien Mazarguil uint16_t 4092e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 4102e22920bSAdrien Mazarguil { 411991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 4121d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 4138c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 4148c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 415c3d62cc9SAdrien Mazarguil unsigned int i = 0; 416a5bf6af9SAdrien Mazarguil unsigned int j = 0; 4173f13f8c2SShahaf Shuler unsigned int k = 0; 4188c819a69SYongseok Koh uint16_t max_elts; 419f04f1d51SNélio Laranjeiro uint16_t max_wqe; 420c305090bSAdrien Mazarguil unsigned int comp; 421ac180a21SYongseok Koh volatile struct mlx5_wqe_ctrl *last_wqe = NULL; 4226579c27cSNélio Laranjeiro unsigned int segs_n = 0; 42327a6b2d6SNélio Laranjeiro const unsigned int max_inline = txq->max_inline; 4242e22920bSAdrien Mazarguil 4251d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 4261d88ba17SNélio Laranjeiro return 0; 4275e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 428c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 4291d88ba17SNélio Laranjeiro /* Start processing. */ 4306cb559d6SYongseok Koh mlx5_tx_complete(txq); 4318c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 4322eefbec5SYongseok Koh /* A CQE slot must always be available. */ 4332eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 434f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 435f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 436f04f1d51SNélio Laranjeiro return 0; 437c3d62cc9SAdrien Mazarguil do { 4383bbae1ebSNélio Laranjeiro struct rte_mbuf *buf = NULL; 4393bbae1ebSNélio Laranjeiro uint8_t *raw; 4403bbae1ebSNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 4419a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 442573f54afSNélio Laranjeiro uint32_t length; 4438688b2f8SNélio Laranjeiro unsigned int ds = 0; 444ac180a21SYongseok Koh unsigned int sg = 0; /* counter of additional segs attached. */ 4456579c27cSNélio Laranjeiro uintptr_t addr; 4460d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 4473f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 448eef822ddSNélio Laranjeiro uint16_t ehdr; 4494aa15eb1SNélio Laranjeiro uint8_t cs_flags; 4503f13f8c2SShahaf Shuler uint64_t tso = 0; 45183daf156SShahaf Shuler uint16_t tso_segsz = 0; 4526579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 4536579c27cSNélio Laranjeiro uint32_t total_length = 0; 4546579c27cSNélio Laranjeiro #endif 455*593f472cSXueming Li int ret; 4562e22920bSAdrien Mazarguil 4576579c27cSNélio Laranjeiro /* first_seg */ 4583730e6c6SYongseok Koh buf = *pkts; 4596579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 460c3d62cc9SAdrien Mazarguil /* 461c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 462c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 463c3d62cc9SAdrien Mazarguil */ 464a5bf6af9SAdrien Mazarguil assert(segs_n); 4658c819a69SYongseok Koh if (max_elts < segs_n) 466c3d62cc9SAdrien Mazarguil break; 4678c819a69SYongseok Koh max_elts -= segs_n; 468f895536bSYongseok Koh sg = --segs_n; 469f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 470f04f1d51SNélio Laranjeiro break; 4719a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 472fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 473fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 4743730e6c6SYongseok Koh if (pkts_n - i > 1) 4753730e6c6SYongseok Koh rte_prefetch0(*(pkts + 1)); 4766579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 4772e22920bSAdrien Mazarguil length = DATA_LEN(buf); 478eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 479eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 4806579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 4816579c27cSNélio Laranjeiro total_length = length; 4826579c27cSNélio Laranjeiro #endif 48324c14430SShahaf Shuler if (length < (MLX5_WQE_DWORD_SIZE + 2)) { 48424c14430SShahaf Shuler txq->stats.oerrors++; 485959be52eSNélio Laranjeiro break; 48624c14430SShahaf Shuler } 4872e22920bSAdrien Mazarguil /* Update element. */ 4888c819a69SYongseok Koh (*txq->elts)[elts_head & elts_m] = buf; 4895e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 4903730e6c6SYongseok Koh if (pkts_n - i > 1) 4913730e6c6SYongseok Koh rte_prefetch0( 4923730e6c6SYongseok Koh rte_pktmbuf_mtod(*(pkts + 1), volatile void *)); 4934aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 494b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 4956579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 4966579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 4976b30a6a8SShachar Beiser uint32_t vlan = rte_cpu_to_be_32(0x81000000 | 4986b30a6a8SShachar Beiser buf->vlan_tci); 4990d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 5006579c27cSNélio Laranjeiro 5010d637a34SNélio Laranjeiro addr += 2; 5020d637a34SNélio Laranjeiro length -= 2; 5030d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 5040d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 5050d637a34SNélio Laranjeiro /* Copy VLAN. */ 5060d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 5070d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 5080d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 5090d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 5100d637a34SNélio Laranjeiro addr += len + 2; 5110d637a34SNélio Laranjeiro length -= (len + 2); 5120d637a34SNélio Laranjeiro } else { 5130d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 5140d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 5150d637a34SNélio Laranjeiro length -= pkt_inline_sz; 5160d637a34SNélio Laranjeiro addr += pkt_inline_sz; 5176579c27cSNélio Laranjeiro } 518d8292497SYongseok Koh raw += MLX5_WQE_DWORD_SIZE; 51936aa55eaSYongseok Koh tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG); 5203f13f8c2SShahaf Shuler if (tso) { 521*593f472cSXueming Li ret = inline_tso(txq, buf, &length, &cs_flags, 522*593f472cSXueming Li &addr, &pkt_inline_sz, 523*593f472cSXueming Li &raw, &max_wqe, 524*593f472cSXueming Li &tso_segsz, &tso_header_sz); 525*593f472cSXueming Li if (ret == -EINVAL) { 52696fc8d65SShahaf Shuler break; 527*593f472cSXueming Li } else if (ret == -EAGAIN) { 5283f13f8c2SShahaf Shuler /* NOP WQE. */ 5293f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 53036aa55eaSYongseok Koh rte_cpu_to_be_32(txq->wqe_ci << 8), 53136aa55eaSYongseok Koh rte_cpu_to_be_32(txq->qp_num_8s | 1), 5323f13f8c2SShahaf Shuler 0, 5333f13f8c2SShahaf Shuler 0, 5343f13f8c2SShahaf Shuler }; 5353f13f8c2SShahaf Shuler ds = 1; 536cb98affeSThierry Herbelot #ifdef MLX5_PMD_SOFT_COUNTERS 5373f13f8c2SShahaf Shuler total_length = 0; 538cb98affeSThierry Herbelot #endif 5393f13f8c2SShahaf Shuler k++; 5403f13f8c2SShahaf Shuler goto next_wqe; 5413f13f8c2SShahaf Shuler } 5423f13f8c2SShahaf Shuler } 5436579c27cSNélio Laranjeiro /* Inline if enough room. */ 54427a6b2d6SNélio Laranjeiro if (max_inline || tso) { 545f895536bSYongseok Koh uint32_t inl = 0; 546fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 547fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 548fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 549ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 5508fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 551d8292497SYongseok Koh (pkt_inline_sz - 2) - 552d8292497SYongseok Koh !!tso * sizeof(inl); 553f895536bSYongseok Koh uintptr_t addr_end; 554f895536bSYongseok Koh unsigned int copy_b; 5556579c27cSNélio Laranjeiro 556f895536bSYongseok Koh pkt_inline: 557f895536bSYongseok Koh addr_end = RTE_ALIGN_FLOOR(addr + inline_room, 558f895536bSYongseok Koh RTE_CACHE_LINE_SIZE); 559f895536bSYongseok Koh copy_b = (addr_end > addr) ? 560f895536bSYongseok Koh RTE_MIN((addr_end - addr), length) : 0; 5618fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 562f04f1d51SNélio Laranjeiro /* 563f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 564f04f1d51SNélio Laranjeiro * keep the computation positive, it is 565f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 566f04f1d51SNélio Laranjeiro */ 5678fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 5688fcd6c2cSNélio Laranjeiro 569f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 570f04f1d51SNélio Laranjeiro break; 571f04f1d51SNélio Laranjeiro max_wqe -= n; 572f895536bSYongseok Koh if (tso && !inl) { 5736963ae8bSYongseok Koh inl = rte_cpu_to_be_32(copy_b | 5746b30a6a8SShachar Beiser MLX5_INLINE_SEG); 5753f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 5763f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 5773f13f8c2SShahaf Shuler raw += sizeof(inl); 5783f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 5793f13f8c2SShahaf Shuler } 5806579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 5816579c27cSNélio Laranjeiro addr += copy_b; 5826579c27cSNélio Laranjeiro length -= copy_b; 5836579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 5846579c27cSNélio Laranjeiro } 5856579c27cSNélio Laranjeiro /* 586786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 5876579c27cSNélio Laranjeiro * the size of the inline part of the packet. 5886579c27cSNélio Laranjeiro */ 5896579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 5906579c27cSNélio Laranjeiro if (length > 0) { 591f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 592f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 593f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 594f04f1d51SNélio Laranjeiro break; 595f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 596f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 597f04f1d51SNélio Laranjeiro ds / 4); 598f04f1d51SNélio Laranjeiro } else { 5999a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 6006579c27cSNélio Laranjeiro ((uintptr_t)wqe + 6016579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 602f04f1d51SNélio Laranjeiro } 6036579c27cSNélio Laranjeiro goto use_dseg; 6046579c27cSNélio Laranjeiro } else if (!segs_n) { 6056579c27cSNélio Laranjeiro goto next_pkt; 6066579c27cSNélio Laranjeiro } else { 607f895536bSYongseok Koh raw += copy_b; 608f895536bSYongseok Koh inline_room -= copy_b; 609f895536bSYongseok Koh --segs_n; 610f895536bSYongseok Koh buf = buf->next; 611f895536bSYongseok Koh assert(buf); 612f895536bSYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 613f895536bSYongseok Koh length = DATA_LEN(buf); 614f895536bSYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 615f895536bSYongseok Koh total_length += length; 616f895536bSYongseok Koh #endif 617f895536bSYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 618f895536bSYongseok Koh goto pkt_inline; 6196579c27cSNélio Laranjeiro } 6206579c27cSNélio Laranjeiro } else { 6216579c27cSNélio Laranjeiro /* 6226579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 6236579c27cSNélio Laranjeiro * Ethernet Header as been stored. 6246579c27cSNélio Laranjeiro */ 6259a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 6266579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 6276579c27cSNélio Laranjeiro ds = 3; 6286579c27cSNélio Laranjeiro use_dseg: 6296579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 630ebbb81ebSNélio Laranjeiro addr = rte_cpu_to_be_64(addr); 6319a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6326b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 6336cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 634ebbb81ebSNélio Laranjeiro addr, 635ebbb81ebSNélio Laranjeiro addr >> 32, 6366579c27cSNélio Laranjeiro }; 6376579c27cSNélio Laranjeiro ++ds; 6386579c27cSNélio Laranjeiro if (!segs_n) 6396579c27cSNélio Laranjeiro goto next_pkt; 6406579c27cSNélio Laranjeiro } 6416579c27cSNélio Laranjeiro next_seg: 6426579c27cSNélio Laranjeiro assert(buf); 6436579c27cSNélio Laranjeiro assert(ds); 6446579c27cSNélio Laranjeiro assert(wqe); 645a5bf6af9SAdrien Mazarguil /* 646a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 647a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 648a5bf6af9SAdrien Mazarguil * of data segment size. 649a5bf6af9SAdrien Mazarguil */ 6508688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 6516579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 652f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 653f04f1d51SNélio Laranjeiro break; 6549a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 655f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 656f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 657f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 6586579c27cSNélio Laranjeiro } else { 659a5bf6af9SAdrien Mazarguil ++dseg; 6606579c27cSNélio Laranjeiro } 661a5bf6af9SAdrien Mazarguil ++ds; 662a5bf6af9SAdrien Mazarguil buf = buf->next; 663a5bf6af9SAdrien Mazarguil assert(buf); 6646579c27cSNélio Laranjeiro length = DATA_LEN(buf); 665a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 6666579c27cSNélio Laranjeiro total_length += length; 667a5bf6af9SAdrien Mazarguil #endif 6686579c27cSNélio Laranjeiro /* Store segment information. */ 669ebbb81ebSNélio Laranjeiro addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)); 6709a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 6716b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 6726cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 673ebbb81ebSNélio Laranjeiro addr, 674ebbb81ebSNélio Laranjeiro addr >> 32, 6756579c27cSNélio Laranjeiro }; 6768c819a69SYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 677f895536bSYongseok Koh if (--segs_n) 6786579c27cSNélio Laranjeiro goto next_seg; 6796579c27cSNélio Laranjeiro next_pkt: 680883ce172SShahaf Shuler if (ds > MLX5_DSEG_MAX) { 681883ce172SShahaf Shuler txq->stats.oerrors++; 682883ce172SShahaf Shuler break; 683883ce172SShahaf Shuler } 6848c819a69SYongseok Koh ++elts_head; 6853730e6c6SYongseok Koh ++pkts; 6866579c27cSNélio Laranjeiro ++i; 687f895536bSYongseok Koh j += sg; 688b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 6893f13f8c2SShahaf Shuler if (tso) { 6903f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 6916b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 6926b30a6a8SShachar Beiser MLX5_OPCODE_TSO), 6936b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 6943f13f8c2SShahaf Shuler 0, 6953f13f8c2SShahaf Shuler 0, 6963f13f8c2SShahaf Shuler }; 6973f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 6983f13f8c2SShahaf Shuler 0, 6996b30a6a8SShachar Beiser cs_flags | (rte_cpu_to_be_16(tso_segsz) << 16), 7003f13f8c2SShahaf Shuler 0, 7016b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(tso_header_sz), 7023f13f8c2SShahaf Shuler }; 7033f13f8c2SShahaf Shuler } else { 7049a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 7056b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 7066b30a6a8SShachar Beiser MLX5_OPCODE_SEND), 7076b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 7089a7fa9f7SNélio Laranjeiro 0, 7099a7fa9f7SNélio Laranjeiro 0, 7109a7fa9f7SNélio Laranjeiro }; 7119a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 7129a7fa9f7SNélio Laranjeiro 0, 7139a7fa9f7SNélio Laranjeiro cs_flags, 7149a7fa9f7SNélio Laranjeiro 0, 7156b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz), 7169a7fa9f7SNélio Laranjeiro }; 7173f13f8c2SShahaf Shuler } 7183f13f8c2SShahaf Shuler next_wqe: 7196579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 720ac180a21SYongseok Koh /* Save the last successful WQE for completion request */ 721ac180a21SYongseok Koh last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe; 72287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 723573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 7246579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 72587011737SAdrien Mazarguil #endif 7263730e6c6SYongseok Koh } while (i < pkts_n); 7272e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 7283f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 7292e22920bSAdrien Mazarguil return 0; 7308c819a69SYongseok Koh txq->elts_head += (i + j); 731c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 7323f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 733c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 734c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 7356b30a6a8SShachar Beiser last_wqe->ctrl2 = rte_cpu_to_be_32(8); 736c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 737ac180a21SYongseok Koh last_wqe->ctrl3 = txq->elts_head; 738c305090bSAdrien Mazarguil txq->elts_comp = 0; 7392eefbec5SYongseok Koh #ifndef NDEBUG 7402eefbec5SYongseok Koh ++txq->cq_pi; 7412eefbec5SYongseok Koh #endif 742c305090bSAdrien Mazarguil } else { 743c305090bSAdrien Mazarguil txq->elts_comp = comp; 744c305090bSAdrien Mazarguil } 74587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 74687011737SAdrien Mazarguil /* Increment sent packets counter. */ 74787011737SAdrien Mazarguil txq->stats.opackets += i; 74887011737SAdrien Mazarguil #endif 7492e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 750ac180a21SYongseok Koh mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe); 7512e22920bSAdrien Mazarguil return i; 7522e22920bSAdrien Mazarguil } 7532e22920bSAdrien Mazarguil 7542e22920bSAdrien Mazarguil /** 755230189d9SNélio Laranjeiro * Open a MPW session. 756230189d9SNélio Laranjeiro * 757230189d9SNélio Laranjeiro * @param txq 758230189d9SNélio Laranjeiro * Pointer to TX queue structure. 759230189d9SNélio Laranjeiro * @param mpw 760230189d9SNélio Laranjeiro * Pointer to MPW session structure. 761230189d9SNélio Laranjeiro * @param length 762230189d9SNélio Laranjeiro * Packet length. 763230189d9SNélio Laranjeiro */ 764230189d9SNélio Laranjeiro static inline void 765991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length) 766230189d9SNélio Laranjeiro { 767a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 768230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 769230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 770fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 771230189d9SNélio Laranjeiro 772230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 773230189d9SNélio Laranjeiro mpw->pkts_n = 0; 774230189d9SNélio Laranjeiro mpw->len = length; 775230189d9SNélio Laranjeiro mpw->total_len = 0; 776fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 7776b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 7788688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 7798688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 7808688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 7818688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 7826b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 7836b30a6a8SShachar Beiser (txq->wqe_ci << 8) | 7846b30a6a8SShachar Beiser MLX5_OPCODE_TSO); 7858688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 7868688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 7878688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 7888688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 7898688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 7908688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 791230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 792230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 793230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 794230189d9SNélio Laranjeiro } 795230189d9SNélio Laranjeiro 796230189d9SNélio Laranjeiro /** 797230189d9SNélio Laranjeiro * Close a MPW session. 798230189d9SNélio Laranjeiro * 799230189d9SNélio Laranjeiro * @param txq 800230189d9SNélio Laranjeiro * Pointer to TX queue structure. 801230189d9SNélio Laranjeiro * @param mpw 802230189d9SNélio Laranjeiro * Pointer to MPW session structure. 803230189d9SNélio Laranjeiro */ 804230189d9SNélio Laranjeiro static inline void 805991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 806230189d9SNélio Laranjeiro { 807230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 808230189d9SNélio Laranjeiro 809230189d9SNélio Laranjeiro /* 810230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 811230189d9SNélio Laranjeiro * count as 2. 812230189d9SNélio Laranjeiro */ 8136b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num)); 814230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 815230189d9SNélio Laranjeiro if (num < 3) 816230189d9SNélio Laranjeiro ++txq->wqe_ci; 817230189d9SNélio Laranjeiro else 818230189d9SNélio Laranjeiro txq->wqe_ci += 2; 819fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 820fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 821230189d9SNélio Laranjeiro } 822230189d9SNélio Laranjeiro 823230189d9SNélio Laranjeiro /** 824230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 825230189d9SNélio Laranjeiro * 826230189d9SNélio Laranjeiro * @param dpdk_txq 827230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 828230189d9SNélio Laranjeiro * @param[in] pkts 829230189d9SNélio Laranjeiro * Packets to transmit. 830230189d9SNélio Laranjeiro * @param pkts_n 831230189d9SNélio Laranjeiro * Number of packets in array. 832230189d9SNélio Laranjeiro * 833230189d9SNélio Laranjeiro * @return 834230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 835230189d9SNélio Laranjeiro */ 836230189d9SNélio Laranjeiro uint16_t 837230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 838230189d9SNélio Laranjeiro { 839991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 840230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 8418c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 8428c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 843c3d62cc9SAdrien Mazarguil unsigned int i = 0; 844a5bf6af9SAdrien Mazarguil unsigned int j = 0; 8458c819a69SYongseok Koh uint16_t max_elts; 846f04f1d51SNélio Laranjeiro uint16_t max_wqe; 847230189d9SNélio Laranjeiro unsigned int comp; 848230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 849230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 850230189d9SNélio Laranjeiro }; 851230189d9SNélio Laranjeiro 852c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 853c3d62cc9SAdrien Mazarguil return 0; 854230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 855fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 856fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 857230189d9SNélio Laranjeiro /* Start processing. */ 8586cb559d6SYongseok Koh mlx5_tx_complete(txq); 8598c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 8602eefbec5SYongseok Koh /* A CQE slot must always be available. */ 8612eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 862f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 863f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 864f04f1d51SNélio Laranjeiro return 0; 865c3d62cc9SAdrien Mazarguil do { 866a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 867230189d9SNélio Laranjeiro uint32_t length; 868a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 8694aa15eb1SNélio Laranjeiro uint32_t cs_flags; 870230189d9SNélio Laranjeiro 871c3d62cc9SAdrien Mazarguil /* 872c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 873c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 874c3d62cc9SAdrien Mazarguil */ 875a5bf6af9SAdrien Mazarguil assert(segs_n); 8768c819a69SYongseok Koh if (max_elts < segs_n) 877c3d62cc9SAdrien Mazarguil break; 878a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 87924c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 88024c14430SShahaf Shuler txq->stats.oerrors++; 881a5bf6af9SAdrien Mazarguil break; 88224c14430SShahaf Shuler } 8838c819a69SYongseok Koh max_elts -= segs_n; 884c3d62cc9SAdrien Mazarguil --pkts_n; 8854aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 886a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 887a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 888a5bf6af9SAdrien Mazarguil assert(length); 889230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 890230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 891230189d9SNélio Laranjeiro ((mpw.len != length) || 892a5bf6af9SAdrien Mazarguil (segs_n != 1) || 8938688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 894230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 895230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 896f04f1d51SNélio Laranjeiro /* 897f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 898f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 899f04f1d51SNélio Laranjeiro * resources. 900f04f1d51SNélio Laranjeiro */ 901f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 902f04f1d51SNélio Laranjeiro break; 903f04f1d51SNélio Laranjeiro max_wqe -= 2; 904230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 9058688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 906230189d9SNélio Laranjeiro } 907a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 908a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 909a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 910a5bf6af9SAdrien Mazarguil length = 0; 911a5bf6af9SAdrien Mazarguil #endif 912a5bf6af9SAdrien Mazarguil do { 913a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 914a5bf6af9SAdrien Mazarguil uintptr_t addr; 915a5bf6af9SAdrien Mazarguil 916a5bf6af9SAdrien Mazarguil assert(buf); 9178c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 918230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 919a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 920230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 9216b30a6a8SShachar Beiser .byte_count = rte_cpu_to_be_32(DATA_LEN(buf)), 9226cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 9236b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 924230189d9SNélio Laranjeiro }; 925a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 926a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 927a5bf6af9SAdrien Mazarguil #endif 928a5bf6af9SAdrien Mazarguil buf = buf->next; 929230189d9SNélio Laranjeiro ++mpw.pkts_n; 930a5bf6af9SAdrien Mazarguil ++j; 931a5bf6af9SAdrien Mazarguil } while (--segs_n); 932a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 933230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 934230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 935230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 936230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 937230189d9SNélio Laranjeiro txq->stats.obytes += length; 938230189d9SNélio Laranjeiro #endif 939c3d62cc9SAdrien Mazarguil ++i; 940c3d62cc9SAdrien Mazarguil } while (pkts_n); 941230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 942230189d9SNélio Laranjeiro if (unlikely(i == 0)) 943230189d9SNélio Laranjeiro return 0; 944230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 945a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 946a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 947230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 9488688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 949230189d9SNélio Laranjeiro 950230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 9516b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 952230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 9538688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 954230189d9SNélio Laranjeiro txq->elts_comp = 0; 9552eefbec5SYongseok Koh #ifndef NDEBUG 9562eefbec5SYongseok Koh ++txq->cq_pi; 9572eefbec5SYongseok Koh #endif 958230189d9SNélio Laranjeiro } else { 959230189d9SNélio Laranjeiro txq->elts_comp = comp; 960230189d9SNélio Laranjeiro } 961230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 962230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 963230189d9SNélio Laranjeiro txq->stats.opackets += i; 964230189d9SNélio Laranjeiro #endif 965230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 966230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 967230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 96830807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 969230189d9SNélio Laranjeiro txq->elts_head = elts_head; 970230189d9SNélio Laranjeiro return i; 971230189d9SNélio Laranjeiro } 972230189d9SNélio Laranjeiro 973230189d9SNélio Laranjeiro /** 974230189d9SNélio Laranjeiro * Open a MPW inline session. 975230189d9SNélio Laranjeiro * 976230189d9SNélio Laranjeiro * @param txq 977230189d9SNélio Laranjeiro * Pointer to TX queue structure. 978230189d9SNélio Laranjeiro * @param mpw 979230189d9SNélio Laranjeiro * Pointer to MPW session structure. 980230189d9SNélio Laranjeiro * @param length 981230189d9SNélio Laranjeiro * Packet length. 982230189d9SNélio Laranjeiro */ 983230189d9SNélio Laranjeiro static inline void 984991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, 985991b04f6SNélio Laranjeiro uint32_t length) 986230189d9SNélio Laranjeiro { 987a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 9888688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 989230189d9SNélio Laranjeiro 990230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 991230189d9SNélio Laranjeiro mpw->pkts_n = 0; 992230189d9SNélio Laranjeiro mpw->len = length; 993230189d9SNélio Laranjeiro mpw->total_len = 0; 994fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 9956b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 996230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 997c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 9988688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 9998688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 10006b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 10018688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 10028688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 10038688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 10048688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 10058688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 10068688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 10078688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 10088688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 1009230189d9SNélio Laranjeiro } 1010230189d9SNélio Laranjeiro 1011230189d9SNélio Laranjeiro /** 1012230189d9SNélio Laranjeiro * Close a MPW inline session. 1013230189d9SNélio Laranjeiro * 1014230189d9SNélio Laranjeiro * @param txq 1015230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1016230189d9SNélio Laranjeiro * @param mpw 1017230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1018230189d9SNélio Laranjeiro */ 1019230189d9SNélio Laranjeiro static inline void 1020991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 1021230189d9SNélio Laranjeiro { 1022230189d9SNélio Laranjeiro unsigned int size; 10238688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 10248688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 1025230189d9SNélio Laranjeiro 10268688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 1027230189d9SNélio Laranjeiro /* 1028230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1029230189d9SNélio Laranjeiro * count as 2. 1030230189d9SNélio Laranjeiro */ 10316b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 10326b30a6a8SShachar Beiser MLX5_WQE_DS(size)); 1033230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 10346b30a6a8SShachar Beiser inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG); 10358688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1036230189d9SNélio Laranjeiro } 1037230189d9SNélio Laranjeiro 1038230189d9SNélio Laranjeiro /** 1039230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1040230189d9SNélio Laranjeiro * 1041230189d9SNélio Laranjeiro * @param dpdk_txq 1042230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1043230189d9SNélio Laranjeiro * @param[in] pkts 1044230189d9SNélio Laranjeiro * Packets to transmit. 1045230189d9SNélio Laranjeiro * @param pkts_n 1046230189d9SNélio Laranjeiro * Number of packets in array. 1047230189d9SNélio Laranjeiro * 1048230189d9SNélio Laranjeiro * @return 1049230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1050230189d9SNélio Laranjeiro */ 1051230189d9SNélio Laranjeiro uint16_t 1052230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1053230189d9SNélio Laranjeiro uint16_t pkts_n) 1054230189d9SNélio Laranjeiro { 1055991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 1056230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 10578c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 10588c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 1059c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1060a5bf6af9SAdrien Mazarguil unsigned int j = 0; 10618c819a69SYongseok Koh uint16_t max_elts; 1062f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1063230189d9SNélio Laranjeiro unsigned int comp; 10640e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1065230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1066230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1067230189d9SNélio Laranjeiro }; 1068f04f1d51SNélio Laranjeiro /* 1069f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1070f04f1d51SNélio Laranjeiro * code. 1071f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1072f04f1d51SNélio Laranjeiro * - 1 control segment, 1073f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1074f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1075f04f1d51SNélio Laranjeiro */ 1076f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1077f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1078f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1079f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1080230189d9SNélio Laranjeiro 1081c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1082c3d62cc9SAdrien Mazarguil return 0; 1083230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1084fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1085fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1086230189d9SNélio Laranjeiro /* Start processing. */ 10876cb559d6SYongseok Koh mlx5_tx_complete(txq); 10888c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 10892eefbec5SYongseok Koh /* A CQE slot must always be available. */ 10902eefbec5SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 1091c3d62cc9SAdrien Mazarguil do { 1092a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1093230189d9SNélio Laranjeiro uintptr_t addr; 1094230189d9SNélio Laranjeiro uint32_t length; 1095a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 10964aa15eb1SNélio Laranjeiro uint8_t cs_flags; 1097230189d9SNélio Laranjeiro 1098c3d62cc9SAdrien Mazarguil /* 1099c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1100c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1101c3d62cc9SAdrien Mazarguil */ 1102a5bf6af9SAdrien Mazarguil assert(segs_n); 11038c819a69SYongseok Koh if (max_elts < segs_n) 1104c3d62cc9SAdrien Mazarguil break; 1105a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 110624c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 110724c14430SShahaf Shuler txq->stats.oerrors++; 1108a5bf6af9SAdrien Mazarguil break; 110924c14430SShahaf Shuler } 11108c819a69SYongseok Koh max_elts -= segs_n; 1111c3d62cc9SAdrien Mazarguil --pkts_n; 1112f04f1d51SNélio Laranjeiro /* 1113f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1114f04f1d51SNélio Laranjeiro * iteration. 1115f04f1d51SNélio Laranjeiro */ 1116f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 11174aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 1118a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1119a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1120230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1121230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1122230189d9SNélio Laranjeiro if ((mpw.len != length) || 1123a5bf6af9SAdrien Mazarguil (segs_n != 1) || 11248688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1125230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1126230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1127230189d9SNélio Laranjeiro if ((mpw.len != length) || 1128a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1129230189d9SNélio Laranjeiro (length > inline_room) || 11308688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1131230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 11320e8679fcSNélio Laranjeiro inline_room = 11330e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1134230189d9SNélio Laranjeiro } 1135230189d9SNélio Laranjeiro } 1136230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1137a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1138a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1139f04f1d51SNélio Laranjeiro /* 1140f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1141f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1142f04f1d51SNélio Laranjeiro * such resources. 1143f04f1d51SNélio Laranjeiro */ 1144f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1145f04f1d51SNélio Laranjeiro break; 1146f04f1d51SNélio Laranjeiro max_wqe -= 2; 1147230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 11488688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1149230189d9SNélio Laranjeiro } else { 1150f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1151f04f1d51SNélio Laranjeiro break; 1152f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1153230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 11548688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1155230189d9SNélio Laranjeiro } 1156230189d9SNélio Laranjeiro } 1157a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1158a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1159230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 11600e8679fcSNélio Laranjeiro assert(inline_room == 11610e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1162a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1163a5bf6af9SAdrien Mazarguil length = 0; 1164a5bf6af9SAdrien Mazarguil #endif 1165a5bf6af9SAdrien Mazarguil do { 1166230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1167230189d9SNélio Laranjeiro 1168a5bf6af9SAdrien Mazarguil assert(buf); 11698c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1170230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1171a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1172230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 11736b30a6a8SShachar Beiser .byte_count = 11746b30a6a8SShachar Beiser rte_cpu_to_be_32(DATA_LEN(buf)), 11756cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 11766b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 1177230189d9SNélio Laranjeiro }; 1178a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1179a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1180a5bf6af9SAdrien Mazarguil #endif 1181a5bf6af9SAdrien Mazarguil buf = buf->next; 1182230189d9SNélio Laranjeiro ++mpw.pkts_n; 1183a5bf6af9SAdrien Mazarguil ++j; 1184a5bf6af9SAdrien Mazarguil } while (--segs_n); 1185a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1186230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1187230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1188230189d9SNélio Laranjeiro } else { 1189230189d9SNélio Laranjeiro unsigned int max; 1190230189d9SNélio Laranjeiro 1191230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1192230189d9SNélio Laranjeiro assert(length <= inline_room); 1193a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1194a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 11958c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1196230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1197fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1198fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1199fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1200230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1201230189d9SNélio Laranjeiro if (length > max) { 1202230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1203230189d9SNélio Laranjeiro (void *)addr, 1204230189d9SNélio Laranjeiro max); 1205fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1206230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1207230189d9SNélio Laranjeiro (void *)(addr + max), 1208230189d9SNélio Laranjeiro length - max); 1209230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1210230189d9SNélio Laranjeiro } else { 1211230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1212230189d9SNélio Laranjeiro (void *)addr, 1213230189d9SNélio Laranjeiro length); 121416c64768SYongseok Koh 121516c64768SYongseok Koh if (length == max) 121616c64768SYongseok Koh mpw.data.raw = 121716c64768SYongseok Koh (volatile void *)txq->wqes; 121816c64768SYongseok Koh else 1219230189d9SNélio Laranjeiro mpw.data.raw += length; 1220230189d9SNélio Laranjeiro } 1221230189d9SNélio Laranjeiro ++mpw.pkts_n; 122276bf1574SYongseok Koh mpw.total_len += length; 1223a5bf6af9SAdrien Mazarguil ++j; 1224230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1225230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 12260e8679fcSNélio Laranjeiro inline_room = 12270e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1228230189d9SNélio Laranjeiro } else { 1229230189d9SNélio Laranjeiro inline_room -= length; 1230230189d9SNélio Laranjeiro } 1231230189d9SNélio Laranjeiro } 1232230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1233230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1234230189d9SNélio Laranjeiro txq->stats.obytes += length; 1235230189d9SNélio Laranjeiro #endif 1236c3d62cc9SAdrien Mazarguil ++i; 1237c3d62cc9SAdrien Mazarguil } while (pkts_n); 1238230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1239230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1240230189d9SNélio Laranjeiro return 0; 1241230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1242a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1243a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1244230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 12458688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1246230189d9SNélio Laranjeiro 1247230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 12486b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 1249230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 12508688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1251230189d9SNélio Laranjeiro txq->elts_comp = 0; 12522eefbec5SYongseok Koh #ifndef NDEBUG 12532eefbec5SYongseok Koh ++txq->cq_pi; 12542eefbec5SYongseok Koh #endif 1255230189d9SNélio Laranjeiro } else { 1256230189d9SNélio Laranjeiro txq->elts_comp = comp; 1257230189d9SNélio Laranjeiro } 1258230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1259230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1260230189d9SNélio Laranjeiro txq->stats.opackets += i; 1261230189d9SNélio Laranjeiro #endif 1262230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1263230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1264230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1265230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1266230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 126730807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1268230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1269230189d9SNélio Laranjeiro return i; 1270230189d9SNélio Laranjeiro } 1271230189d9SNélio Laranjeiro 1272230189d9SNélio Laranjeiro /** 12736ce84bd8SYongseok Koh * Open an Enhanced MPW session. 12746ce84bd8SYongseok Koh * 12756ce84bd8SYongseok Koh * @param txq 12766ce84bd8SYongseok Koh * Pointer to TX queue structure. 12776ce84bd8SYongseok Koh * @param mpw 12786ce84bd8SYongseok Koh * Pointer to MPW session structure. 12796ce84bd8SYongseok Koh * @param length 12806ce84bd8SYongseok Koh * Packet length. 12816ce84bd8SYongseok Koh */ 12826ce84bd8SYongseok Koh static inline void 1283991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding) 12846ce84bd8SYongseok Koh { 12856ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 12866ce84bd8SYongseok Koh 12876ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 12886ce84bd8SYongseok Koh mpw->pkts_n = 0; 12896ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 12906ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 12916b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = 12926b30a6a8SShachar Beiser rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 12936ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 12946ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 12956ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 12966ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 12976ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 12986ce84bd8SYongseok Koh if (unlikely(padding)) { 12996ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 13006ce84bd8SYongseok Koh 13016ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 13026b30a6a8SShachar Beiser *(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG); 13036ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 13046b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_INLINE_SEG); 13056ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 13066ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 13076ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 13086ce84bd8SYongseok Koh } else { 13096ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 13106ce84bd8SYongseok Koh } 13116ce84bd8SYongseok Koh } 13126ce84bd8SYongseok Koh 13136ce84bd8SYongseok Koh /** 13146ce84bd8SYongseok Koh * Close an Enhanced MPW session. 13156ce84bd8SYongseok Koh * 13166ce84bd8SYongseok Koh * @param txq 13176ce84bd8SYongseok Koh * Pointer to TX queue structure. 13186ce84bd8SYongseok Koh * @param mpw 13196ce84bd8SYongseok Koh * Pointer to MPW session structure. 13206ce84bd8SYongseok Koh * 13216ce84bd8SYongseok Koh * @return 13226ce84bd8SYongseok Koh * Number of consumed WQEs. 13236ce84bd8SYongseok Koh */ 13246ce84bd8SYongseok Koh static inline uint16_t 1325991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 13266ce84bd8SYongseok Koh { 13276ce84bd8SYongseok Koh uint16_t ret; 13286ce84bd8SYongseok Koh 13296ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 13306ce84bd8SYongseok Koh * count as 2. 13316ce84bd8SYongseok Koh */ 13326b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 13336b30a6a8SShachar Beiser MLX5_WQE_DS(mpw->total_len)); 13346ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 13356ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 13366ce84bd8SYongseok Koh txq->wqe_ci += ret; 13376ce84bd8SYongseok Koh return ret; 13386ce84bd8SYongseok Koh } 13396ce84bd8SYongseok Koh 13406ce84bd8SYongseok Koh /** 13414b0d7b7fSYongseok Koh * TX with Enhanced MPW support. 13426ce84bd8SYongseok Koh * 13434b0d7b7fSYongseok Koh * @param txq 13444b0d7b7fSYongseok Koh * Pointer to TX queue structure. 13456ce84bd8SYongseok Koh * @param[in] pkts 13466ce84bd8SYongseok Koh * Packets to transmit. 13476ce84bd8SYongseok Koh * @param pkts_n 13486ce84bd8SYongseok Koh * Number of packets in array. 13496ce84bd8SYongseok Koh * 13506ce84bd8SYongseok Koh * @return 13516ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 13526ce84bd8SYongseok Koh */ 13534b0d7b7fSYongseok Koh static inline uint16_t 13544b0d7b7fSYongseok Koh txq_burst_empw(struct mlx5_txq_data *txq, struct rte_mbuf **pkts, 13554b0d7b7fSYongseok Koh uint16_t pkts_n) 13566ce84bd8SYongseok Koh { 13576ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 13588c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 13598c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 13606ce84bd8SYongseok Koh unsigned int i = 0; 13616ce84bd8SYongseok Koh unsigned int j = 0; 13628c819a69SYongseok Koh uint16_t max_elts; 13636ce84bd8SYongseok Koh uint16_t max_wqe; 13646ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 13656ce84bd8SYongseok Koh unsigned int mpw_room = 0; 13666ce84bd8SYongseok Koh unsigned int inl_pad = 0; 13676ce84bd8SYongseok Koh uint32_t inl_hdr; 13686ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 13696ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 13706ce84bd8SYongseok Koh }; 13716ce84bd8SYongseok Koh 13726ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 13736ce84bd8SYongseok Koh return 0; 13746ce84bd8SYongseok Koh /* Start processing. */ 13756cb559d6SYongseok Koh mlx5_tx_complete(txq); 13766ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 13776ce84bd8SYongseok Koh /* A CQE slot must always be available. */ 13786ce84bd8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 13796ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 13806ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 13816ce84bd8SYongseok Koh return 0; 13826ce84bd8SYongseok Koh do { 13836ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 13846ce84bd8SYongseok Koh uintptr_t addr; 13856ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 13866ce84bd8SYongseok Koh uint32_t length; 13874aa15eb1SNélio Laranjeiro uint8_t cs_flags; 13886ce84bd8SYongseok Koh 138948642ec5SYongseok Koh /* Multi-segmented packet is handled in slow-path outside. */ 139048642ec5SYongseok Koh assert(NB_SEGS(buf) == 1); 139148642ec5SYongseok Koh /* Make sure there is enough room to store this packet. */ 139248642ec5SYongseok Koh if (max_elts - j == 0) 13936ce84bd8SYongseok Koh break; 13944aa15eb1SNélio Laranjeiro cs_flags = txq_ol_cksum_to_cs(txq, buf); 13956ce84bd8SYongseok Koh /* Retrieve packet information. */ 13966ce84bd8SYongseok Koh length = PKT_LEN(buf); 13976ce84bd8SYongseok Koh /* Start new session if: 13986ce84bd8SYongseok Koh * - multi-segment packet 13996ce84bd8SYongseok Koh * - no space left even for a dseg 14006ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 14016ce84bd8SYongseok Koh * - cs_flag differs 14026ce84bd8SYongseok Koh */ 14036ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 140448642ec5SYongseok Koh if ((inl_pad + sizeof(struct mlx5_wqe_data_seg) > 14056ce84bd8SYongseok Koh mpw_room) || 14066ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 14076ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 14086ce84bd8SYongseok Koh mpw_room) || 14096ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 14106ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 14116ce84bd8SYongseok Koh } 14126ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 141348642ec5SYongseok Koh /* In Enhanced MPW, inline as much as the budget is 141448642ec5SYongseok Koh * allowed. The remaining space is to be filled with 141548642ec5SYongseok Koh * dsegs. If the title WQEBB isn't padded, it will have 141648642ec5SYongseok Koh * 2 dsegs there. 14176ce84bd8SYongseok Koh */ 14186ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 14196ce84bd8SYongseok Koh (max_inline ? max_inline : 14206ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 14216ce84bd8SYongseok Koh MLX5_WQE_SIZE); 142248642ec5SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < mpw_room)) 14236ce84bd8SYongseok Koh break; 14246ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 14256ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 14266ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 14276ce84bd8SYongseok Koh inl_pad = 0; 142848642ec5SYongseok Koh do_inline = length <= txq->inline_max_packet_sz && 14296ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 14306ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 14316ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 14326ce84bd8SYongseok Koh } else { 14336ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 14346ce84bd8SYongseok Koh * Inlininig is possible when: 14356ce84bd8SYongseok Koh * - length is less than configured value 14366ce84bd8SYongseok Koh * - length fits for remaining space 14376ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 14386ce84bd8SYongseok Koh */ 14396ce84bd8SYongseok Koh do_inline = 14406ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 14416ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 14426ce84bd8SYongseok Koh mpw_room && 14436ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 14446ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 14456ce84bd8SYongseok Koh } 144624a8f524SYongseok Koh if (max_inline && do_inline) { 14476ce84bd8SYongseok Koh /* Inline packet into WQE. */ 14486ce84bd8SYongseok Koh unsigned int max; 14496ce84bd8SYongseok Koh 14506ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14516ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14526b30a6a8SShachar Beiser inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG); 14536ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14546ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14556ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 14566ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 14576ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 14586ce84bd8SYongseok Koh /* Copy inline header. */ 14596ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14606ce84bd8SYongseok Koh mlx5_copy_to_wq( 14616ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 14626ce84bd8SYongseok Koh &inl_hdr, 14636ce84bd8SYongseok Koh sizeof(inl_hdr), 14646ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 14656ce84bd8SYongseok Koh max); 14666ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 14676ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 14686ce84bd8SYongseok Koh /* Copy packet data. */ 14696ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 14706ce84bd8SYongseok Koh mlx5_copy_to_wq( 14716ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 14726ce84bd8SYongseok Koh (void *)addr, 14736ce84bd8SYongseok Koh length, 14746ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 14756ce84bd8SYongseok Koh max); 14766ce84bd8SYongseok Koh ++mpw.pkts_n; 14776ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 14786ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 14796ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 14806ce84bd8SYongseok Koh */ 14816ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 14826ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 14836ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 14846ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 14856ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 14866ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 14876ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 14886ce84bd8SYongseok Koh } else { 14896ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 14906ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 14916ce84bd8SYongseok Koh 14926ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14936ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 14946ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14956ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 14966ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 14976ce84bd8SYongseok Koh + inl_pad))) 14986ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 14996ce84bd8SYongseok Koh else 15006ce84bd8SYongseok Koh dseg = (volatile void *) 15016ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 15026ce84bd8SYongseok Koh inl_pad); 15038c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1504f84411beSYongseok Koh addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, 1505f84411beSYongseok Koh uintptr_t)); 15066ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 15076b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 15086cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 1509ebbb81ebSNélio Laranjeiro addr, 1510ebbb81ebSNélio Laranjeiro addr >> 32, 15116ce84bd8SYongseok Koh }; 15126ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 15136ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 15146ce84bd8SYongseok Koh ++j; 15156ce84bd8SYongseok Koh ++mpw.pkts_n; 15166ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 15176ce84bd8SYongseok Koh inl_pad = 0; 15186ce84bd8SYongseok Koh } 15196ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 15206ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 15216ce84bd8SYongseok Koh txq->stats.obytes += length; 15226ce84bd8SYongseok Koh #endif 15236ce84bd8SYongseok Koh ++i; 15246ce84bd8SYongseok Koh } while (i < pkts_n); 15256ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 15266ce84bd8SYongseok Koh if (unlikely(i == 0)) 15276ce84bd8SYongseok Koh return 0; 15286ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 15296ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 15306ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 15316ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 15326ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 15336ce84bd8SYongseok Koh 15346ce84bd8SYongseok Koh /* Request completion on last WQE. */ 15356b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 15366ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 15376ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 15386ce84bd8SYongseok Koh txq->elts_comp = 0; 15396ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 15402eefbec5SYongseok Koh #ifndef NDEBUG 15412eefbec5SYongseok Koh ++txq->cq_pi; 15422eefbec5SYongseok Koh #endif 15436ce84bd8SYongseok Koh } else { 15446ce84bd8SYongseok Koh txq->elts_comp += j; 15456ce84bd8SYongseok Koh } 15466ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 15476ce84bd8SYongseok Koh /* Increment sent packets counter. */ 15486ce84bd8SYongseok Koh txq->stats.opackets += i; 15496ce84bd8SYongseok Koh #endif 15506ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 15516ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 15526ce84bd8SYongseok Koh /* Ring QP doorbell. */ 15536ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 15546ce84bd8SYongseok Koh txq->elts_head = elts_head; 15556ce84bd8SYongseok Koh return i; 15566ce84bd8SYongseok Koh } 15576ce84bd8SYongseok Koh 15586ce84bd8SYongseok Koh /** 15594b0d7b7fSYongseok Koh * DPDK callback for TX with Enhanced MPW support. 15604b0d7b7fSYongseok Koh * 15614b0d7b7fSYongseok Koh * @param dpdk_txq 15624b0d7b7fSYongseok Koh * Generic pointer to TX queue structure. 15634b0d7b7fSYongseok Koh * @param[in] pkts 15644b0d7b7fSYongseok Koh * Packets to transmit. 15654b0d7b7fSYongseok Koh * @param pkts_n 15664b0d7b7fSYongseok Koh * Number of packets in array. 15674b0d7b7fSYongseok Koh * 15684b0d7b7fSYongseok Koh * @return 15694b0d7b7fSYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 15704b0d7b7fSYongseok Koh */ 15714b0d7b7fSYongseok Koh uint16_t 15724b0d7b7fSYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 15734b0d7b7fSYongseok Koh { 15744b0d7b7fSYongseok Koh struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 15754b0d7b7fSYongseok Koh uint16_t nb_tx = 0; 15764b0d7b7fSYongseok Koh 15774b0d7b7fSYongseok Koh while (pkts_n > nb_tx) { 15784b0d7b7fSYongseok Koh uint16_t n; 15794b0d7b7fSYongseok Koh uint16_t ret; 15804b0d7b7fSYongseok Koh 15814b0d7b7fSYongseok Koh n = txq_count_contig_multi_seg(&pkts[nb_tx], pkts_n - nb_tx); 15824b0d7b7fSYongseok Koh if (n) { 15834b0d7b7fSYongseok Koh ret = mlx5_tx_burst(dpdk_txq, &pkts[nb_tx], n); 15844b0d7b7fSYongseok Koh if (!ret) 15854b0d7b7fSYongseok Koh break; 15864b0d7b7fSYongseok Koh nb_tx += ret; 15874b0d7b7fSYongseok Koh } 15884b0d7b7fSYongseok Koh n = txq_count_contig_single_seg(&pkts[nb_tx], pkts_n - nb_tx); 15894b0d7b7fSYongseok Koh if (n) { 15904b0d7b7fSYongseok Koh ret = txq_burst_empw(txq, &pkts[nb_tx], n); 15914b0d7b7fSYongseok Koh if (!ret) 15924b0d7b7fSYongseok Koh break; 15934b0d7b7fSYongseok Koh nb_tx += ret; 15944b0d7b7fSYongseok Koh } 15954b0d7b7fSYongseok Koh } 15964b0d7b7fSYongseok Koh return nb_tx; 15974b0d7b7fSYongseok Koh } 15984b0d7b7fSYongseok Koh 15994b0d7b7fSYongseok Koh /** 160067fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 160167fa62bcSAdrien Mazarguil * 16026218063bSNélio Laranjeiro * @param[in] cqe 16036218063bSNélio Laranjeiro * Pointer to CQE. 160467fa62bcSAdrien Mazarguil * 160578a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 160678a38edfSJianfeng Tan * 160767fa62bcSAdrien Mazarguil * @return 160867fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 160967fa62bcSAdrien Mazarguil */ 161067fa62bcSAdrien Mazarguil static inline uint32_t 161197267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 161267fa62bcSAdrien Mazarguil { 1613ea16068cSYongseok Koh uint8_t idx; 1614ea16068cSYongseok Koh uint8_t pinfo = cqe->pkt_info; 1615ea16068cSYongseok Koh uint16_t ptype = cqe->hdr_type_etc; 161667fa62bcSAdrien Mazarguil 1617ea16068cSYongseok Koh /* 1618ea16068cSYongseok Koh * The index to the array should have: 1619ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 1620ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 1621ea16068cSYongseok Koh * bit[5] = ip_frag 1622ea16068cSYongseok Koh * bit[6] = tunneled 1623ea16068cSYongseok Koh * bit[7] = outer_l3_type 1624ea16068cSYongseok Koh */ 1625ea16068cSYongseok Koh idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10); 1626ea16068cSYongseok Koh return mlx5_ptype_table[idx]; 162767fa62bcSAdrien Mazarguil } 162867fa62bcSAdrien Mazarguil 162967fa62bcSAdrien Mazarguil /** 163099c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 163199c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 163299c12dccSNélio Laranjeiro * been processed. 163399c12dccSNélio Laranjeiro * 163499c12dccSNélio Laranjeiro * @param rxq 163599c12dccSNélio Laranjeiro * Pointer to RX queue. 163699c12dccSNélio Laranjeiro * @param cqe 163799c12dccSNélio Laranjeiro * CQE to process. 1638ecf60761SNélio Laranjeiro * @param[out] rss_hash 1639ecf60761SNélio Laranjeiro * Packet RSS Hash result. 164099c12dccSNélio Laranjeiro * 164199c12dccSNélio Laranjeiro * @return 164299c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 164399c12dccSNélio Laranjeiro * with error. 164499c12dccSNélio Laranjeiro */ 164599c12dccSNélio Laranjeiro static inline int 164678142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 1647ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 164899c12dccSNélio Laranjeiro { 164999c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 165099c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 165199c12dccSNélio Laranjeiro int len = 0; 1652d2e842d0SYongseok Koh uint16_t idx, end; 165399c12dccSNélio Laranjeiro 165499c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 165599c12dccSNélio Laranjeiro if (zip->ai) { 165699c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 165799c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 16584aff4bcbSYongseok Koh (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info); 165999c12dccSNélio Laranjeiro 16606b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt); 16616b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[zip->ai & 7].rx_hash_result); 166299c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1663d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1664d2e842d0SYongseok Koh idx = zip->ca; 1665d2e842d0SYongseok Koh end = zip->na; 1666d2e842d0SYongseok Koh while (idx != end) { 1667d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1668d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1669d2e842d0SYongseok Koh ++idx; 1670d2e842d0SYongseok Koh } 167199c12dccSNélio Laranjeiro /* 167299c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 167399c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 167499c12dccSNélio Laranjeiro * ring for software use. 167599c12dccSNélio Laranjeiro */ 167699c12dccSNélio Laranjeiro zip->ca = zip->na; 167799c12dccSNélio Laranjeiro zip->na += 8; 167899c12dccSNélio Laranjeiro } 167999c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1680d2e842d0SYongseok Koh /* Invalidate the rest */ 1681d2e842d0SYongseok Koh idx = zip->ca; 1682d2e842d0SYongseok Koh end = zip->cq_ci; 168399c12dccSNélio Laranjeiro 168499c12dccSNélio Laranjeiro while (idx != end) { 168597267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 168699c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 168799c12dccSNélio Laranjeiro ++idx; 168899c12dccSNélio Laranjeiro } 168999c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 169099c12dccSNélio Laranjeiro zip->ai = 0; 169199c12dccSNélio Laranjeiro } 169299c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 169399c12dccSNélio Laranjeiro } else { 169499c12dccSNélio Laranjeiro int ret; 169599c12dccSNélio Laranjeiro int8_t op_own; 169699c12dccSNélio Laranjeiro 169797267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 169899c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 169999c12dccSNélio Laranjeiro return 0; 170099c12dccSNélio Laranjeiro ++rxq->cq_ci; 170199c12dccSNélio Laranjeiro op_own = cqe->op_own; 17021742c2d9SYongseok Koh rte_cio_rmb(); 170399c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 170499c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 170599c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 170699c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 17074aff4bcbSYongseok Koh cqe_cnt].pkt_info); 170899c12dccSNélio Laranjeiro 170999c12dccSNélio Laranjeiro /* Fix endianness. */ 17106b30a6a8SShachar Beiser zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt); 171199c12dccSNélio Laranjeiro /* 171299c12dccSNélio Laranjeiro * Current mini array position is the one returned by 171399c12dccSNélio Laranjeiro * check_cqe64(). 171499c12dccSNélio Laranjeiro * 171599c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 171699c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 171799c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 171899c12dccSNélio Laranjeiro */ 1719d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 172099c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 172199c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 172299c12dccSNélio Laranjeiro --rxq->cq_ci; 172399c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 172499c12dccSNélio Laranjeiro /* Get packet size to return. */ 17256b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[0].byte_cnt); 17266b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32((*mc)[0].rx_hash_result); 172799c12dccSNélio Laranjeiro zip->ai = 1; 1728d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1729d2e842d0SYongseok Koh idx = zip->ca; 1730d2e842d0SYongseok Koh end = zip->cq_ci; 1731d2e842d0SYongseok Koh while (idx != end) { 1732d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1733d2e842d0SYongseok Koh ++idx; 1734d2e842d0SYongseok Koh } 173599c12dccSNélio Laranjeiro } else { 17366b30a6a8SShachar Beiser len = rte_be_to_cpu_32(cqe->byte_cnt); 17376b30a6a8SShachar Beiser *rss_hash = rte_be_to_cpu_32(cqe->rx_hash_res); 173899c12dccSNélio Laranjeiro } 173999c12dccSNélio Laranjeiro /* Error while receiving packet. */ 174099c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 174199c12dccSNélio Laranjeiro return -1; 174299c12dccSNélio Laranjeiro } 174399c12dccSNélio Laranjeiro return len; 174499c12dccSNélio Laranjeiro } 174599c12dccSNélio Laranjeiro 174699c12dccSNélio Laranjeiro /** 174767fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 174867fa62bcSAdrien Mazarguil * 174967fa62bcSAdrien Mazarguil * @param[in] rxq 175067fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 17516218063bSNélio Laranjeiro * @param[in] cqe 17526218063bSNélio Laranjeiro * Pointer to CQE. 175367fa62bcSAdrien Mazarguil * 175467fa62bcSAdrien Mazarguil * @return 175567fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 175667fa62bcSAdrien Mazarguil */ 175767fa62bcSAdrien Mazarguil static inline uint32_t 175878142aacSNélio Laranjeiro rxq_cq_to_ol_flags(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe) 175967fa62bcSAdrien Mazarguil { 176067fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 17616b30a6a8SShachar Beiser uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 176267fa62bcSAdrien Mazarguil 17630603df73SNélio Laranjeiro ol_flags = 17640603df73SNélio Laranjeiro TRANSPOSE(flags, 17650603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 17660603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17670603df73SNélio Laranjeiro TRANSPOSE(flags, 17680603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 176983e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 177097267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 177167fa62bcSAdrien Mazarguil ol_flags |= 17720603df73SNélio Laranjeiro TRANSPOSE(flags, 17730603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 177483e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 17750603df73SNélio Laranjeiro TRANSPOSE(flags, 17760603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 177783e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 177867fa62bcSAdrien Mazarguil return ol_flags; 177967fa62bcSAdrien Mazarguil } 178067fa62bcSAdrien Mazarguil 178167fa62bcSAdrien Mazarguil /** 17822e22920bSAdrien Mazarguil * DPDK callback for RX. 17832e22920bSAdrien Mazarguil * 17842e22920bSAdrien Mazarguil * @param dpdk_rxq 17852e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 17862e22920bSAdrien Mazarguil * @param[out] pkts 17872e22920bSAdrien Mazarguil * Array to store received packets. 17882e22920bSAdrien Mazarguil * @param pkts_n 17892e22920bSAdrien Mazarguil * Maximum number of packets in array. 17902e22920bSAdrien Mazarguil * 17912e22920bSAdrien Mazarguil * @return 17922e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 17932e22920bSAdrien Mazarguil */ 17942e22920bSAdrien Mazarguil uint16_t 17952e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 17962e22920bSAdrien Mazarguil { 179778142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = dpdk_rxq; 1798b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1799e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 18009964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 18019964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 18029964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 180397267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 180497267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 18059964b965SNélio Laranjeiro unsigned int i = 0; 18069964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 18074e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 18082e22920bSAdrien Mazarguil 18099964b965SNélio Laranjeiro while (pkts_n) { 18109964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 18119964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 18129964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1813ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 18149964b965SNélio Laranjeiro 18159964b965SNélio Laranjeiro if (pkt) 18169964b965SNélio Laranjeiro NEXT(seg) = rep; 18179964b965SNélio Laranjeiro seg = rep; 18189964b965SNélio Laranjeiro rte_prefetch0(seg); 18196218063bSNélio Laranjeiro rte_prefetch0(cqe); 18209964b965SNélio Laranjeiro rte_prefetch0(wqe); 1821fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 18222e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 182315a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 182415a756b6SSagi Grimberg if (!pkt) { 182515a756b6SSagi Grimberg /* 182615a756b6SSagi Grimberg * no buffers before we even started, 182715a756b6SSagi Grimberg * bail out silently. 182815a756b6SSagi Grimberg */ 182915a756b6SSagi Grimberg break; 183015a756b6SSagi Grimberg } 1831a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1832a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1833fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 18348f094a9aSOlivier Matz NEXT(pkt) = NULL; 18358f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 18361f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 1837fe5fe382SNélio Laranjeiro pkt = rep; 18389964b965SNélio Laranjeiro } 18396218063bSNélio Laranjeiro break; 18402e22920bSAdrien Mazarguil } 18419964b965SNélio Laranjeiro if (!pkt) { 184297267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1843ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1844ecf60761SNélio Laranjeiro &rss_hash_res); 1845ecf60761SNélio Laranjeiro if (!len) { 18461f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 18476218063bSNélio Laranjeiro break; 18486218063bSNélio Laranjeiro } 184999c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 185099c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 18511f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 185299c12dccSNélio Laranjeiro ++rxq->stats.idropped; 185399c12dccSNélio Laranjeiro goto skip; 185499c12dccSNélio Laranjeiro } 18559964b965SNélio Laranjeiro pkt = seg; 18569964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 18579964b965SNélio Laranjeiro /* Update packet information. */ 185848dfc20fSYongseok Koh pkt->packet_type = rxq_cq_to_pkt_type(cqe); 18590ac64846SMaxime Leroy pkt->ol_flags = 0; 186036ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1861ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1862ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1863ecf60761SNélio Laranjeiro } 1864c604f619SNélio Laranjeiro if (rxq->mark && 1865c604f619SNélio Laranjeiro MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 1866b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 1867b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 18686b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) { 1869b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 1870b268a3eeSNélio Laranjeiro 1871b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 1872ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1873b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 1874b268a3eeSNélio Laranjeiro } 1875ea3bc3b1SNélio Laranjeiro } 187648dfc20fSYongseok Koh if (rxq->csum | rxq->csum_l2tun) 18776703d836SNélio Laranjeiro pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe); 18786703d836SNélio Laranjeiro if (rxq->vlan_strip && 18796703d836SNélio Laranjeiro (cqe->hdr_type_etc & 18806b30a6a8SShachar Beiser rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) { 1881380a7aabSOlivier Matz pkt->ol_flags |= PKT_RX_VLAN | 1882b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 18836b30a6a8SShachar Beiser pkt->vlan_tci = 18846b30a6a8SShachar Beiser rte_be_to_cpu_16(cqe->vlan_info); 1885f3db9489SYaacov Hazan } 188678c7406bSRaslan Darawsheh if (rxq->hw_timestamp) { 188778c7406bSRaslan Darawsheh pkt->timestamp = 188878c7406bSRaslan Darawsheh rte_be_to_cpu_64(cqe->timestamp); 188978c7406bSRaslan Darawsheh pkt->ol_flags |= PKT_RX_TIMESTAMP; 189078c7406bSRaslan Darawsheh } 18916218063bSNélio Laranjeiro if (rxq->crc_present) 18926218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 18936218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 18949964b965SNélio Laranjeiro } 18959964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 18969964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 18979964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 18989964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 18999964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 19009964b965SNélio Laranjeiro /* 19019964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 19029964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 19039964b965SNélio Laranjeiro * changes. 19049964b965SNélio Laranjeiro */ 19056b30a6a8SShachar Beiser wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 19069964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 19079964b965SNélio Laranjeiro len -= DATA_LEN(seg); 19089964b965SNélio Laranjeiro ++NB_SEGS(pkt); 19099964b965SNélio Laranjeiro ++rq_ci; 19109964b965SNélio Laranjeiro continue; 19119964b965SNélio Laranjeiro } 19129964b965SNélio Laranjeiro DATA_LEN(seg) = len; 191387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 191487011737SAdrien Mazarguil /* Increment bytes counter. */ 19159964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 191687011737SAdrien Mazarguil #endif 19176218063bSNélio Laranjeiro /* Return packet. */ 19186218063bSNélio Laranjeiro *(pkts++) = pkt; 19199964b965SNélio Laranjeiro pkt = NULL; 19209964b965SNélio Laranjeiro --pkts_n; 19219964b965SNélio Laranjeiro ++i; 192299c12dccSNélio Laranjeiro skip: 19239964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 19249964b965SNélio Laranjeiro rq_ci >>= sges_n; 19256218063bSNélio Laranjeiro ++rq_ci; 19269964b965SNélio Laranjeiro rq_ci <<= sges_n; 19272e22920bSAdrien Mazarguil } 19289964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 19292e22920bSAdrien Mazarguil return 0; 19306218063bSNélio Laranjeiro /* Update the consumer index. */ 19319964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 19324fe7f662SYongseok Koh rte_cio_wmb(); 19336b30a6a8SShachar Beiser *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 19344fe7f662SYongseok Koh rte_cio_wmb(); 19356b30a6a8SShachar Beiser *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 193687011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 193787011737SAdrien Mazarguil /* Increment packets counter. */ 19389964b965SNélio Laranjeiro rxq->stats.ipackets += i; 193987011737SAdrien Mazarguil #endif 19409964b965SNélio Laranjeiro return i; 19412e22920bSAdrien Mazarguil } 19422e22920bSAdrien Mazarguil 19432e22920bSAdrien Mazarguil /** 19442e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 19452e22920bSAdrien Mazarguil * 19462e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19472e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19482e22920bSAdrien Mazarguil * 19492e22920bSAdrien Mazarguil * @param dpdk_txq 19502e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 19512e22920bSAdrien Mazarguil * @param[in] pkts 19522e22920bSAdrien Mazarguil * Packets to transmit. 19532e22920bSAdrien Mazarguil * @param pkts_n 19542e22920bSAdrien Mazarguil * Number of packets in array. 19552e22920bSAdrien Mazarguil * 19562e22920bSAdrien Mazarguil * @return 19572e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 19582e22920bSAdrien Mazarguil */ 19592e22920bSAdrien Mazarguil uint16_t 196056f08e16SNélio Laranjeiro removed_tx_burst(void *dpdk_txq __rte_unused, 196156f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 196256f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 19632e22920bSAdrien Mazarguil { 19642e22920bSAdrien Mazarguil return 0; 19652e22920bSAdrien Mazarguil } 19662e22920bSAdrien Mazarguil 19672e22920bSAdrien Mazarguil /** 19682e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 19692e22920bSAdrien Mazarguil * 19702e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 19712e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 19722e22920bSAdrien Mazarguil * 19732e22920bSAdrien Mazarguil * @param dpdk_rxq 19742e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 19752e22920bSAdrien Mazarguil * @param[out] pkts 19762e22920bSAdrien Mazarguil * Array to store received packets. 19772e22920bSAdrien Mazarguil * @param pkts_n 19782e22920bSAdrien Mazarguil * Maximum number of packets in array. 19792e22920bSAdrien Mazarguil * 19802e22920bSAdrien Mazarguil * @return 19812e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 19822e22920bSAdrien Mazarguil */ 19832e22920bSAdrien Mazarguil uint16_t 198456f08e16SNélio Laranjeiro removed_rx_burst(void *dpdk_txq __rte_unused, 198556f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 198656f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 19872e22920bSAdrien Mazarguil { 19882e22920bSAdrien Mazarguil return 0; 19892e22920bSAdrien Mazarguil } 19906cb559d6SYongseok Koh 19916cb559d6SYongseok Koh /* 19926cb559d6SYongseok Koh * Vectorized Rx/Tx routines are not compiled in when required vector 19936cb559d6SYongseok Koh * instructions are not supported on a target architecture. The following null 19946cb559d6SYongseok Koh * stubs are needed for linkage when those are not included outside of this file 19956cb559d6SYongseok Koh * (e.g. mlx5_rxtx_vec_sse.c for x86). 19966cb559d6SYongseok Koh */ 19976cb559d6SYongseok Koh 19986cb559d6SYongseok Koh uint16_t __attribute__((weak)) 199956f08e16SNélio Laranjeiro mlx5_tx_burst_raw_vec(void *dpdk_txq __rte_unused, 200056f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 200156f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 20026cb559d6SYongseok Koh { 20036cb559d6SYongseok Koh return 0; 20046cb559d6SYongseok Koh } 20056cb559d6SYongseok Koh 20066cb559d6SYongseok Koh uint16_t __attribute__((weak)) 200756f08e16SNélio Laranjeiro mlx5_tx_burst_vec(void *dpdk_txq __rte_unused, 200856f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 200956f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 20106cb559d6SYongseok Koh { 20116cb559d6SYongseok Koh return 0; 20126cb559d6SYongseok Koh } 20136cb559d6SYongseok Koh 20146cb559d6SYongseok Koh uint16_t __attribute__((weak)) 201556f08e16SNélio Laranjeiro mlx5_rx_burst_vec(void *dpdk_txq __rte_unused, 201656f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 201756f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 20186cb559d6SYongseok Koh { 20196cb559d6SYongseok Koh return 0; 20206cb559d6SYongseok Koh } 20216cb559d6SYongseok Koh 20226cb559d6SYongseok Koh int __attribute__((weak)) 2023af4f09f2SNélio Laranjeiro mlx5_check_raw_vec_tx_support(struct rte_eth_dev *dev __rte_unused) 20246cb559d6SYongseok Koh { 20256cb559d6SYongseok Koh return -ENOTSUP; 20266cb559d6SYongseok Koh } 20276cb559d6SYongseok Koh 20286cb559d6SYongseok Koh int __attribute__((weak)) 2029af4f09f2SNélio Laranjeiro mlx5_check_vec_tx_support(struct rte_eth_dev *dev __rte_unused) 20306cb559d6SYongseok Koh { 20316cb559d6SYongseok Koh return -ENOTSUP; 20326cb559d6SYongseok Koh } 20336cb559d6SYongseok Koh 20346cb559d6SYongseok Koh int __attribute__((weak)) 2035af4f09f2SNélio Laranjeiro mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused) 20366cb559d6SYongseok Koh { 20376cb559d6SYongseok Koh return -ENOTSUP; 20386cb559d6SYongseok Koh } 20396cb559d6SYongseok Koh 20406cb559d6SYongseok Koh int __attribute__((weak)) 2041af4f09f2SNélio Laranjeiro mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused) 20426cb559d6SYongseok Koh { 20436cb559d6SYongseok Koh return -ENOTSUP; 20446cb559d6SYongseok Koh } 2045