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 373cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, 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, 412e633f1fSYongseok Koh uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe); 42ff1807a3SNélio Laranjeiro 43c0583d98SJerin Jacob static __rte_always_inline uint32_t 446ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe); 45ff1807a3SNélio Laranjeiro 463e1f82a1SYongseok Koh static __rte_always_inline void 473e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 483e1f82a1SYongseok Koh volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res); 493e1f82a1SYongseok Koh 507d6bf6b8SYongseok Koh static __rte_always_inline void 517d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx); 527d6bf6b8SYongseok Koh 53ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = { 54ea16068cSYongseok Koh [0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */ 55ea16068cSYongseok Koh }; 56ea16068cSYongseok Koh 575f8ba81cSXueming Li uint8_t mlx5_cksum_table[1 << 10] __rte_cache_aligned; 585f8ba81cSXueming Li uint8_t mlx5_swp_types_table[1 << 10] __rte_cache_aligned; 595f8ba81cSXueming Li 60ea16068cSYongseok Koh /** 61ea16068cSYongseok Koh * Build a table to translate Rx completion flags to packet type. 62ea16068cSYongseok Koh * 63ea16068cSYongseok Koh * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 64ea16068cSYongseok Koh */ 65ea16068cSYongseok Koh void 66ea16068cSYongseok Koh mlx5_set_ptype_table(void) 67ea16068cSYongseok Koh { 68ea16068cSYongseok Koh unsigned int i; 69ea16068cSYongseok Koh uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table; 70ea16068cSYongseok Koh 719807f113SYongseok Koh /* Last entry must not be overwritten, reserved for errored packet. */ 729807f113SYongseok Koh for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i) 73ea16068cSYongseok Koh (*p)[i] = RTE_PTYPE_UNKNOWN; 746cb559d6SYongseok Koh /* 756cb559d6SYongseok Koh * The index to the array should have: 76ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 77ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 78ea16068cSYongseok Koh * bit[5] = ip_frag 79ea16068cSYongseok Koh * bit[6] = tunneled 80ea16068cSYongseok Koh * bit[7] = outer_l3_type 8199c12dccSNélio Laranjeiro */ 823ca63b88SShahaf Shuler /* L2 */ 833ca63b88SShahaf Shuler (*p)[0x00] = RTE_PTYPE_L2_ETHER; 84ea16068cSYongseok Koh /* L3 */ 85ea16068cSYongseok Koh (*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 86ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 87ea16068cSYongseok Koh (*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 88ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 89ea16068cSYongseok Koh /* Fragmented */ 90ea16068cSYongseok Koh (*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 91ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 92ea16068cSYongseok Koh (*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 93ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 94ea16068cSYongseok Koh /* TCP */ 95ea16068cSYongseok Koh (*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 96ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 97ea16068cSYongseok Koh (*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 98ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 990915e287SBin Huang (*p)[0x0d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1000915e287SBin Huang RTE_PTYPE_L4_TCP; 1010915e287SBin Huang (*p)[0x0e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1020915e287SBin Huang RTE_PTYPE_L4_TCP; 1030915e287SBin Huang (*p)[0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1040915e287SBin Huang RTE_PTYPE_L4_TCP; 1050915e287SBin Huang (*p)[0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1060915e287SBin Huang RTE_PTYPE_L4_TCP; 107ea16068cSYongseok Koh /* UDP */ 108ea16068cSYongseok Koh (*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 109ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 110ea16068cSYongseok Koh (*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 111ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 112ea16068cSYongseok Koh /* Repeat with outer_l3_type being set. Just in case. */ 113ea16068cSYongseok Koh (*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 114ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 115ea16068cSYongseok Koh (*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 116ea16068cSYongseok Koh RTE_PTYPE_L4_NONFRAG; 117ea16068cSYongseok Koh (*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 118ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 119ea16068cSYongseok Koh (*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 120ea16068cSYongseok Koh RTE_PTYPE_L4_FRAG; 121ea16068cSYongseok Koh (*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 122ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 123ea16068cSYongseok Koh (*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 124ea16068cSYongseok Koh RTE_PTYPE_L4_TCP; 1250915e287SBin Huang (*p)[0x8d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1260915e287SBin Huang RTE_PTYPE_L4_TCP; 1270915e287SBin Huang (*p)[0x8e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1280915e287SBin Huang RTE_PTYPE_L4_TCP; 1290915e287SBin Huang (*p)[0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1300915e287SBin Huang RTE_PTYPE_L4_TCP; 1310915e287SBin Huang (*p)[0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1320915e287SBin Huang RTE_PTYPE_L4_TCP; 133ea16068cSYongseok Koh (*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 134ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 135ea16068cSYongseok Koh (*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 136ea16068cSYongseok Koh RTE_PTYPE_L4_UDP; 137ea16068cSYongseok Koh /* Tunneled - L3 */ 1383cc08bc6SXueming Li (*p)[0x40] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN; 139ea16068cSYongseok Koh (*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 140ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 141ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 142ea16068cSYongseok Koh (*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 143ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 144ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 1453cc08bc6SXueming Li (*p)[0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN; 146ea16068cSYongseok Koh (*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 147ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 148ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 149ea16068cSYongseok Koh (*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 150ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 151ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_NONFRAG; 152ea16068cSYongseok Koh /* Tunneled - Fragmented */ 153ea16068cSYongseok Koh (*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 154ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 155ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 156ea16068cSYongseok Koh (*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 157ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 158ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 159ea16068cSYongseok Koh (*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 160ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 161ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 162ea16068cSYongseok Koh (*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 163ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 164ea16068cSYongseok Koh RTE_PTYPE_INNER_L4_FRAG; 165ea16068cSYongseok Koh /* Tunneled - TCP */ 166ea16068cSYongseok Koh (*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 167ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1686c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 169ea16068cSYongseok Koh (*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 170ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1716c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 1720915e287SBin Huang (*p)[0x4d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1730915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1740915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1750915e287SBin Huang (*p)[0x4e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1760915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1770915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1780915e287SBin Huang (*p)[0x51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1790915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1800915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1810915e287SBin Huang (*p)[0x52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 1820915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1830915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 184ea16068cSYongseok Koh (*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 185ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1866c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 187ea16068cSYongseok Koh (*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 188ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1896c897093SYongseok Koh RTE_PTYPE_INNER_L4_TCP; 1900915e287SBin Huang (*p)[0xcd] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1910915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1920915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1930915e287SBin Huang (*p)[0xce] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1940915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 1950915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1960915e287SBin Huang (*p)[0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1970915e287SBin Huang RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 1980915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 1990915e287SBin Huang (*p)[0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 2000915e287SBin Huang RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 2010915e287SBin Huang RTE_PTYPE_INNER_L4_TCP; 202ea16068cSYongseok Koh /* Tunneled - UDP */ 203ea16068cSYongseok Koh (*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 204ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 2056c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 206ea16068cSYongseok Koh (*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 207ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 2086c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 209ea16068cSYongseok Koh (*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 210ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | 2116c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 212ea16068cSYongseok Koh (*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 213ea16068cSYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | 2146c897093SYongseok Koh RTE_PTYPE_INNER_L4_UDP; 215ea16068cSYongseok Koh } 216fdcb0f53SNélio Laranjeiro 2172e22920bSAdrien Mazarguil /** 2185f8ba81cSXueming Li * Build a table to translate packet to checksum type of Verbs. 2195f8ba81cSXueming Li */ 2205f8ba81cSXueming Li void 2215f8ba81cSXueming Li mlx5_set_cksum_table(void) 2225f8ba81cSXueming Li { 2235f8ba81cSXueming Li unsigned int i; 2245f8ba81cSXueming Li uint8_t v; 2255f8ba81cSXueming Li 2265f8ba81cSXueming Li /* 2275f8ba81cSXueming Li * The index should have: 2285f8ba81cSXueming Li * bit[0] = PKT_TX_TCP_SEG 2295f8ba81cSXueming Li * bit[2:3] = PKT_TX_UDP_CKSUM, PKT_TX_TCP_CKSUM 2305f8ba81cSXueming Li * bit[4] = PKT_TX_IP_CKSUM 2315f8ba81cSXueming Li * bit[8] = PKT_TX_OUTER_IP_CKSUM 2325f8ba81cSXueming Li * bit[9] = tunnel 2335f8ba81cSXueming Li */ 2345f8ba81cSXueming Li for (i = 0; i < RTE_DIM(mlx5_cksum_table); ++i) { 2355f8ba81cSXueming Li v = 0; 2365f8ba81cSXueming Li if (i & (1 << 9)) { 2375f8ba81cSXueming Li /* Tunneled packet. */ 2385f8ba81cSXueming Li if (i & (1 << 8)) /* Outer IP. */ 2395f8ba81cSXueming Li v |= MLX5_ETH_WQE_L3_CSUM; 2405f8ba81cSXueming Li if (i & (1 << 4)) /* Inner IP. */ 2415f8ba81cSXueming Li v |= MLX5_ETH_WQE_L3_INNER_CSUM; 2425f8ba81cSXueming Li if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */ 2435f8ba81cSXueming Li v |= MLX5_ETH_WQE_L4_INNER_CSUM; 2445f8ba81cSXueming Li } else { 2455f8ba81cSXueming Li /* No tunnel. */ 2465f8ba81cSXueming Li if (i & (1 << 4)) /* IP. */ 2475f8ba81cSXueming Li v |= MLX5_ETH_WQE_L3_CSUM; 2485f8ba81cSXueming Li if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */ 2495f8ba81cSXueming Li v |= MLX5_ETH_WQE_L4_CSUM; 2505f8ba81cSXueming Li } 2515f8ba81cSXueming Li mlx5_cksum_table[i] = v; 2525f8ba81cSXueming Li } 2535f8ba81cSXueming Li } 2545f8ba81cSXueming Li 2555f8ba81cSXueming Li /** 2565f8ba81cSXueming Li * Build a table to translate packet type of mbuf to SWP type of Verbs. 2575f8ba81cSXueming Li */ 2585f8ba81cSXueming Li void 2595f8ba81cSXueming Li mlx5_set_swp_types_table(void) 2605f8ba81cSXueming Li { 2615f8ba81cSXueming Li unsigned int i; 2625f8ba81cSXueming Li uint8_t v; 2635f8ba81cSXueming Li 2645f8ba81cSXueming Li /* 2655f8ba81cSXueming Li * The index should have: 2665f8ba81cSXueming Li * bit[0:1] = PKT_TX_L4_MASK 2675f8ba81cSXueming Li * bit[4] = PKT_TX_IPV6 2685f8ba81cSXueming Li * bit[8] = PKT_TX_OUTER_IPV6 2695f8ba81cSXueming Li * bit[9] = PKT_TX_OUTER_UDP 2705f8ba81cSXueming Li */ 2715f8ba81cSXueming Li for (i = 0; i < RTE_DIM(mlx5_swp_types_table); ++i) { 2725f8ba81cSXueming Li v = 0; 2735f8ba81cSXueming Li if (i & (1 << 8)) 2745f8ba81cSXueming Li v |= MLX5_ETH_WQE_L3_OUTER_IPV6; 2755f8ba81cSXueming Li if (i & (1 << 9)) 2765f8ba81cSXueming Li v |= MLX5_ETH_WQE_L4_OUTER_UDP; 2775f8ba81cSXueming Li if (i & (1 << 4)) 2785f8ba81cSXueming Li v |= MLX5_ETH_WQE_L3_INNER_IPV6; 2795f8ba81cSXueming Li if ((i & 3) == (PKT_TX_UDP_CKSUM >> 52)) 2805f8ba81cSXueming Li v |= MLX5_ETH_WQE_L4_INNER_UDP; 2815f8ba81cSXueming Li mlx5_swp_types_table[i] = v; 2825f8ba81cSXueming Li } 2835f8ba81cSXueming Li } 2845f8ba81cSXueming Li 2855f8ba81cSXueming Li /** 2866ce84bd8SYongseok Koh * Return the size of tailroom of WQ. 2876ce84bd8SYongseok Koh * 2886ce84bd8SYongseok Koh * @param txq 2896ce84bd8SYongseok Koh * Pointer to TX queue structure. 2906ce84bd8SYongseok Koh * @param addr 2916ce84bd8SYongseok Koh * Pointer to tail of WQ. 2926ce84bd8SYongseok Koh * 2936ce84bd8SYongseok Koh * @return 2946ce84bd8SYongseok Koh * Size of tailroom. 2956ce84bd8SYongseok Koh */ 2966ce84bd8SYongseok Koh static inline size_t 297991b04f6SNélio Laranjeiro tx_mlx5_wq_tailroom(struct mlx5_txq_data *txq, void *addr) 2986ce84bd8SYongseok Koh { 2996ce84bd8SYongseok Koh size_t tailroom; 3006ce84bd8SYongseok Koh tailroom = (uintptr_t)(txq->wqes) + 3016ce84bd8SYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE - 3026ce84bd8SYongseok Koh (uintptr_t)addr; 3036ce84bd8SYongseok Koh return tailroom; 3046ce84bd8SYongseok Koh } 3056ce84bd8SYongseok Koh 3066ce84bd8SYongseok Koh /** 3076ce84bd8SYongseok Koh * Copy data to tailroom of circular queue. 3086ce84bd8SYongseok Koh * 3096ce84bd8SYongseok Koh * @param dst 3106ce84bd8SYongseok Koh * Pointer to destination. 3116ce84bd8SYongseok Koh * @param src 3126ce84bd8SYongseok Koh * Pointer to source. 3136ce84bd8SYongseok Koh * @param n 3146ce84bd8SYongseok Koh * Number of bytes to copy. 3156ce84bd8SYongseok Koh * @param base 3166ce84bd8SYongseok Koh * Pointer to head of queue. 3176ce84bd8SYongseok Koh * @param tailroom 3186ce84bd8SYongseok Koh * Size of tailroom from dst. 3196ce84bd8SYongseok Koh * 3206ce84bd8SYongseok Koh * @return 3216ce84bd8SYongseok Koh * Pointer after copied data. 3226ce84bd8SYongseok Koh */ 3236ce84bd8SYongseok Koh static inline void * 3246ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n, 3256ce84bd8SYongseok Koh void *base, size_t tailroom) 3266ce84bd8SYongseok Koh { 3276ce84bd8SYongseok Koh void *ret; 3286ce84bd8SYongseok Koh 3296ce84bd8SYongseok Koh if (n > tailroom) { 3306ce84bd8SYongseok Koh rte_memcpy(dst, src, tailroom); 3316ce84bd8SYongseok Koh rte_memcpy(base, (void *)((uintptr_t)src + tailroom), 3326ce84bd8SYongseok Koh n - tailroom); 3336ce84bd8SYongseok Koh ret = (uint8_t *)base + n - tailroom; 3346ce84bd8SYongseok Koh } else { 3356ce84bd8SYongseok Koh rte_memcpy(dst, src, n); 3366ce84bd8SYongseok Koh ret = (n == tailroom) ? base : (uint8_t *)dst + n; 3376ce84bd8SYongseok Koh } 3386ce84bd8SYongseok Koh return ret; 3396ce84bd8SYongseok Koh } 3406ce84bd8SYongseok Koh 3416ce84bd8SYongseok Koh /** 342593f472cSXueming Li * Inline TSO headers into WQE. 343593f472cSXueming Li * 344593f472cSXueming Li * @return 345593f472cSXueming Li * 0 on success, negative errno value on failure. 346593f472cSXueming Li */ 347593f472cSXueming Li static int 348593f472cSXueming Li inline_tso(struct mlx5_txq_data *txq, struct rte_mbuf *buf, 349593f472cSXueming Li uint32_t *length, 350593f472cSXueming Li uintptr_t *addr, 351593f472cSXueming Li uint16_t *pkt_inline_sz, 352593f472cSXueming Li uint8_t **raw, 353593f472cSXueming Li uint16_t *max_wqe, 354593f472cSXueming Li uint16_t *tso_segsz, 355593f472cSXueming Li uint16_t *tso_header_sz) 356593f472cSXueming Li { 357593f472cSXueming Li uintptr_t end = (uintptr_t)(((uintptr_t)txq->wqes) + 358593f472cSXueming Li (1 << txq->wqe_n) * MLX5_WQE_SIZE); 359593f472cSXueming Li unsigned int copy_b; 360593f472cSXueming Li uint8_t vlan_sz = (buf->ol_flags & PKT_TX_VLAN_PKT) ? 4 : 0; 3615f8ba81cSXueming Li const uint8_t tunneled = txq->tunnel_en && (buf->ol_flags & 3625f8ba81cSXueming Li PKT_TX_TUNNEL_MASK); 363593f472cSXueming Li uint16_t n_wqe; 364593f472cSXueming Li 365593f472cSXueming Li *tso_segsz = buf->tso_segsz; 366593f472cSXueming Li *tso_header_sz = buf->l2_len + vlan_sz + buf->l3_len + buf->l4_len; 367593f472cSXueming Li if (unlikely(*tso_segsz == 0 || *tso_header_sz == 0)) { 368593f472cSXueming Li txq->stats.oerrors++; 369593f472cSXueming Li return -EINVAL; 370593f472cSXueming Li } 3715f8ba81cSXueming Li if (tunneled) 372593f472cSXueming Li *tso_header_sz += buf->outer_l2_len + buf->outer_l3_len; 3735f8ba81cSXueming Li /* First seg must contain all TSO headers. */ 3745f8ba81cSXueming Li if (unlikely(*tso_header_sz > MLX5_MAX_TSO_HEADER) || 3755f8ba81cSXueming Li *tso_header_sz > DATA_LEN(buf)) { 376593f472cSXueming Li txq->stats.oerrors++; 377593f472cSXueming Li return -EINVAL; 378593f472cSXueming Li } 379593f472cSXueming Li copy_b = *tso_header_sz - *pkt_inline_sz; 380593f472cSXueming Li if (!copy_b || ((end - (uintptr_t)*raw) < copy_b)) 381593f472cSXueming Li return -EAGAIN; 382593f472cSXueming Li n_wqe = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 383593f472cSXueming Li if (unlikely(*max_wqe < n_wqe)) 384593f472cSXueming Li return -EINVAL; 385593f472cSXueming Li *max_wqe -= n_wqe; 386593f472cSXueming Li rte_memcpy((void *)*raw, (void *)*addr, copy_b); 387593f472cSXueming Li *length -= copy_b; 388593f472cSXueming Li *addr += copy_b; 389593f472cSXueming Li copy_b = MLX5_WQE_DS(copy_b) * MLX5_WQE_DWORD_SIZE; 390593f472cSXueming Li *pkt_inline_sz += copy_b; 391593f472cSXueming Li *raw += copy_b; 392593f472cSXueming Li return 0; 393593f472cSXueming Li } 394593f472cSXueming Li 395593f472cSXueming Li /** 3968788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 3978788fec1SOlivier Matz * 3988788fec1SOlivier Matz * @param tx_queue 3998788fec1SOlivier Matz * The tx queue. 4008788fec1SOlivier Matz * @param[in] offset 4018788fec1SOlivier Matz * The index of the descriptor in the ring. 4028788fec1SOlivier Matz * 4038788fec1SOlivier Matz * @return 4048788fec1SOlivier Matz * The status of the tx descriptor. 4058788fec1SOlivier Matz */ 4068788fec1SOlivier Matz int 4078788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 4088788fec1SOlivier Matz { 409991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = tx_queue; 4108c819a69SYongseok Koh uint16_t used; 4118788fec1SOlivier Matz 4126cb559d6SYongseok Koh mlx5_tx_complete(txq); 4138c819a69SYongseok Koh used = txq->elts_head - txq->elts_tail; 4148788fec1SOlivier Matz if (offset < used) 4158788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 4168788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 4178788fec1SOlivier Matz } 4188788fec1SOlivier Matz 4198788fec1SOlivier Matz /** 42026f04883STom Barbette * Internal function to compute the number of used descriptors in an RX queue 4218788fec1SOlivier Matz * 42226f04883STom Barbette * @param rxq 42326f04883STom Barbette * The Rx queue. 4248788fec1SOlivier Matz * 4258788fec1SOlivier Matz * @return 42626f04883STom Barbette * The number of used rx descriptor. 4278788fec1SOlivier Matz */ 42826f04883STom Barbette static uint32_t 42926f04883STom Barbette rx_queue_count(struct mlx5_rxq_data *rxq) 4308788fec1SOlivier Matz { 4318788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 4328788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 4338788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 4348788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 4358788fec1SOlivier Matz unsigned int cq_ci; 4368788fec1SOlivier Matz unsigned int used; 4378788fec1SOlivier Matz 4388788fec1SOlivier Matz /* if we are processing a compressed cqe */ 4398788fec1SOlivier Matz if (zip->ai) { 4408788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 4418788fec1SOlivier Matz cq_ci = zip->cq_ci; 4428788fec1SOlivier Matz } else { 4438788fec1SOlivier Matz used = 0; 4448788fec1SOlivier Matz cq_ci = rxq->cq_ci; 4458788fec1SOlivier Matz } 4468788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4478788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 4488788fec1SOlivier Matz int8_t op_own; 4498788fec1SOlivier Matz unsigned int n; 4508788fec1SOlivier Matz 4518788fec1SOlivier Matz op_own = cqe->op_own; 4528788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 4536b30a6a8SShachar Beiser n = rte_be_to_cpu_32(cqe->byte_cnt); 4548788fec1SOlivier Matz else 4558788fec1SOlivier Matz n = 1; 4568788fec1SOlivier Matz cq_ci += n; 4578788fec1SOlivier Matz used += n; 4588788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 4598788fec1SOlivier Matz } 4608788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 46126f04883STom Barbette return used; 46226f04883STom Barbette } 46326f04883STom Barbette 46426f04883STom Barbette /** 46526f04883STom Barbette * DPDK callback to check the status of a rx descriptor. 46626f04883STom Barbette * 46726f04883STom Barbette * @param rx_queue 46826f04883STom Barbette * The Rx queue. 46926f04883STom Barbette * @param[in] offset 47026f04883STom Barbette * The index of the descriptor in the ring. 47126f04883STom Barbette * 47226f04883STom Barbette * @return 47326f04883STom Barbette * The status of the tx descriptor. 47426f04883STom Barbette */ 47526f04883STom Barbette int 47626f04883STom Barbette mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 47726f04883STom Barbette { 47826f04883STom Barbette struct mlx5_rxq_data *rxq = rx_queue; 47926f04883STom Barbette struct mlx5_rxq_ctrl *rxq_ctrl = 48026f04883STom Barbette container_of(rxq, struct mlx5_rxq_ctrl, rxq); 48126f04883STom Barbette struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv); 48226f04883STom Barbette 48326f04883STom Barbette if (dev->rx_pkt_burst != mlx5_rx_burst) { 48426f04883STom Barbette rte_errno = ENOTSUP; 48526f04883STom Barbette return -rte_errno; 48626f04883STom Barbette } 48726f04883STom Barbette if (offset >= (1 << rxq->elts_n)) { 48826f04883STom Barbette rte_errno = EINVAL; 48926f04883STom Barbette return -rte_errno; 49026f04883STom Barbette } 49126f04883STom Barbette if (offset < rx_queue_count(rxq)) 4928788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 4938788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 4948788fec1SOlivier Matz } 4958788fec1SOlivier Matz 4968788fec1SOlivier Matz /** 49726f04883STom Barbette * DPDK callback to get the number of used descriptors in a RX queue 49826f04883STom Barbette * 49926f04883STom Barbette * @param dev 50026f04883STom Barbette * Pointer to the device structure. 50126f04883STom Barbette * 50226f04883STom Barbette * @param rx_queue_id 50326f04883STom Barbette * The Rx queue. 50426f04883STom Barbette * 50526f04883STom Barbette * @return 50626f04883STom Barbette * The number of used rx descriptor. 50726f04883STom Barbette * -EINVAL if the queue is invalid 50826f04883STom Barbette */ 50926f04883STom Barbette uint32_t 51026f04883STom Barbette mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id) 51126f04883STom Barbette { 512dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 51326f04883STom Barbette struct mlx5_rxq_data *rxq; 51426f04883STom Barbette 51526f04883STom Barbette if (dev->rx_pkt_burst != mlx5_rx_burst) { 51626f04883STom Barbette rte_errno = ENOTSUP; 51726f04883STom Barbette return -rte_errno; 51826f04883STom Barbette } 51926f04883STom Barbette rxq = (*priv->rxqs)[rx_queue_id]; 52026f04883STom Barbette if (!rxq) { 52126f04883STom Barbette rte_errno = EINVAL; 52226f04883STom Barbette return -rte_errno; 52326f04883STom Barbette } 52426f04883STom Barbette return rx_queue_count(rxq); 52526f04883STom Barbette } 52626f04883STom Barbette 527066cfecdSMatan Azrad #define MLX5_SYSTEM_LOG_DIR "/var/log" 528066cfecdSMatan Azrad /** 529066cfecdSMatan Azrad * Dump debug information to log file. 530066cfecdSMatan Azrad * 531066cfecdSMatan Azrad * @param fname 532066cfecdSMatan Azrad * The file name. 533066cfecdSMatan Azrad * @param hex_title 534066cfecdSMatan Azrad * If not NULL this string is printed as a header to the output 535066cfecdSMatan Azrad * and the output will be in hexadecimal view. 536066cfecdSMatan Azrad * @param buf 537066cfecdSMatan Azrad * This is the buffer address to print out. 538066cfecdSMatan Azrad * @param len 539066cfecdSMatan Azrad * The number of bytes to dump out. 540066cfecdSMatan Azrad */ 541066cfecdSMatan Azrad void 542066cfecdSMatan Azrad mlx5_dump_debug_information(const char *fname, const char *hex_title, 543066cfecdSMatan Azrad const void *buf, unsigned int hex_len) 544066cfecdSMatan Azrad { 545066cfecdSMatan Azrad FILE *fd; 546066cfecdSMatan Azrad 547066cfecdSMatan Azrad MKSTR(path, "%s/%s", MLX5_SYSTEM_LOG_DIR, fname); 548066cfecdSMatan Azrad fd = fopen(path, "a+"); 549066cfecdSMatan Azrad if (!fd) { 550066cfecdSMatan Azrad DRV_LOG(WARNING, "cannot open %s for debug dump\n", 551066cfecdSMatan Azrad path); 552066cfecdSMatan Azrad MKSTR(path2, "./%s", fname); 553066cfecdSMatan Azrad fd = fopen(path2, "a+"); 554066cfecdSMatan Azrad if (!fd) { 555066cfecdSMatan Azrad DRV_LOG(ERR, "cannot open %s for debug dump\n", 556066cfecdSMatan Azrad path2); 557066cfecdSMatan Azrad return; 558066cfecdSMatan Azrad } 559066cfecdSMatan Azrad DRV_LOG(INFO, "New debug dump in file %s\n", path2); 560066cfecdSMatan Azrad } else { 561066cfecdSMatan Azrad DRV_LOG(INFO, "New debug dump in file %s\n", path); 562066cfecdSMatan Azrad } 563066cfecdSMatan Azrad if (hex_title) 564066cfecdSMatan Azrad rte_hexdump(fd, hex_title, buf, hex_len); 565066cfecdSMatan Azrad else 566066cfecdSMatan Azrad fprintf(fd, "%s", (const char *)buf); 567066cfecdSMatan Azrad fprintf(fd, "\n\n\n"); 568066cfecdSMatan Azrad fclose(fd); 569066cfecdSMatan Azrad } 570066cfecdSMatan Azrad 57126f04883STom Barbette /** 5722e22920bSAdrien Mazarguil * DPDK callback for TX. 5732e22920bSAdrien Mazarguil * 5742e22920bSAdrien Mazarguil * @param dpdk_txq 5752e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 5762e22920bSAdrien Mazarguil * @param[in] pkts 5772e22920bSAdrien Mazarguil * Packets to transmit. 5782e22920bSAdrien Mazarguil * @param pkts_n 5792e22920bSAdrien Mazarguil * Number of packets in array. 5802e22920bSAdrien Mazarguil * 5812e22920bSAdrien Mazarguil * @return 5822e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 5832e22920bSAdrien Mazarguil */ 5842e22920bSAdrien Mazarguil uint16_t 5852e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 5862e22920bSAdrien Mazarguil { 587991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 5881d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 5898c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 5908c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 591c3d62cc9SAdrien Mazarguil unsigned int i = 0; 592a5bf6af9SAdrien Mazarguil unsigned int j = 0; 5933f13f8c2SShahaf Shuler unsigned int k = 0; 5948c819a69SYongseok Koh uint16_t max_elts; 595f04f1d51SNélio Laranjeiro uint16_t max_wqe; 596c305090bSAdrien Mazarguil unsigned int comp; 597ac180a21SYongseok Koh volatile struct mlx5_wqe_ctrl *last_wqe = NULL; 5986579c27cSNélio Laranjeiro unsigned int segs_n = 0; 59927a6b2d6SNélio Laranjeiro const unsigned int max_inline = txq->max_inline; 6006bf10ab6SMoti Haimovsky uint64_t addr_64; 6012e22920bSAdrien Mazarguil 6021d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 6031d88ba17SNélio Laranjeiro return 0; 6045e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 605c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 6061d88ba17SNélio Laranjeiro /* Start processing. */ 6076cb559d6SYongseok Koh mlx5_tx_complete(txq); 6088c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 609f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 610f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 611f04f1d51SNélio Laranjeiro return 0; 612c3d62cc9SAdrien Mazarguil do { 6135f8ba81cSXueming Li struct rte_mbuf *buf = *pkts; /* First_seg. */ 6143bbae1ebSNélio Laranjeiro uint8_t *raw; 6153bbae1ebSNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 6169a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 617573f54afSNélio Laranjeiro uint32_t length; 6188688b2f8SNélio Laranjeiro unsigned int ds = 0; 619ac180a21SYongseok Koh unsigned int sg = 0; /* counter of additional segs attached. */ 6206579c27cSNélio Laranjeiro uintptr_t addr; 6210d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 6223f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 623eef822ddSNélio Laranjeiro uint16_t ehdr; 6244aa15eb1SNélio Laranjeiro uint8_t cs_flags; 6255f8ba81cSXueming Li uint8_t tso = txq->tso_en && (buf->ol_flags & PKT_TX_TCP_SEG); 6265f8ba81cSXueming Li uint32_t swp_offsets = 0; 6275f8ba81cSXueming Li uint8_t swp_types = 0; 6286bd7fbd0SDekel Peled rte_be32_t metadata; 62983daf156SShahaf Shuler uint16_t tso_segsz = 0; 6306579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 6316579c27cSNélio Laranjeiro uint32_t total_length = 0; 6326579c27cSNélio Laranjeiro #endif 633593f472cSXueming Li int ret; 6342e22920bSAdrien Mazarguil 6356579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 636c3d62cc9SAdrien Mazarguil /* 637c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 638c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 639c3d62cc9SAdrien Mazarguil */ 640a5bf6af9SAdrien Mazarguil assert(segs_n); 6418c819a69SYongseok Koh if (max_elts < segs_n) 642c3d62cc9SAdrien Mazarguil break; 6438c819a69SYongseok Koh max_elts -= segs_n; 644f895536bSYongseok Koh sg = --segs_n; 645f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 646f04f1d51SNélio Laranjeiro break; 6479a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 648fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 649fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 6503730e6c6SYongseok Koh if (pkts_n - i > 1) 6513730e6c6SYongseok Koh rte_prefetch0(*(pkts + 1)); 6526579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 6532e22920bSAdrien Mazarguil length = DATA_LEN(buf); 654eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 655eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 6566579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 6576579c27cSNélio Laranjeiro total_length = length; 6586579c27cSNélio Laranjeiro #endif 65924c14430SShahaf Shuler if (length < (MLX5_WQE_DWORD_SIZE + 2)) { 66024c14430SShahaf Shuler txq->stats.oerrors++; 661959be52eSNélio Laranjeiro break; 66224c14430SShahaf Shuler } 6632e22920bSAdrien Mazarguil /* Update element. */ 6648c819a69SYongseok Koh (*txq->elts)[elts_head & elts_m] = buf; 6655e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 6663730e6c6SYongseok Koh if (pkts_n - i > 1) 6673730e6c6SYongseok Koh rte_prefetch0( 6683730e6c6SYongseok Koh rte_pktmbuf_mtod(*(pkts + 1), volatile void *)); 6695f8ba81cSXueming Li cs_flags = txq_ol_cksum_to_cs(buf); 6708f6d9e13SYongseok Koh txq_mbuf_to_swp(txq, buf, (uint8_t *)&swp_offsets, &swp_types); 671b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 6726bd7fbd0SDekel Peled /* Copy metadata from mbuf if valid */ 6736bd7fbd0SDekel Peled metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata : 6746bd7fbd0SDekel Peled 0; 6756579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 6768f6d9e13SYongseok Koh if (buf->ol_flags & PKT_TX_VLAN_PKT) { 6776b30a6a8SShachar Beiser uint32_t vlan = rte_cpu_to_be_32(0x81000000 | 6786b30a6a8SShachar Beiser buf->vlan_tci); 67935b2d13fSOlivier Matz unsigned int len = 2 * RTE_ETHER_ADDR_LEN - 2; 6806579c27cSNélio Laranjeiro 6810d637a34SNélio Laranjeiro addr += 2; 6820d637a34SNélio Laranjeiro length -= 2; 6830d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 6840d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 6850d637a34SNélio Laranjeiro /* Copy VLAN. */ 6860d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 6870d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 6880d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 6890d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 6900d637a34SNélio Laranjeiro addr += len + 2; 6910d637a34SNélio Laranjeiro length -= (len + 2); 6920d637a34SNélio Laranjeiro } else { 6930d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 6940d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 6950d637a34SNélio Laranjeiro length -= pkt_inline_sz; 6960d637a34SNélio Laranjeiro addr += pkt_inline_sz; 6976579c27cSNélio Laranjeiro } 698d8292497SYongseok Koh raw += MLX5_WQE_DWORD_SIZE; 6993f13f8c2SShahaf Shuler if (tso) { 7005f8ba81cSXueming Li ret = inline_tso(txq, buf, &length, 701593f472cSXueming Li &addr, &pkt_inline_sz, 702593f472cSXueming Li &raw, &max_wqe, 703593f472cSXueming Li &tso_segsz, &tso_header_sz); 704593f472cSXueming Li if (ret == -EINVAL) { 70596fc8d65SShahaf Shuler break; 706593f472cSXueming Li } else if (ret == -EAGAIN) { 7073f13f8c2SShahaf Shuler /* NOP WQE. */ 7083f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 70936aa55eaSYongseok Koh rte_cpu_to_be_32(txq->wqe_ci << 8), 71036aa55eaSYongseok Koh rte_cpu_to_be_32(txq->qp_num_8s | 1), 7113f13f8c2SShahaf Shuler 0, 7123f13f8c2SShahaf Shuler 0, 7133f13f8c2SShahaf Shuler }; 7143f13f8c2SShahaf Shuler ds = 1; 715cb98affeSThierry Herbelot #ifdef MLX5_PMD_SOFT_COUNTERS 7163f13f8c2SShahaf Shuler total_length = 0; 717cb98affeSThierry Herbelot #endif 7183f13f8c2SShahaf Shuler k++; 7193f13f8c2SShahaf Shuler goto next_wqe; 7203f13f8c2SShahaf Shuler } 7213f13f8c2SShahaf Shuler } 7226579c27cSNélio Laranjeiro /* Inline if enough room. */ 72327a6b2d6SNélio Laranjeiro if (max_inline || tso) { 724f895536bSYongseok Koh uint32_t inl = 0; 725fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 726fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 727fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 728ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 7298fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 730d8292497SYongseok Koh (pkt_inline_sz - 2) - 731d8292497SYongseok Koh !!tso * sizeof(inl); 732f895536bSYongseok Koh uintptr_t addr_end; 733f895536bSYongseok Koh unsigned int copy_b; 7346579c27cSNélio Laranjeiro 735f895536bSYongseok Koh pkt_inline: 736f895536bSYongseok Koh addr_end = RTE_ALIGN_FLOOR(addr + inline_room, 737f895536bSYongseok Koh RTE_CACHE_LINE_SIZE); 738f895536bSYongseok Koh copy_b = (addr_end > addr) ? 739f895536bSYongseok Koh RTE_MIN((addr_end - addr), length) : 0; 74057c0e249SShahaf Shuler if (copy_b && ((end - (uintptr_t)raw) > 74157c0e249SShahaf Shuler (copy_b + sizeof(inl)))) { 742f04f1d51SNélio Laranjeiro /* 743f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 744f04f1d51SNélio Laranjeiro * keep the computation positive, it is 745f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 746f04f1d51SNélio Laranjeiro */ 7478fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 7488fcd6c2cSNélio Laranjeiro 749f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 750f04f1d51SNélio Laranjeiro break; 751f04f1d51SNélio Laranjeiro max_wqe -= n; 7525f44cfd0SYongseok Koh if (tso) { 7535f44cfd0SYongseok Koh assert(inl == 0); 7546963ae8bSYongseok Koh inl = rte_cpu_to_be_32(copy_b | 7556b30a6a8SShachar Beiser MLX5_INLINE_SEG); 7563f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 7573f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 7583f13f8c2SShahaf Shuler raw += sizeof(inl); 7593f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 7603f13f8c2SShahaf Shuler } 7616579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 7626579c27cSNélio Laranjeiro addr += copy_b; 7636579c27cSNélio Laranjeiro length -= copy_b; 7646579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 7656579c27cSNélio Laranjeiro } 7666579c27cSNélio Laranjeiro /* 767786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 7686579c27cSNélio Laranjeiro * the size of the inline part of the packet. 7696579c27cSNélio Laranjeiro */ 7706579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 7716579c27cSNélio Laranjeiro if (length > 0) { 772f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 773f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 774f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 775f04f1d51SNélio Laranjeiro break; 776f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 777f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 778f04f1d51SNélio Laranjeiro ds / 4); 779f04f1d51SNélio Laranjeiro } else { 7809a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 7816579c27cSNélio Laranjeiro ((uintptr_t)wqe + 7826579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 783f04f1d51SNélio Laranjeiro } 7846579c27cSNélio Laranjeiro goto use_dseg; 7856579c27cSNélio Laranjeiro } else if (!segs_n) { 7866579c27cSNélio Laranjeiro goto next_pkt; 7876579c27cSNélio Laranjeiro } else { 7885f44cfd0SYongseok Koh /* 7895f44cfd0SYongseok Koh * Further inline the next segment only for 7905f44cfd0SYongseok Koh * non-TSO packets. 7915f44cfd0SYongseok Koh */ 7925f44cfd0SYongseok Koh if (!tso) { 793f895536bSYongseok Koh raw += copy_b; 794f895536bSYongseok Koh inline_room -= copy_b; 7955f44cfd0SYongseok Koh } else { 7965f44cfd0SYongseok Koh inline_room = 0; 7975f44cfd0SYongseok Koh } 7985f44cfd0SYongseok Koh /* Move to the next segment. */ 799f895536bSYongseok Koh --segs_n; 800f895536bSYongseok Koh buf = buf->next; 801f895536bSYongseok Koh assert(buf); 802f895536bSYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 803f895536bSYongseok Koh length = DATA_LEN(buf); 804f895536bSYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 805f895536bSYongseok Koh total_length += length; 806f895536bSYongseok Koh #endif 807f895536bSYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 808f895536bSYongseok Koh goto pkt_inline; 8096579c27cSNélio Laranjeiro } 8106579c27cSNélio Laranjeiro } else { 8116579c27cSNélio Laranjeiro /* 8126579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 8136579c27cSNélio Laranjeiro * Ethernet Header as been stored. 8146579c27cSNélio Laranjeiro */ 8159a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 8166579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 8176579c27cSNélio Laranjeiro ds = 3; 8186579c27cSNélio Laranjeiro use_dseg: 8196579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 8206bf10ab6SMoti Haimovsky addr_64 = rte_cpu_to_be_64(addr); 8219a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 8226b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 8236cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 8246bf10ab6SMoti Haimovsky addr_64, 8256bf10ab6SMoti Haimovsky addr_64 >> 32, 8266579c27cSNélio Laranjeiro }; 8276579c27cSNélio Laranjeiro ++ds; 8286579c27cSNélio Laranjeiro if (!segs_n) 8296579c27cSNélio Laranjeiro goto next_pkt; 8306579c27cSNélio Laranjeiro } 8316579c27cSNélio Laranjeiro next_seg: 8326579c27cSNélio Laranjeiro assert(buf); 8336579c27cSNélio Laranjeiro assert(ds); 8346579c27cSNélio Laranjeiro assert(wqe); 835a5bf6af9SAdrien Mazarguil /* 836a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 837a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 838a5bf6af9SAdrien Mazarguil * of data segment size. 839a5bf6af9SAdrien Mazarguil */ 8408688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 8416579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 842f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 843f04f1d51SNélio Laranjeiro break; 8449a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 845f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 846f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 847f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 8486579c27cSNélio Laranjeiro } else { 849a5bf6af9SAdrien Mazarguil ++dseg; 8506579c27cSNélio Laranjeiro } 851a5bf6af9SAdrien Mazarguil ++ds; 852a5bf6af9SAdrien Mazarguil buf = buf->next; 853a5bf6af9SAdrien Mazarguil assert(buf); 8546579c27cSNélio Laranjeiro length = DATA_LEN(buf); 855a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 8566579c27cSNélio Laranjeiro total_length += length; 857a5bf6af9SAdrien Mazarguil #endif 8586579c27cSNélio Laranjeiro /* Store segment information. */ 8596bf10ab6SMoti Haimovsky addr_64 = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)); 8609a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 8616b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 8626cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 8636bf10ab6SMoti Haimovsky addr_64, 8646bf10ab6SMoti Haimovsky addr_64 >> 32, 8656579c27cSNélio Laranjeiro }; 8668c819a69SYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 867f895536bSYongseok Koh if (--segs_n) 8686579c27cSNélio Laranjeiro goto next_seg; 8696579c27cSNélio Laranjeiro next_pkt: 870883ce172SShahaf Shuler if (ds > MLX5_DSEG_MAX) { 871883ce172SShahaf Shuler txq->stats.oerrors++; 872883ce172SShahaf Shuler break; 873883ce172SShahaf Shuler } 8748c819a69SYongseok Koh ++elts_head; 8753730e6c6SYongseok Koh ++pkts; 8766579c27cSNélio Laranjeiro ++i; 877f895536bSYongseok Koh j += sg; 878b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 8793f13f8c2SShahaf Shuler if (tso) { 8803f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 8816b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 8826b30a6a8SShachar Beiser MLX5_OPCODE_TSO), 8836b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 8843f13f8c2SShahaf Shuler 0, 8853f13f8c2SShahaf Shuler 0, 8863f13f8c2SShahaf Shuler }; 8873f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 8885f8ba81cSXueming Li swp_offsets, 8895f8ba81cSXueming Li cs_flags | (swp_types << 8) | 8905f8ba81cSXueming Li (rte_cpu_to_be_16(tso_segsz) << 16), 8916bd7fbd0SDekel Peled metadata, 8926b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(tso_header_sz), 8933f13f8c2SShahaf Shuler }; 8943f13f8c2SShahaf Shuler } else { 8959a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 8966b30a6a8SShachar Beiser rte_cpu_to_be_32((txq->wqe_ci << 8) | 8976b30a6a8SShachar Beiser MLX5_OPCODE_SEND), 8986b30a6a8SShachar Beiser rte_cpu_to_be_32(txq->qp_num_8s | ds), 8999a7fa9f7SNélio Laranjeiro 0, 9009a7fa9f7SNélio Laranjeiro 0, 9019a7fa9f7SNélio Laranjeiro }; 9029a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 9035f8ba81cSXueming Li swp_offsets, 9045f8ba81cSXueming Li cs_flags | (swp_types << 8), 9056bd7fbd0SDekel Peled metadata, 9066b30a6a8SShachar Beiser (ehdr << 16) | rte_cpu_to_be_16(pkt_inline_sz), 9079a7fa9f7SNélio Laranjeiro }; 9083f13f8c2SShahaf Shuler } 9093f13f8c2SShahaf Shuler next_wqe: 9106579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 911ac180a21SYongseok Koh /* Save the last successful WQE for completion request */ 912ac180a21SYongseok Koh last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe; 91387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 914573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 9156579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 91687011737SAdrien Mazarguil #endif 9173730e6c6SYongseok Koh } while (i < pkts_n); 9182e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 9193f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 9202e22920bSAdrien Mazarguil return 0; 9218c819a69SYongseok Koh txq->elts_head += (i + j); 922c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 9233f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 924c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 925c618e7e8SYongseok Koh /* A CQE slot must always be available. */ 926c618e7e8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci)); 927c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 9286b30a6a8SShachar Beiser last_wqe->ctrl2 = rte_cpu_to_be_32(8); 929c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 930ac180a21SYongseok Koh last_wqe->ctrl3 = txq->elts_head; 931c305090bSAdrien Mazarguil txq->elts_comp = 0; 932c305090bSAdrien Mazarguil } else { 933c305090bSAdrien Mazarguil txq->elts_comp = comp; 934c305090bSAdrien Mazarguil } 93587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 93687011737SAdrien Mazarguil /* Increment sent packets counter. */ 93787011737SAdrien Mazarguil txq->stats.opackets += i; 93887011737SAdrien Mazarguil #endif 9392e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 940ac180a21SYongseok Koh mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe); 9412e22920bSAdrien Mazarguil return i; 9422e22920bSAdrien Mazarguil } 9432e22920bSAdrien Mazarguil 9442e22920bSAdrien Mazarguil /** 945230189d9SNélio Laranjeiro * Open a MPW session. 946230189d9SNélio Laranjeiro * 947230189d9SNélio Laranjeiro * @param txq 948230189d9SNélio Laranjeiro * Pointer to TX queue structure. 949230189d9SNélio Laranjeiro * @param mpw 950230189d9SNélio Laranjeiro * Pointer to MPW session structure. 951230189d9SNélio Laranjeiro * @param length 952230189d9SNélio Laranjeiro * Packet length. 953230189d9SNélio Laranjeiro */ 954230189d9SNélio Laranjeiro static inline void 955991b04f6SNélio Laranjeiro mlx5_mpw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, uint32_t length) 956230189d9SNélio Laranjeiro { 957a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 958230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 959230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 960fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 961230189d9SNélio Laranjeiro 962230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 963230189d9SNélio Laranjeiro mpw->pkts_n = 0; 964230189d9SNélio Laranjeiro mpw->len = length; 965230189d9SNélio Laranjeiro mpw->total_len = 0; 966fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 9676b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 9688688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 9698688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 9708688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 9716bd7fbd0SDekel Peled mpw->wqe->eseg.flow_table_metadata = 0; 9726b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 9736b30a6a8SShachar Beiser (txq->wqe_ci << 8) | 9746b30a6a8SShachar Beiser MLX5_OPCODE_TSO); 9758688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 9768688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 9778688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 9788688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 9798688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 9808688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 981230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 982230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 983230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 984230189d9SNélio Laranjeiro } 985230189d9SNélio Laranjeiro 986230189d9SNélio Laranjeiro /** 987230189d9SNélio Laranjeiro * Close a MPW session. 988230189d9SNélio Laranjeiro * 989230189d9SNélio Laranjeiro * @param txq 990230189d9SNélio Laranjeiro * Pointer to TX queue structure. 991230189d9SNélio Laranjeiro * @param mpw 992230189d9SNélio Laranjeiro * Pointer to MPW session structure. 993230189d9SNélio Laranjeiro */ 994230189d9SNélio Laranjeiro static inline void 995991b04f6SNélio Laranjeiro mlx5_mpw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 996230189d9SNélio Laranjeiro { 997230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 998230189d9SNélio Laranjeiro 999230189d9SNélio Laranjeiro /* 1000230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1001230189d9SNélio Laranjeiro * count as 2. 1002230189d9SNélio Laranjeiro */ 10036b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | (2 + num)); 1004230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 1005230189d9SNélio Laranjeiro if (num < 3) 1006230189d9SNélio Laranjeiro ++txq->wqe_ci; 1007230189d9SNélio Laranjeiro else 1008230189d9SNélio Laranjeiro txq->wqe_ci += 2; 1009fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1010fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1011230189d9SNélio Laranjeiro } 1012230189d9SNélio Laranjeiro 1013230189d9SNélio Laranjeiro /** 1014230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 1015230189d9SNélio Laranjeiro * 1016230189d9SNélio Laranjeiro * @param dpdk_txq 1017230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1018230189d9SNélio Laranjeiro * @param[in] pkts 1019230189d9SNélio Laranjeiro * Packets to transmit. 1020230189d9SNélio Laranjeiro * @param pkts_n 1021230189d9SNélio Laranjeiro * Number of packets in array. 1022230189d9SNélio Laranjeiro * 1023230189d9SNélio Laranjeiro * @return 1024230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1025230189d9SNélio Laranjeiro */ 1026230189d9SNélio Laranjeiro uint16_t 1027230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 1028230189d9SNélio Laranjeiro { 1029991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 1030230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 10318c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 10328c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 1033c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1034a5bf6af9SAdrien Mazarguil unsigned int j = 0; 10358c819a69SYongseok Koh uint16_t max_elts; 1036f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1037230189d9SNélio Laranjeiro unsigned int comp; 1038230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1039230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1040230189d9SNélio Laranjeiro }; 1041230189d9SNélio Laranjeiro 1042c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1043c3d62cc9SAdrien Mazarguil return 0; 1044230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1045fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1046fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1047230189d9SNélio Laranjeiro /* Start processing. */ 10486cb559d6SYongseok Koh mlx5_tx_complete(txq); 10498c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 1050f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 1051f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 1052f04f1d51SNélio Laranjeiro return 0; 1053c3d62cc9SAdrien Mazarguil do { 1054a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1055230189d9SNélio Laranjeiro uint32_t length; 1056a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 10574aa15eb1SNélio Laranjeiro uint32_t cs_flags; 10586bd7fbd0SDekel Peled rte_be32_t metadata; 1059230189d9SNélio Laranjeiro 1060c3d62cc9SAdrien Mazarguil /* 1061c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1062c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1063c3d62cc9SAdrien Mazarguil */ 1064a5bf6af9SAdrien Mazarguil assert(segs_n); 10658c819a69SYongseok Koh if (max_elts < segs_n) 1066c3d62cc9SAdrien Mazarguil break; 1067a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 106824c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 106924c14430SShahaf Shuler txq->stats.oerrors++; 1070a5bf6af9SAdrien Mazarguil break; 107124c14430SShahaf Shuler } 10728c819a69SYongseok Koh max_elts -= segs_n; 1073c3d62cc9SAdrien Mazarguil --pkts_n; 10745f8ba81cSXueming Li cs_flags = txq_ol_cksum_to_cs(buf); 10756bd7fbd0SDekel Peled /* Copy metadata from mbuf if valid */ 10766bd7fbd0SDekel Peled metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata : 10776bd7fbd0SDekel Peled 0; 1078a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1079a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1080a5bf6af9SAdrien Mazarguil assert(length); 1081230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1082230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 1083230189d9SNélio Laranjeiro ((mpw.len != length) || 1084a5bf6af9SAdrien Mazarguil (segs_n != 1) || 10856bd7fbd0SDekel Peled (mpw.wqe->eseg.flow_table_metadata != metadata) || 10868688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 1087230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1088230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1089f04f1d51SNélio Laranjeiro /* 1090f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1091f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 1092f04f1d51SNélio Laranjeiro * resources. 1093f04f1d51SNélio Laranjeiro */ 1094f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1095f04f1d51SNélio Laranjeiro break; 1096f04f1d51SNélio Laranjeiro max_wqe -= 2; 1097230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 10988688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 10996bd7fbd0SDekel Peled mpw.wqe->eseg.flow_table_metadata = metadata; 1100230189d9SNélio Laranjeiro } 1101a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1102a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1103a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1104a5bf6af9SAdrien Mazarguil length = 0; 1105a5bf6af9SAdrien Mazarguil #endif 1106a5bf6af9SAdrien Mazarguil do { 1107a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 1108a5bf6af9SAdrien Mazarguil uintptr_t addr; 1109a5bf6af9SAdrien Mazarguil 1110a5bf6af9SAdrien Mazarguil assert(buf); 11118c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1112230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1113a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1114230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 11156b30a6a8SShachar Beiser .byte_count = rte_cpu_to_be_32(DATA_LEN(buf)), 11166cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 11176b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 1118230189d9SNélio Laranjeiro }; 1119a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1120a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1121a5bf6af9SAdrien Mazarguil #endif 1122a5bf6af9SAdrien Mazarguil buf = buf->next; 1123230189d9SNélio Laranjeiro ++mpw.pkts_n; 1124a5bf6af9SAdrien Mazarguil ++j; 1125a5bf6af9SAdrien Mazarguil } while (--segs_n); 1126a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1127230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1128230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1129230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1130230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1131230189d9SNélio Laranjeiro txq->stats.obytes += length; 1132230189d9SNélio Laranjeiro #endif 1133c3d62cc9SAdrien Mazarguil ++i; 1134c3d62cc9SAdrien Mazarguil } while (pkts_n); 1135230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1136230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1137230189d9SNélio Laranjeiro return 0; 1138230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1139a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1140a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1141230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 11428688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1143230189d9SNélio Laranjeiro 1144c618e7e8SYongseok Koh /* A CQE slot must always be available. */ 1145c618e7e8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci)); 1146230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 11476b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 1148230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 11498688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1150230189d9SNélio Laranjeiro txq->elts_comp = 0; 1151230189d9SNélio Laranjeiro } else { 1152230189d9SNélio Laranjeiro txq->elts_comp = comp; 1153230189d9SNélio Laranjeiro } 1154230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1155230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1156230189d9SNélio Laranjeiro txq->stats.opackets += i; 1157230189d9SNélio Laranjeiro #endif 1158230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1159230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 1160230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 116130807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1162230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1163230189d9SNélio Laranjeiro return i; 1164230189d9SNélio Laranjeiro } 1165230189d9SNélio Laranjeiro 1166230189d9SNélio Laranjeiro /** 1167230189d9SNélio Laranjeiro * Open a MPW inline session. 1168230189d9SNélio Laranjeiro * 1169230189d9SNélio Laranjeiro * @param txq 1170230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1171230189d9SNélio Laranjeiro * @param mpw 1172230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1173230189d9SNélio Laranjeiro * @param length 1174230189d9SNélio Laranjeiro * Packet length. 1175230189d9SNélio Laranjeiro */ 1176230189d9SNélio Laranjeiro static inline void 1177991b04f6SNélio Laranjeiro mlx5_mpw_inline_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, 1178991b04f6SNélio Laranjeiro uint32_t length) 1179230189d9SNélio Laranjeiro { 1180a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 11818688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 1182230189d9SNélio Laranjeiro 1183230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 1184230189d9SNélio Laranjeiro mpw->pkts_n = 0; 1185230189d9SNélio Laranjeiro mpw->len = length; 1186230189d9SNélio Laranjeiro mpw->total_len = 0; 1187fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 11886b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = rte_cpu_to_be_32((MLX5_OPC_MOD_MPW << 24) | 1189230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 1190c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 11918688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 11928688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 11936b30a6a8SShachar Beiser mpw->wqe->eseg.mss = rte_cpu_to_be_16(length); 11948688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 11958688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 11968688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 11978688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 11986bd7fbd0SDekel Peled mpw->wqe->eseg.flow_table_metadata = 0; 11998688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 12008688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 12018688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 1202230189d9SNélio Laranjeiro } 1203230189d9SNélio Laranjeiro 1204230189d9SNélio Laranjeiro /** 1205230189d9SNélio Laranjeiro * Close a MPW inline session. 1206230189d9SNélio Laranjeiro * 1207230189d9SNélio Laranjeiro * @param txq 1208230189d9SNélio Laranjeiro * Pointer to TX queue structure. 1209230189d9SNélio Laranjeiro * @param mpw 1210230189d9SNélio Laranjeiro * Pointer to MPW session structure. 1211230189d9SNélio Laranjeiro */ 1212230189d9SNélio Laranjeiro static inline void 1213991b04f6SNélio Laranjeiro mlx5_mpw_inline_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 1214230189d9SNélio Laranjeiro { 1215230189d9SNélio Laranjeiro unsigned int size; 12168688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 12178688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 1218230189d9SNélio Laranjeiro 12198688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 1220230189d9SNélio Laranjeiro /* 1221230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 1222230189d9SNélio Laranjeiro * count as 2. 1223230189d9SNélio Laranjeiro */ 12246b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 12256b30a6a8SShachar Beiser MLX5_WQE_DS(size)); 1226230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 12276b30a6a8SShachar Beiser inl->byte_cnt = rte_cpu_to_be_32(mpw->total_len | MLX5_INLINE_SEG); 12288688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 1229230189d9SNélio Laranjeiro } 1230230189d9SNélio Laranjeiro 1231230189d9SNélio Laranjeiro /** 1232230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 1233230189d9SNélio Laranjeiro * 1234230189d9SNélio Laranjeiro * @param dpdk_txq 1235230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 1236230189d9SNélio Laranjeiro * @param[in] pkts 1237230189d9SNélio Laranjeiro * Packets to transmit. 1238230189d9SNélio Laranjeiro * @param pkts_n 1239230189d9SNélio Laranjeiro * Number of packets in array. 1240230189d9SNélio Laranjeiro * 1241230189d9SNélio Laranjeiro * @return 1242230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 1243230189d9SNélio Laranjeiro */ 1244230189d9SNélio Laranjeiro uint16_t 1245230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 1246230189d9SNélio Laranjeiro uint16_t pkts_n) 1247230189d9SNélio Laranjeiro { 1248991b04f6SNélio Laranjeiro struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 1249230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 12508c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 12518c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 1252c3d62cc9SAdrien Mazarguil unsigned int i = 0; 1253a5bf6af9SAdrien Mazarguil unsigned int j = 0; 12548c819a69SYongseok Koh uint16_t max_elts; 1255f04f1d51SNélio Laranjeiro uint16_t max_wqe; 1256230189d9SNélio Laranjeiro unsigned int comp; 12570e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 1258230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 1259230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 1260230189d9SNélio Laranjeiro }; 1261f04f1d51SNélio Laranjeiro /* 1262f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 1263f04f1d51SNélio Laranjeiro * code. 1264f04f1d51SNélio Laranjeiro * - 2 DSEG for: 1265f04f1d51SNélio Laranjeiro * - 1 control segment, 1266f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 1267f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 1268f04f1d51SNélio Laranjeiro */ 1269f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 1270f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 1271f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 1272f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 1273230189d9SNélio Laranjeiro 1274c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 1275c3d62cc9SAdrien Mazarguil return 0; 1276230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 1277fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 1278fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 1279230189d9SNélio Laranjeiro /* Start processing. */ 12806cb559d6SYongseok Koh mlx5_tx_complete(txq); 12818c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 1282c3d62cc9SAdrien Mazarguil do { 1283a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 1284230189d9SNélio Laranjeiro uintptr_t addr; 1285230189d9SNélio Laranjeiro uint32_t length; 1286a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 12874aa15eb1SNélio Laranjeiro uint8_t cs_flags; 12886bd7fbd0SDekel Peled rte_be32_t metadata; 1289230189d9SNélio Laranjeiro 1290c3d62cc9SAdrien Mazarguil /* 1291c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 1292c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 1293c3d62cc9SAdrien Mazarguil */ 1294a5bf6af9SAdrien Mazarguil assert(segs_n); 12958c819a69SYongseok Koh if (max_elts < segs_n) 1296c3d62cc9SAdrien Mazarguil break; 1297a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 129824c14430SShahaf Shuler if (segs_n > MLX5_MPW_DSEG_MAX) { 129924c14430SShahaf Shuler txq->stats.oerrors++; 1300a5bf6af9SAdrien Mazarguil break; 130124c14430SShahaf Shuler } 13028c819a69SYongseok Koh max_elts -= segs_n; 1303c3d62cc9SAdrien Mazarguil --pkts_n; 1304f04f1d51SNélio Laranjeiro /* 1305f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 1306f04f1d51SNélio Laranjeiro * iteration. 1307f04f1d51SNélio Laranjeiro */ 1308f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 13095f8ba81cSXueming Li cs_flags = txq_ol_cksum_to_cs(buf); 13106bd7fbd0SDekel Peled /* Copy metadata from mbuf if valid */ 13116bd7fbd0SDekel Peled metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata : 13126bd7fbd0SDekel Peled 0; 1313a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 1314a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 1315230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 1316230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 1317230189d9SNélio Laranjeiro if ((mpw.len != length) || 1318a5bf6af9SAdrien Mazarguil (segs_n != 1) || 13196bd7fbd0SDekel Peled (mpw.wqe->eseg.flow_table_metadata != metadata) || 13208688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1321230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1322230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1323230189d9SNélio Laranjeiro if ((mpw.len != length) || 1324a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1325230189d9SNélio Laranjeiro (length > inline_room) || 13266bd7fbd0SDekel Peled (mpw.wqe->eseg.flow_table_metadata != metadata) || 13278688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1328230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 13290e8679fcSNélio Laranjeiro inline_room = 13300e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1331230189d9SNélio Laranjeiro } 1332230189d9SNélio Laranjeiro } 1333230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1334a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1335a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1336f04f1d51SNélio Laranjeiro /* 1337f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1338f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1339f04f1d51SNélio Laranjeiro * such resources. 1340f04f1d51SNélio Laranjeiro */ 1341f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1342f04f1d51SNélio Laranjeiro break; 1343f04f1d51SNélio Laranjeiro max_wqe -= 2; 1344230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 13458688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 13466bd7fbd0SDekel Peled mpw.wqe->eseg.flow_table_metadata = metadata; 1347230189d9SNélio Laranjeiro } else { 1348f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1349f04f1d51SNélio Laranjeiro break; 1350f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1351230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 13528688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 13536bd7fbd0SDekel Peled mpw.wqe->eseg.flow_table_metadata = metadata; 1354230189d9SNélio Laranjeiro } 1355230189d9SNélio Laranjeiro } 1356a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1357a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1358230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 13590e8679fcSNélio Laranjeiro assert(inline_room == 13600e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1361a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1362a5bf6af9SAdrien Mazarguil length = 0; 1363a5bf6af9SAdrien Mazarguil #endif 1364a5bf6af9SAdrien Mazarguil do { 1365230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1366230189d9SNélio Laranjeiro 1367a5bf6af9SAdrien Mazarguil assert(buf); 13688c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1369230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1370a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1371230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 13726b30a6a8SShachar Beiser .byte_count = 13736b30a6a8SShachar Beiser rte_cpu_to_be_32(DATA_LEN(buf)), 13746cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 13756b30a6a8SShachar Beiser .addr = rte_cpu_to_be_64(addr), 1376230189d9SNélio Laranjeiro }; 1377a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1378a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1379a5bf6af9SAdrien Mazarguil #endif 1380a5bf6af9SAdrien Mazarguil buf = buf->next; 1381230189d9SNélio Laranjeiro ++mpw.pkts_n; 1382a5bf6af9SAdrien Mazarguil ++j; 1383a5bf6af9SAdrien Mazarguil } while (--segs_n); 1384a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1385230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1386230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1387230189d9SNélio Laranjeiro } else { 1388230189d9SNélio Laranjeiro unsigned int max; 1389230189d9SNélio Laranjeiro 1390230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1391230189d9SNélio Laranjeiro assert(length <= inline_room); 1392a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1393a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 13948c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1395230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1396fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1397fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1398fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1399230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1400230189d9SNélio Laranjeiro if (length > max) { 1401230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1402230189d9SNélio Laranjeiro (void *)addr, 1403230189d9SNélio Laranjeiro max); 1404fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1405230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1406230189d9SNélio Laranjeiro (void *)(addr + max), 1407230189d9SNélio Laranjeiro length - max); 1408230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1409230189d9SNélio Laranjeiro } else { 1410230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1411230189d9SNélio Laranjeiro (void *)addr, 1412230189d9SNélio Laranjeiro length); 141316c64768SYongseok Koh 141416c64768SYongseok Koh if (length == max) 141516c64768SYongseok Koh mpw.data.raw = 141616c64768SYongseok Koh (volatile void *)txq->wqes; 141716c64768SYongseok Koh else 1418230189d9SNélio Laranjeiro mpw.data.raw += length; 1419230189d9SNélio Laranjeiro } 1420230189d9SNélio Laranjeiro ++mpw.pkts_n; 142176bf1574SYongseok Koh mpw.total_len += length; 1422a5bf6af9SAdrien Mazarguil ++j; 1423230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1424230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 14250e8679fcSNélio Laranjeiro inline_room = 14260e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1427230189d9SNélio Laranjeiro } else { 1428230189d9SNélio Laranjeiro inline_room -= length; 1429230189d9SNélio Laranjeiro } 1430230189d9SNélio Laranjeiro } 1431230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1432230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1433230189d9SNélio Laranjeiro txq->stats.obytes += length; 1434230189d9SNélio Laranjeiro #endif 1435c3d62cc9SAdrien Mazarguil ++i; 1436c3d62cc9SAdrien Mazarguil } while (pkts_n); 1437230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1438230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1439230189d9SNélio Laranjeiro return 0; 1440230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1441a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1442a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1443230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 14448688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1445230189d9SNélio Laranjeiro 1446c618e7e8SYongseok Koh /* A CQE slot must always be available. */ 1447c618e7e8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci)); 1448230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 14496b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 1450230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 14518688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1452230189d9SNélio Laranjeiro txq->elts_comp = 0; 1453230189d9SNélio Laranjeiro } else { 1454230189d9SNélio Laranjeiro txq->elts_comp = comp; 1455230189d9SNélio Laranjeiro } 1456230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1457230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1458230189d9SNélio Laranjeiro txq->stats.opackets += i; 1459230189d9SNélio Laranjeiro #endif 1460230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1461230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1462230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1463230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1464230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 146530807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1466230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1467230189d9SNélio Laranjeiro return i; 1468230189d9SNélio Laranjeiro } 1469230189d9SNélio Laranjeiro 1470230189d9SNélio Laranjeiro /** 14716ce84bd8SYongseok Koh * Open an Enhanced MPW session. 14726ce84bd8SYongseok Koh * 14736ce84bd8SYongseok Koh * @param txq 14746ce84bd8SYongseok Koh * Pointer to TX queue structure. 14756ce84bd8SYongseok Koh * @param mpw 14766ce84bd8SYongseok Koh * Pointer to MPW session structure. 14776ce84bd8SYongseok Koh * @param length 14786ce84bd8SYongseok Koh * Packet length. 14796ce84bd8SYongseok Koh */ 14806ce84bd8SYongseok Koh static inline void 1481991b04f6SNélio Laranjeiro mlx5_empw_new(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw, int padding) 14826ce84bd8SYongseok Koh { 14836ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 14846ce84bd8SYongseok Koh 14856ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 14866ce84bd8SYongseok Koh mpw->pkts_n = 0; 14876ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 14886ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 14896b30a6a8SShachar Beiser mpw->wqe->ctrl[0] = 14906b30a6a8SShachar Beiser rte_cpu_to_be_32((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 14916ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 14926ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 14936ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 14946ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 14956ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 14966ce84bd8SYongseok Koh if (unlikely(padding)) { 14976ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 14986ce84bd8SYongseok Koh 14996ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 15006b30a6a8SShachar Beiser *(volatile uint32_t *)addr = rte_cpu_to_be_32(MLX5_INLINE_SEG); 15016ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 15026b30a6a8SShachar Beiser rte_cpu_to_be_32(MLX5_INLINE_SEG); 15036ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 15046ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 15056ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 15066ce84bd8SYongseok Koh } else { 15076ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 15086ce84bd8SYongseok Koh } 15096ce84bd8SYongseok Koh } 15106ce84bd8SYongseok Koh 15116ce84bd8SYongseok Koh /** 15126ce84bd8SYongseok Koh * Close an Enhanced MPW session. 15136ce84bd8SYongseok Koh * 15146ce84bd8SYongseok Koh * @param txq 15156ce84bd8SYongseok Koh * Pointer to TX queue structure. 15166ce84bd8SYongseok Koh * @param mpw 15176ce84bd8SYongseok Koh * Pointer to MPW session structure. 15186ce84bd8SYongseok Koh * 15196ce84bd8SYongseok Koh * @return 15206ce84bd8SYongseok Koh * Number of consumed WQEs. 15216ce84bd8SYongseok Koh */ 15226ce84bd8SYongseok Koh static inline uint16_t 1523991b04f6SNélio Laranjeiro mlx5_empw_close(struct mlx5_txq_data *txq, struct mlx5_mpw *mpw) 15246ce84bd8SYongseok Koh { 15256ce84bd8SYongseok Koh uint16_t ret; 15266ce84bd8SYongseok Koh 15276ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 15286ce84bd8SYongseok Koh * count as 2. 15296ce84bd8SYongseok Koh */ 15306b30a6a8SShachar Beiser mpw->wqe->ctrl[1] = rte_cpu_to_be_32(txq->qp_num_8s | 15316b30a6a8SShachar Beiser MLX5_WQE_DS(mpw->total_len)); 15326ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 15336ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 15346ce84bd8SYongseok Koh txq->wqe_ci += ret; 15356ce84bd8SYongseok Koh return ret; 15366ce84bd8SYongseok Koh } 15376ce84bd8SYongseok Koh 15386ce84bd8SYongseok Koh /** 15394b0d7b7fSYongseok Koh * TX with Enhanced MPW support. 15406ce84bd8SYongseok Koh * 15414b0d7b7fSYongseok Koh * @param txq 15424b0d7b7fSYongseok Koh * Pointer to TX queue structure. 15436ce84bd8SYongseok Koh * @param[in] pkts 15446ce84bd8SYongseok Koh * Packets to transmit. 15456ce84bd8SYongseok Koh * @param pkts_n 15466ce84bd8SYongseok Koh * Number of packets in array. 15476ce84bd8SYongseok Koh * 15486ce84bd8SYongseok Koh * @return 15496ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 15506ce84bd8SYongseok Koh */ 15514b0d7b7fSYongseok Koh static inline uint16_t 15524b0d7b7fSYongseok Koh txq_burst_empw(struct mlx5_txq_data *txq, struct rte_mbuf **pkts, 15534b0d7b7fSYongseok Koh uint16_t pkts_n) 15546ce84bd8SYongseok Koh { 15556ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 15568c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 15578c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 15586ce84bd8SYongseok Koh unsigned int i = 0; 15596ce84bd8SYongseok Koh unsigned int j = 0; 15608c819a69SYongseok Koh uint16_t max_elts; 15616ce84bd8SYongseok Koh uint16_t max_wqe; 15626ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 15636ce84bd8SYongseok Koh unsigned int mpw_room = 0; 15646ce84bd8SYongseok Koh unsigned int inl_pad = 0; 15656ce84bd8SYongseok Koh uint32_t inl_hdr; 15666bf10ab6SMoti Haimovsky uint64_t addr_64; 15676ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 15686ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 15696ce84bd8SYongseok Koh }; 15706ce84bd8SYongseok Koh 15716ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 15726ce84bd8SYongseok Koh return 0; 15736ce84bd8SYongseok Koh /* Start processing. */ 15746cb559d6SYongseok Koh mlx5_tx_complete(txq); 15756ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 15766ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 15776ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 15786ce84bd8SYongseok Koh return 0; 15796ce84bd8SYongseok Koh do { 15806ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 15816ce84bd8SYongseok Koh uintptr_t addr; 15826ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 15836ce84bd8SYongseok Koh uint32_t length; 15844aa15eb1SNélio Laranjeiro uint8_t cs_flags; 15856bd7fbd0SDekel Peled rte_be32_t metadata; 15866ce84bd8SYongseok Koh 158748642ec5SYongseok Koh /* Multi-segmented packet is handled in slow-path outside. */ 158848642ec5SYongseok Koh assert(NB_SEGS(buf) == 1); 158948642ec5SYongseok Koh /* Make sure there is enough room to store this packet. */ 159048642ec5SYongseok Koh if (max_elts - j == 0) 15916ce84bd8SYongseok Koh break; 15925f8ba81cSXueming Li cs_flags = txq_ol_cksum_to_cs(buf); 15936bd7fbd0SDekel Peled /* Copy metadata from mbuf if valid */ 15946bd7fbd0SDekel Peled metadata = buf->ol_flags & PKT_TX_METADATA ? buf->tx_metadata : 15956bd7fbd0SDekel Peled 0; 15966ce84bd8SYongseok Koh /* Retrieve packet information. */ 15976ce84bd8SYongseok Koh length = PKT_LEN(buf); 15986ce84bd8SYongseok Koh /* Start new session if: 15996ce84bd8SYongseok Koh * - multi-segment packet 16006ce84bd8SYongseok Koh * - no space left even for a dseg 16016ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 16026ce84bd8SYongseok Koh * - cs_flag differs 16036ce84bd8SYongseok Koh */ 16046ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 160548642ec5SYongseok Koh if ((inl_pad + sizeof(struct mlx5_wqe_data_seg) > 16066ce84bd8SYongseok Koh mpw_room) || 16076ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 16086ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 16096ce84bd8SYongseok Koh mpw_room) || 16106bd7fbd0SDekel Peled (mpw.wqe->eseg.flow_table_metadata != metadata) || 16116ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 16126ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 16136ce84bd8SYongseok Koh } 16146ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 161548642ec5SYongseok Koh /* In Enhanced MPW, inline as much as the budget is 161648642ec5SYongseok Koh * allowed. The remaining space is to be filled with 161748642ec5SYongseok Koh * dsegs. If the title WQEBB isn't padded, it will have 161848642ec5SYongseok Koh * 2 dsegs there. 16196ce84bd8SYongseok Koh */ 16206ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 16216ce84bd8SYongseok Koh (max_inline ? max_inline : 16226ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 16236ce84bd8SYongseok Koh MLX5_WQE_SIZE); 162448642ec5SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < mpw_room)) 16256ce84bd8SYongseok Koh break; 16266ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 16276ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 16286ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 16296ce84bd8SYongseok Koh inl_pad = 0; 163048642ec5SYongseok Koh do_inline = length <= txq->inline_max_packet_sz && 16316ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 16326ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 16336ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 16346bd7fbd0SDekel Peled mpw.wqe->eseg.flow_table_metadata = metadata; 16356ce84bd8SYongseok Koh } else { 16366ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 16376ce84bd8SYongseok Koh * Inlininig is possible when: 16386ce84bd8SYongseok Koh * - length is less than configured value 16396ce84bd8SYongseok Koh * - length fits for remaining space 16406ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 16416ce84bd8SYongseok Koh */ 16426ce84bd8SYongseok Koh do_inline = 16436ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 16446ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 16456ce84bd8SYongseok Koh mpw_room && 16466ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 16476ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 16486ce84bd8SYongseok Koh } 164924a8f524SYongseok Koh if (max_inline && do_inline) { 16506ce84bd8SYongseok Koh /* Inline packet into WQE. */ 16516ce84bd8SYongseok Koh unsigned int max; 16526ce84bd8SYongseok Koh 16536ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 16546ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 16556b30a6a8SShachar Beiser inl_hdr = rte_cpu_to_be_32(length | MLX5_INLINE_SEG); 16566ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 16576ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16586ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 16596ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 16606ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 16616ce84bd8SYongseok Koh /* Copy inline header. */ 16626ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16636ce84bd8SYongseok Koh mlx5_copy_to_wq( 16646ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 16656ce84bd8SYongseok Koh &inl_hdr, 16666ce84bd8SYongseok Koh sizeof(inl_hdr), 16676ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 16686ce84bd8SYongseok Koh max); 16696ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 16706ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 16716ce84bd8SYongseok Koh /* Copy packet data. */ 16726ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 16736ce84bd8SYongseok Koh mlx5_copy_to_wq( 16746ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 16756ce84bd8SYongseok Koh (void *)addr, 16766ce84bd8SYongseok Koh length, 16776ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 16786ce84bd8SYongseok Koh max); 16796ce84bd8SYongseok Koh ++mpw.pkts_n; 16806ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 16816ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 16826ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 16836ce84bd8SYongseok Koh */ 16846ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 16856ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 16866ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 16876ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 16886ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 16896ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 16906ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 16916ce84bd8SYongseok Koh } else { 16926ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 16936ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 16946ce84bd8SYongseok Koh 16956ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 16966ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 16976ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 16986ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 16996ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 17006ce84bd8SYongseok Koh + inl_pad))) 17016ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 17026ce84bd8SYongseok Koh else 17036ce84bd8SYongseok Koh dseg = (volatile void *) 17046ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 17056ce84bd8SYongseok Koh inl_pad); 17068c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 17076bf10ab6SMoti Haimovsky addr_64 = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, 1708f84411beSYongseok Koh uintptr_t)); 17096ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 17106b30a6a8SShachar Beiser rte_cpu_to_be_32(length), 17116cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 17126bf10ab6SMoti Haimovsky addr_64, 17136bf10ab6SMoti Haimovsky addr_64 >> 32, 17146ce84bd8SYongseok Koh }; 17156ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 17166ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 17176ce84bd8SYongseok Koh ++j; 17186ce84bd8SYongseok Koh ++mpw.pkts_n; 17196ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 17206ce84bd8SYongseok Koh inl_pad = 0; 17216ce84bd8SYongseok Koh } 17226ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 17236ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 17246ce84bd8SYongseok Koh txq->stats.obytes += length; 17256ce84bd8SYongseok Koh #endif 17266ce84bd8SYongseok Koh ++i; 17276ce84bd8SYongseok Koh } while (i < pkts_n); 17286ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 17296ce84bd8SYongseok Koh if (unlikely(i == 0)) 17306ce84bd8SYongseok Koh return 0; 17316ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 17326ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 17336ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 17346ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 17356ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 17366ce84bd8SYongseok Koh 1737c618e7e8SYongseok Koh /* A CQE slot must always be available. */ 1738c618e7e8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi++ - txq->cq_ci)); 17396ce84bd8SYongseok Koh /* Request completion on last WQE. */ 17406b30a6a8SShachar Beiser wqe->ctrl[2] = rte_cpu_to_be_32(8); 17416ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 17426ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 17436ce84bd8SYongseok Koh txq->elts_comp = 0; 17446ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 17456ce84bd8SYongseok Koh } else { 17466ce84bd8SYongseok Koh txq->elts_comp += j; 17476ce84bd8SYongseok Koh } 17486ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 17496ce84bd8SYongseok Koh /* Increment sent packets counter. */ 17506ce84bd8SYongseok Koh txq->stats.opackets += i; 17516ce84bd8SYongseok Koh #endif 17526ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 17536ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 17546ce84bd8SYongseok Koh /* Ring QP doorbell. */ 17556ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 17566ce84bd8SYongseok Koh txq->elts_head = elts_head; 17576ce84bd8SYongseok Koh return i; 17586ce84bd8SYongseok Koh } 17596ce84bd8SYongseok Koh 17606ce84bd8SYongseok Koh /** 17614b0d7b7fSYongseok Koh * DPDK callback for TX with Enhanced MPW support. 17624b0d7b7fSYongseok Koh * 17634b0d7b7fSYongseok Koh * @param dpdk_txq 17644b0d7b7fSYongseok Koh * Generic pointer to TX queue structure. 17654b0d7b7fSYongseok Koh * @param[in] pkts 17664b0d7b7fSYongseok Koh * Packets to transmit. 17674b0d7b7fSYongseok Koh * @param pkts_n 17684b0d7b7fSYongseok Koh * Number of packets in array. 17694b0d7b7fSYongseok Koh * 17704b0d7b7fSYongseok Koh * @return 17714b0d7b7fSYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 17724b0d7b7fSYongseok Koh */ 17734b0d7b7fSYongseok Koh uint16_t 17744b0d7b7fSYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 17754b0d7b7fSYongseok Koh { 17764b0d7b7fSYongseok Koh struct mlx5_txq_data *txq = (struct mlx5_txq_data *)dpdk_txq; 17774b0d7b7fSYongseok Koh uint16_t nb_tx = 0; 17784b0d7b7fSYongseok Koh 17794b0d7b7fSYongseok Koh while (pkts_n > nb_tx) { 17804b0d7b7fSYongseok Koh uint16_t n; 17814b0d7b7fSYongseok Koh uint16_t ret; 17824b0d7b7fSYongseok Koh 17834b0d7b7fSYongseok Koh n = txq_count_contig_multi_seg(&pkts[nb_tx], pkts_n - nb_tx); 17844b0d7b7fSYongseok Koh if (n) { 17854b0d7b7fSYongseok Koh ret = mlx5_tx_burst(dpdk_txq, &pkts[nb_tx], n); 17864b0d7b7fSYongseok Koh if (!ret) 17874b0d7b7fSYongseok Koh break; 17884b0d7b7fSYongseok Koh nb_tx += ret; 17894b0d7b7fSYongseok Koh } 17904b0d7b7fSYongseok Koh n = txq_count_contig_single_seg(&pkts[nb_tx], pkts_n - nb_tx); 17914b0d7b7fSYongseok Koh if (n) { 17924b0d7b7fSYongseok Koh ret = txq_burst_empw(txq, &pkts[nb_tx], n); 17934b0d7b7fSYongseok Koh if (!ret) 17944b0d7b7fSYongseok Koh break; 17954b0d7b7fSYongseok Koh nb_tx += ret; 17964b0d7b7fSYongseok Koh } 17974b0d7b7fSYongseok Koh } 17984b0d7b7fSYongseok Koh return nb_tx; 17994b0d7b7fSYongseok Koh } 18004b0d7b7fSYongseok Koh 18014b0d7b7fSYongseok Koh /** 180267fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 180367fa62bcSAdrien Mazarguil * 18043cc08bc6SXueming Li * @param[in] rxq 18053cc08bc6SXueming Li * Pointer to RX queue structure. 18066218063bSNélio Laranjeiro * @param[in] cqe 18076218063bSNélio Laranjeiro * Pointer to CQE. 180867fa62bcSAdrien Mazarguil * 180978a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 181078a38edfSJianfeng Tan * 181167fa62bcSAdrien Mazarguil * @return 181267fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 181367fa62bcSAdrien Mazarguil */ 181467fa62bcSAdrien Mazarguil static inline uint32_t 18153cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe) 181667fa62bcSAdrien Mazarguil { 1817ea16068cSYongseok Koh uint8_t idx; 1818ea16068cSYongseok Koh uint8_t pinfo = cqe->pkt_info; 1819ea16068cSYongseok Koh uint16_t ptype = cqe->hdr_type_etc; 182067fa62bcSAdrien Mazarguil 1821ea16068cSYongseok Koh /* 1822ea16068cSYongseok Koh * The index to the array should have: 1823ea16068cSYongseok Koh * bit[1:0] = l3_hdr_type 1824ea16068cSYongseok Koh * bit[4:2] = l4_hdr_type 1825ea16068cSYongseok Koh * bit[5] = ip_frag 1826ea16068cSYongseok Koh * bit[6] = tunneled 1827ea16068cSYongseok Koh * bit[7] = outer_l3_type 1828ea16068cSYongseok Koh */ 1829ea16068cSYongseok Koh idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10); 18303cc08bc6SXueming Li return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6)); 183167fa62bcSAdrien Mazarguil } 183267fa62bcSAdrien Mazarguil 183367fa62bcSAdrien Mazarguil /** 1834*6bb506ccSMatan Azrad * Initialize Rx WQ and indexes. 1835*6bb506ccSMatan Azrad * 1836*6bb506ccSMatan Azrad * @param[in] rxq 1837*6bb506ccSMatan Azrad * Pointer to RX queue structure. 1838*6bb506ccSMatan Azrad */ 1839*6bb506ccSMatan Azrad void 1840*6bb506ccSMatan Azrad mlx5_rxq_initialize(struct mlx5_rxq_data *rxq) 1841*6bb506ccSMatan Azrad { 1842*6bb506ccSMatan Azrad const unsigned int wqe_n = 1 << rxq->elts_n; 1843*6bb506ccSMatan Azrad unsigned int i; 1844*6bb506ccSMatan Azrad 1845*6bb506ccSMatan Azrad for (i = 0; (i != wqe_n); ++i) { 1846*6bb506ccSMatan Azrad volatile struct mlx5_wqe_data_seg *scat; 1847*6bb506ccSMatan Azrad uintptr_t addr; 1848*6bb506ccSMatan Azrad uint32_t byte_count; 1849*6bb506ccSMatan Azrad 1850*6bb506ccSMatan Azrad if (mlx5_rxq_mprq_enabled(rxq)) { 1851*6bb506ccSMatan Azrad struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i]; 1852*6bb506ccSMatan Azrad 1853*6bb506ccSMatan Azrad scat = &((volatile struct mlx5_wqe_mprq *) 1854*6bb506ccSMatan Azrad rxq->wqes)[i].dseg; 1855*6bb506ccSMatan Azrad addr = (uintptr_t)mlx5_mprq_buf_addr(buf); 1856*6bb506ccSMatan Azrad byte_count = (1 << rxq->strd_sz_n) * 1857*6bb506ccSMatan Azrad (1 << rxq->strd_num_n); 1858*6bb506ccSMatan Azrad } else { 1859*6bb506ccSMatan Azrad struct rte_mbuf *buf = (*rxq->elts)[i]; 1860*6bb506ccSMatan Azrad 1861*6bb506ccSMatan Azrad scat = &((volatile struct mlx5_wqe_data_seg *) 1862*6bb506ccSMatan Azrad rxq->wqes)[i]; 1863*6bb506ccSMatan Azrad addr = rte_pktmbuf_mtod(buf, uintptr_t); 1864*6bb506ccSMatan Azrad byte_count = DATA_LEN(buf); 1865*6bb506ccSMatan Azrad } 1866*6bb506ccSMatan Azrad /* scat->addr must be able to store a pointer. */ 1867*6bb506ccSMatan Azrad assert(sizeof(scat->addr) >= sizeof(uintptr_t)); 1868*6bb506ccSMatan Azrad *scat = (struct mlx5_wqe_data_seg){ 1869*6bb506ccSMatan Azrad .addr = rte_cpu_to_be_64(addr), 1870*6bb506ccSMatan Azrad .byte_count = rte_cpu_to_be_32(byte_count), 1871*6bb506ccSMatan Azrad .lkey = mlx5_rx_addr2mr(rxq, addr), 1872*6bb506ccSMatan Azrad }; 1873*6bb506ccSMatan Azrad } 1874*6bb506ccSMatan Azrad rxq->consumed_strd = 0; 1875*6bb506ccSMatan Azrad rxq->decompressed = 0; 1876*6bb506ccSMatan Azrad rxq->rq_pi = 0; 1877*6bb506ccSMatan Azrad rxq->zip = (struct rxq_zip){ 1878*6bb506ccSMatan Azrad .ai = 0, 1879*6bb506ccSMatan Azrad }; 1880*6bb506ccSMatan Azrad /* Update doorbell counter. */ 1881*6bb506ccSMatan Azrad rxq->rq_ci = wqe_n >> rxq->sges_n; 1882*6bb506ccSMatan Azrad rte_cio_wmb(); 1883*6bb506ccSMatan Azrad *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 1884*6bb506ccSMatan Azrad } 1885*6bb506ccSMatan Azrad 1886*6bb506ccSMatan Azrad /** 188799c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 188899c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 188999c12dccSNélio Laranjeiro * been processed. 189099c12dccSNélio Laranjeiro * 189199c12dccSNélio Laranjeiro * @param rxq 189299c12dccSNélio Laranjeiro * Pointer to RX queue. 189399c12dccSNélio Laranjeiro * @param cqe 189499c12dccSNélio Laranjeiro * CQE to process. 18952e633f1fSYongseok Koh * @param[out] mcqe 18962e633f1fSYongseok Koh * Store pointer to mini-CQE if compressed. Otherwise, the pointer is not 18972e633f1fSYongseok Koh * written. 189899c12dccSNélio Laranjeiro * 189999c12dccSNélio Laranjeiro * @return 190099c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 190199c12dccSNélio Laranjeiro * with error. 190299c12dccSNélio Laranjeiro */ 190399c12dccSNélio Laranjeiro static inline int 190478142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 19052e633f1fSYongseok Koh uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe) 190699c12dccSNélio Laranjeiro { 190799c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 190899c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 190999c12dccSNélio Laranjeiro int len = 0; 1910d2e842d0SYongseok Koh uint16_t idx, end; 191199c12dccSNélio Laranjeiro 191299c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 191399c12dccSNélio Laranjeiro if (zip->ai) { 191499c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 191599c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 19164aff4bcbSYongseok Koh (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info); 191799c12dccSNélio Laranjeiro 19186b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt); 19192e633f1fSYongseok Koh *mcqe = &(*mc)[zip->ai & 7]; 192099c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1921d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1922d2e842d0SYongseok Koh idx = zip->ca; 1923d2e842d0SYongseok Koh end = zip->na; 1924d2e842d0SYongseok Koh while (idx != end) { 1925d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1926d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1927d2e842d0SYongseok Koh ++idx; 1928d2e842d0SYongseok Koh } 192999c12dccSNélio Laranjeiro /* 193099c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 193199c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 193299c12dccSNélio Laranjeiro * ring for software use. 193399c12dccSNélio Laranjeiro */ 193499c12dccSNélio Laranjeiro zip->ca = zip->na; 193599c12dccSNélio Laranjeiro zip->na += 8; 193699c12dccSNélio Laranjeiro } 193799c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1938d2e842d0SYongseok Koh /* Invalidate the rest */ 1939d2e842d0SYongseok Koh idx = zip->ca; 1940d2e842d0SYongseok Koh end = zip->cq_ci; 194199c12dccSNélio Laranjeiro 194299c12dccSNélio Laranjeiro while (idx != end) { 194397267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 194499c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 194599c12dccSNélio Laranjeiro ++idx; 194699c12dccSNélio Laranjeiro } 194799c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 194899c12dccSNélio Laranjeiro zip->ai = 0; 194999c12dccSNélio Laranjeiro } 195099c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 195199c12dccSNélio Laranjeiro } else { 195299c12dccSNélio Laranjeiro int ret; 195399c12dccSNélio Laranjeiro int8_t op_own; 195499c12dccSNélio Laranjeiro 195597267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 195699c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 195799c12dccSNélio Laranjeiro return 0; 195899c12dccSNélio Laranjeiro ++rxq->cq_ci; 195999c12dccSNélio Laranjeiro op_own = cqe->op_own; 19601742c2d9SYongseok Koh rte_cio_rmb(); 196199c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 196299c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 196399c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 196499c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 19654aff4bcbSYongseok Koh cqe_cnt].pkt_info); 196699c12dccSNélio Laranjeiro 196799c12dccSNélio Laranjeiro /* Fix endianness. */ 19686b30a6a8SShachar Beiser zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt); 196999c12dccSNélio Laranjeiro /* 197099c12dccSNélio Laranjeiro * Current mini array position is the one returned by 197199c12dccSNélio Laranjeiro * check_cqe64(). 197299c12dccSNélio Laranjeiro * 197399c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 197499c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 197599c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 197699c12dccSNélio Laranjeiro */ 1977d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 197899c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 197999c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 198099c12dccSNélio Laranjeiro --rxq->cq_ci; 198199c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 198299c12dccSNélio Laranjeiro /* Get packet size to return. */ 19836b30a6a8SShachar Beiser len = rte_be_to_cpu_32((*mc)[0].byte_cnt); 19842e633f1fSYongseok Koh *mcqe = &(*mc)[0]; 198599c12dccSNélio Laranjeiro zip->ai = 1; 1986d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1987d2e842d0SYongseok Koh idx = zip->ca; 1988d2e842d0SYongseok Koh end = zip->cq_ci; 1989d2e842d0SYongseok Koh while (idx != end) { 1990d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1991d2e842d0SYongseok Koh ++idx; 1992d2e842d0SYongseok Koh } 199399c12dccSNélio Laranjeiro } else { 19946b30a6a8SShachar Beiser len = rte_be_to_cpu_32(cqe->byte_cnt); 199599c12dccSNélio Laranjeiro } 199699c12dccSNélio Laranjeiro /* Error while receiving packet. */ 199799c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 199899c12dccSNélio Laranjeiro return -1; 199999c12dccSNélio Laranjeiro } 200099c12dccSNélio Laranjeiro return len; 200199c12dccSNélio Laranjeiro } 200299c12dccSNélio Laranjeiro 200399c12dccSNélio Laranjeiro /** 200467fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 200567fa62bcSAdrien Mazarguil * 20066218063bSNélio Laranjeiro * @param[in] cqe 20076218063bSNélio Laranjeiro * Pointer to CQE. 200867fa62bcSAdrien Mazarguil * 200967fa62bcSAdrien Mazarguil * @return 201067fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 201167fa62bcSAdrien Mazarguil */ 201267fa62bcSAdrien Mazarguil static inline uint32_t 20136ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe) 201467fa62bcSAdrien Mazarguil { 201567fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 20166b30a6a8SShachar Beiser uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 201767fa62bcSAdrien Mazarguil 20180603df73SNélio Laranjeiro ol_flags = 20190603df73SNélio Laranjeiro TRANSPOSE(flags, 20200603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 20210603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 20220603df73SNélio Laranjeiro TRANSPOSE(flags, 20230603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 202483e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 202567fa62bcSAdrien Mazarguil return ol_flags; 202667fa62bcSAdrien Mazarguil } 202767fa62bcSAdrien Mazarguil 202867fa62bcSAdrien Mazarguil /** 20293e1f82a1SYongseok Koh * Fill in mbuf fields from RX completion flags. 20303e1f82a1SYongseok Koh * Note that pkt->ol_flags should be initialized outside of this function. 20313e1f82a1SYongseok Koh * 20323e1f82a1SYongseok Koh * @param rxq 20333e1f82a1SYongseok Koh * Pointer to RX queue. 20343e1f82a1SYongseok Koh * @param pkt 20353e1f82a1SYongseok Koh * mbuf to fill. 20363e1f82a1SYongseok Koh * @param cqe 20373e1f82a1SYongseok Koh * CQE to process. 20383e1f82a1SYongseok Koh * @param rss_hash_res 20393e1f82a1SYongseok Koh * Packet RSS Hash result. 20403e1f82a1SYongseok Koh */ 20413e1f82a1SYongseok Koh static inline void 20423e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 20433e1f82a1SYongseok Koh volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res) 20443e1f82a1SYongseok Koh { 20453e1f82a1SYongseok Koh /* Update packet information. */ 20463e1f82a1SYongseok Koh pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe); 20473e1f82a1SYongseok Koh if (rss_hash_res && rxq->rss_hash) { 20483e1f82a1SYongseok Koh pkt->hash.rss = rss_hash_res; 20493e1f82a1SYongseok Koh pkt->ol_flags |= PKT_RX_RSS_HASH; 20503e1f82a1SYongseok Koh } 20513e1f82a1SYongseok Koh if (rxq->mark && MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 20523e1f82a1SYongseok Koh pkt->ol_flags |= PKT_RX_FDIR; 20533e1f82a1SYongseok Koh if (cqe->sop_drop_qpn != 20543e1f82a1SYongseok Koh rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) { 20553e1f82a1SYongseok Koh uint32_t mark = cqe->sop_drop_qpn; 20563e1f82a1SYongseok Koh 20573e1f82a1SYongseok Koh pkt->ol_flags |= PKT_RX_FDIR_ID; 20583e1f82a1SYongseok Koh pkt->hash.fdir.hi = mlx5_flow_mark_get(mark); 20593e1f82a1SYongseok Koh } 20603e1f82a1SYongseok Koh } 20613e1f82a1SYongseok Koh if (rxq->csum) 20623e1f82a1SYongseok Koh pkt->ol_flags |= rxq_cq_to_ol_flags(cqe); 20633e1f82a1SYongseok Koh if (rxq->vlan_strip && 20643e1f82a1SYongseok Koh (cqe->hdr_type_etc & rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) { 20653e1f82a1SYongseok Koh pkt->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED; 20663e1f82a1SYongseok Koh pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info); 20673e1f82a1SYongseok Koh } 20683e1f82a1SYongseok Koh if (rxq->hw_timestamp) { 20693e1f82a1SYongseok Koh pkt->timestamp = rte_be_to_cpu_64(cqe->timestamp); 20703e1f82a1SYongseok Koh pkt->ol_flags |= PKT_RX_TIMESTAMP; 20713e1f82a1SYongseok Koh } 20723e1f82a1SYongseok Koh } 20733e1f82a1SYongseok Koh 20743e1f82a1SYongseok Koh /** 20752e22920bSAdrien Mazarguil * DPDK callback for RX. 20762e22920bSAdrien Mazarguil * 20772e22920bSAdrien Mazarguil * @param dpdk_rxq 20782e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 20792e22920bSAdrien Mazarguil * @param[out] pkts 20802e22920bSAdrien Mazarguil * Array to store received packets. 20812e22920bSAdrien Mazarguil * @param pkts_n 20822e22920bSAdrien Mazarguil * Maximum number of packets in array. 20832e22920bSAdrien Mazarguil * 20842e22920bSAdrien Mazarguil * @return 20852e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 20862e22920bSAdrien Mazarguil */ 20872e22920bSAdrien Mazarguil uint16_t 20882e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 20892e22920bSAdrien Mazarguil { 209078142aacSNélio Laranjeiro struct mlx5_rxq_data *rxq = dpdk_rxq; 2091b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 2092e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 20939964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 20949964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 20959964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 209697267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 209797267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 20989964b965SNélio Laranjeiro unsigned int i = 0; 20999964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 21004e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 21012e22920bSAdrien Mazarguil 21029964b965SNélio Laranjeiro while (pkts_n) { 21039964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 21047d6bf6b8SYongseok Koh volatile struct mlx5_wqe_data_seg *wqe = 21057d6bf6b8SYongseok Koh &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx]; 21069964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 21072e633f1fSYongseok Koh volatile struct mlx5_mini_cqe8 *mcqe = NULL; 21082e633f1fSYongseok Koh uint32_t rss_hash_res; 21099964b965SNélio Laranjeiro 21109964b965SNélio Laranjeiro if (pkt) 21119964b965SNélio Laranjeiro NEXT(seg) = rep; 21129964b965SNélio Laranjeiro seg = rep; 21139964b965SNélio Laranjeiro rte_prefetch0(seg); 21146218063bSNélio Laranjeiro rte_prefetch0(cqe); 21159964b965SNélio Laranjeiro rte_prefetch0(wqe); 2116fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 21172e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 211815a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 211915a756b6SSagi Grimberg if (!pkt) { 212015a756b6SSagi Grimberg /* 212115a756b6SSagi Grimberg * no buffers before we even started, 212215a756b6SSagi Grimberg * bail out silently. 212315a756b6SSagi Grimberg */ 212415a756b6SSagi Grimberg break; 212515a756b6SSagi Grimberg } 2126a1bdb71aSNélio Laranjeiro while (pkt != seg) { 2127a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 2128fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 21298f094a9aSOlivier Matz NEXT(pkt) = NULL; 21308f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 21311f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 2132fe5fe382SNélio Laranjeiro pkt = rep; 21339964b965SNélio Laranjeiro } 21346218063bSNélio Laranjeiro break; 21352e22920bSAdrien Mazarguil } 21369964b965SNélio Laranjeiro if (!pkt) { 213797267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 21382e633f1fSYongseok Koh len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe); 2139ecf60761SNélio Laranjeiro if (!len) { 21401f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 21416218063bSNélio Laranjeiro break; 21426218063bSNélio Laranjeiro } 214399c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 214499c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 21451f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 214699c12dccSNélio Laranjeiro ++rxq->stats.idropped; 214799c12dccSNélio Laranjeiro goto skip; 214899c12dccSNélio Laranjeiro } 21499964b965SNélio Laranjeiro pkt = seg; 21509964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 21510ac64846SMaxime Leroy pkt->ol_flags = 0; 21522e633f1fSYongseok Koh /* If compressed, take hash result from mini-CQE. */ 21532e633f1fSYongseok Koh rss_hash_res = rte_be_to_cpu_32(mcqe == NULL ? 21542e633f1fSYongseok Koh cqe->rx_hash_res : 21552e633f1fSYongseok Koh mcqe->rx_hash_result); 21563e1f82a1SYongseok Koh rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res); 21576218063bSNélio Laranjeiro if (rxq->crc_present) 215835b2d13fSOlivier Matz len -= RTE_ETHER_CRC_LEN; 21596218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 21609964b965SNélio Laranjeiro } 21619964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 21629964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 21639964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 21649964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 21659964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 21669964b965SNélio Laranjeiro /* 21679964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 21689964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 21699964b965SNélio Laranjeiro * changes. 21709964b965SNélio Laranjeiro */ 21716b30a6a8SShachar Beiser wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 2172974f1e7eSYongseok Koh /* If there's only one MR, no need to replace LKey in WQE. */ 2173974f1e7eSYongseok Koh if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1)) 2174974f1e7eSYongseok Koh wqe->lkey = mlx5_rx_mb2mr(rxq, rep); 21759964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 21769964b965SNélio Laranjeiro len -= DATA_LEN(seg); 21779964b965SNélio Laranjeiro ++NB_SEGS(pkt); 21789964b965SNélio Laranjeiro ++rq_ci; 21799964b965SNélio Laranjeiro continue; 21809964b965SNélio Laranjeiro } 21819964b965SNélio Laranjeiro DATA_LEN(seg) = len; 218287011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 218387011737SAdrien Mazarguil /* Increment bytes counter. */ 21849964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 218587011737SAdrien Mazarguil #endif 21866218063bSNélio Laranjeiro /* Return packet. */ 21876218063bSNélio Laranjeiro *(pkts++) = pkt; 21889964b965SNélio Laranjeiro pkt = NULL; 21899964b965SNélio Laranjeiro --pkts_n; 21909964b965SNélio Laranjeiro ++i; 219199c12dccSNélio Laranjeiro skip: 21929964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 21939964b965SNélio Laranjeiro rq_ci >>= sges_n; 21946218063bSNélio Laranjeiro ++rq_ci; 21959964b965SNélio Laranjeiro rq_ci <<= sges_n; 21962e22920bSAdrien Mazarguil } 21979964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 21982e22920bSAdrien Mazarguil return 0; 21996218063bSNélio Laranjeiro /* Update the consumer index. */ 22009964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 22014fe7f662SYongseok Koh rte_cio_wmb(); 22026b30a6a8SShachar Beiser *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 22034fe7f662SYongseok Koh rte_cio_wmb(); 22046b30a6a8SShachar Beiser *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 220587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 220687011737SAdrien Mazarguil /* Increment packets counter. */ 22079964b965SNélio Laranjeiro rxq->stats.ipackets += i; 220887011737SAdrien Mazarguil #endif 22099964b965SNélio Laranjeiro return i; 22102e22920bSAdrien Mazarguil } 22112e22920bSAdrien Mazarguil 22127d6bf6b8SYongseok Koh void 22137d6bf6b8SYongseok Koh mlx5_mprq_buf_free_cb(void *addr __rte_unused, void *opaque) 22147d6bf6b8SYongseok Koh { 22157d6bf6b8SYongseok Koh struct mlx5_mprq_buf *buf = opaque; 22167d6bf6b8SYongseok Koh 22177d6bf6b8SYongseok Koh if (rte_atomic16_read(&buf->refcnt) == 1) { 22187d6bf6b8SYongseok Koh rte_mempool_put(buf->mp, buf); 22197d6bf6b8SYongseok Koh } else if (rte_atomic16_add_return(&buf->refcnt, -1) == 0) { 22207d6bf6b8SYongseok Koh rte_atomic16_set(&buf->refcnt, 1); 22217d6bf6b8SYongseok Koh rte_mempool_put(buf->mp, buf); 22227d6bf6b8SYongseok Koh } 22237d6bf6b8SYongseok Koh } 22247d6bf6b8SYongseok Koh 22257d6bf6b8SYongseok Koh void 22267d6bf6b8SYongseok Koh mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf) 22277d6bf6b8SYongseok Koh { 22287d6bf6b8SYongseok Koh mlx5_mprq_buf_free_cb(NULL, buf); 22297d6bf6b8SYongseok Koh } 22307d6bf6b8SYongseok Koh 22317d6bf6b8SYongseok Koh static inline void 22327d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx) 22337d6bf6b8SYongseok Koh { 22347d6bf6b8SYongseok Koh struct mlx5_mprq_buf *rep = rxq->mprq_repl; 22357d6bf6b8SYongseok Koh volatile struct mlx5_wqe_data_seg *wqe = 22367d6bf6b8SYongseok Koh &((volatile struct mlx5_wqe_mprq *)rxq->wqes)[rq_idx].dseg; 22377d6bf6b8SYongseok Koh void *addr; 22387d6bf6b8SYongseok Koh 22397d6bf6b8SYongseok Koh assert(rep != NULL); 22407d6bf6b8SYongseok Koh /* Replace MPRQ buf. */ 22417d6bf6b8SYongseok Koh (*rxq->mprq_bufs)[rq_idx] = rep; 22427d6bf6b8SYongseok Koh /* Replace WQE. */ 22437d6bf6b8SYongseok Koh addr = mlx5_mprq_buf_addr(rep); 22447d6bf6b8SYongseok Koh wqe->addr = rte_cpu_to_be_64((uintptr_t)addr); 22457d6bf6b8SYongseok Koh /* If there's only one MR, no need to replace LKey in WQE. */ 22467d6bf6b8SYongseok Koh if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1)) 22477d6bf6b8SYongseok Koh wqe->lkey = mlx5_rx_addr2mr(rxq, (uintptr_t)addr); 22487d6bf6b8SYongseok Koh /* Stash a mbuf for next replacement. */ 22497d6bf6b8SYongseok Koh if (likely(!rte_mempool_get(rxq->mprq_mp, (void **)&rep))) 22507d6bf6b8SYongseok Koh rxq->mprq_repl = rep; 22517d6bf6b8SYongseok Koh else 22527d6bf6b8SYongseok Koh rxq->mprq_repl = NULL; 22537d6bf6b8SYongseok Koh } 22547d6bf6b8SYongseok Koh 22557d6bf6b8SYongseok Koh /** 22567d6bf6b8SYongseok Koh * DPDK callback for RX with Multi-Packet RQ support. 22577d6bf6b8SYongseok Koh * 22587d6bf6b8SYongseok Koh * @param dpdk_rxq 22597d6bf6b8SYongseok Koh * Generic pointer to RX queue structure. 22607d6bf6b8SYongseok Koh * @param[out] pkts 22617d6bf6b8SYongseok Koh * Array to store received packets. 22627d6bf6b8SYongseok Koh * @param pkts_n 22637d6bf6b8SYongseok Koh * Maximum number of packets in array. 22647d6bf6b8SYongseok Koh * 22657d6bf6b8SYongseok Koh * @return 22667d6bf6b8SYongseok Koh * Number of packets successfully received (<= pkts_n). 22677d6bf6b8SYongseok Koh */ 22687d6bf6b8SYongseok Koh uint16_t 22697d6bf6b8SYongseok Koh mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 22707d6bf6b8SYongseok Koh { 22717d6bf6b8SYongseok Koh struct mlx5_rxq_data *rxq = dpdk_rxq; 22727d6bf6b8SYongseok Koh const unsigned int strd_n = 1 << rxq->strd_num_n; 22737d6bf6b8SYongseok Koh const unsigned int strd_sz = 1 << rxq->strd_sz_n; 22747d6bf6b8SYongseok Koh const unsigned int strd_shift = 22757d6bf6b8SYongseok Koh MLX5_MPRQ_STRIDE_SHIFT_BYTE * rxq->strd_shift_en; 22767d6bf6b8SYongseok Koh const unsigned int cq_mask = (1 << rxq->cqe_n) - 1; 22777d6bf6b8SYongseok Koh const unsigned int wq_mask = (1 << rxq->elts_n) - 1; 22787d6bf6b8SYongseok Koh volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 22797d6bf6b8SYongseok Koh unsigned int i = 0; 22803afdf157SXueming Li uint32_t rq_ci = rxq->rq_ci; 22811787eb7bSYongseok Koh uint16_t consumed_strd = rxq->consumed_strd; 22827d6bf6b8SYongseok Koh struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 22837d6bf6b8SYongseok Koh 22847d6bf6b8SYongseok Koh while (i < pkts_n) { 22857d6bf6b8SYongseok Koh struct rte_mbuf *pkt; 22867d6bf6b8SYongseok Koh void *addr; 22877d6bf6b8SYongseok Koh int ret; 22887d6bf6b8SYongseok Koh unsigned int len; 22891787eb7bSYongseok Koh uint16_t strd_cnt; 22901787eb7bSYongseok Koh uint16_t strd_idx; 22917d6bf6b8SYongseok Koh uint32_t offset; 22927d6bf6b8SYongseok Koh uint32_t byte_cnt; 22932e633f1fSYongseok Koh volatile struct mlx5_mini_cqe8 *mcqe = NULL; 22941787eb7bSYongseok Koh uint32_t rss_hash_res = 0; 22957d6bf6b8SYongseok Koh 22961787eb7bSYongseok Koh if (consumed_strd == strd_n) { 22977d6bf6b8SYongseok Koh /* Replace WQE only if the buffer is still in use. */ 22987d6bf6b8SYongseok Koh if (rte_atomic16_read(&buf->refcnt) > 1) { 22997d6bf6b8SYongseok Koh mprq_buf_replace(rxq, rq_ci & wq_mask); 23007d6bf6b8SYongseok Koh /* Release the old buffer. */ 23017d6bf6b8SYongseok Koh mlx5_mprq_buf_free(buf); 23027d6bf6b8SYongseok Koh } else if (unlikely(rxq->mprq_repl == NULL)) { 23037d6bf6b8SYongseok Koh struct mlx5_mprq_buf *rep; 23047d6bf6b8SYongseok Koh 23057d6bf6b8SYongseok Koh /* 23067d6bf6b8SYongseok Koh * Currently, the MPRQ mempool is out of buffer 23077d6bf6b8SYongseok Koh * and doing memcpy regardless of the size of Rx 23087d6bf6b8SYongseok Koh * packet. Retry allocation to get back to 23097d6bf6b8SYongseok Koh * normal. 23107d6bf6b8SYongseok Koh */ 23117d6bf6b8SYongseok Koh if (!rte_mempool_get(rxq->mprq_mp, 23127d6bf6b8SYongseok Koh (void **)&rep)) 23137d6bf6b8SYongseok Koh rxq->mprq_repl = rep; 23147d6bf6b8SYongseok Koh } 23157d6bf6b8SYongseok Koh /* Advance to the next WQE. */ 23161787eb7bSYongseok Koh consumed_strd = 0; 23177d6bf6b8SYongseok Koh ++rq_ci; 23187d6bf6b8SYongseok Koh buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 23197d6bf6b8SYongseok Koh } 23207d6bf6b8SYongseok Koh cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 23212e633f1fSYongseok Koh ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe); 23227d6bf6b8SYongseok Koh if (!ret) 23237d6bf6b8SYongseok Koh break; 23247d6bf6b8SYongseok Koh if (unlikely(ret == -1)) { 23257d6bf6b8SYongseok Koh /* RX error, packet is likely too large. */ 23267d6bf6b8SYongseok Koh ++rxq->stats.idropped; 23277d6bf6b8SYongseok Koh continue; 23287d6bf6b8SYongseok Koh } 23297d6bf6b8SYongseok Koh byte_cnt = ret; 23301787eb7bSYongseok Koh strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >> 23317d6bf6b8SYongseok Koh MLX5_MPRQ_STRIDE_NUM_SHIFT; 23321787eb7bSYongseok Koh assert(strd_cnt); 23331787eb7bSYongseok Koh consumed_strd += strd_cnt; 23347d6bf6b8SYongseok Koh if (byte_cnt & MLX5_MPRQ_FILLER_MASK) 23357d6bf6b8SYongseok Koh continue; 23361787eb7bSYongseok Koh if (mcqe == NULL) { 23371787eb7bSYongseok Koh rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res); 23381787eb7bSYongseok Koh strd_idx = rte_be_to_cpu_16(cqe->wqe_counter); 23391787eb7bSYongseok Koh } else { 23401787eb7bSYongseok Koh /* mini-CQE for MPRQ doesn't have hash result. */ 23411787eb7bSYongseok Koh strd_idx = rte_be_to_cpu_16(mcqe->stride_idx); 23421787eb7bSYongseok Koh } 23431787eb7bSYongseok Koh assert(strd_idx < strd_n); 23441787eb7bSYongseok Koh assert(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & wq_mask)); 23457d6bf6b8SYongseok Koh /* 23467d6bf6b8SYongseok Koh * Currently configured to receive a packet per a stride. But if 23477d6bf6b8SYongseok Koh * MTU is adjusted through kernel interface, device could 23487d6bf6b8SYongseok Koh * consume multiple strides without raising an error. In this 23497d6bf6b8SYongseok Koh * case, the packet should be dropped because it is bigger than 23507d6bf6b8SYongseok Koh * the max_rx_pkt_len. 23517d6bf6b8SYongseok Koh */ 23521787eb7bSYongseok Koh if (unlikely(strd_cnt > 1)) { 23537d6bf6b8SYongseok Koh ++rxq->stats.idropped; 23547d6bf6b8SYongseok Koh continue; 23557d6bf6b8SYongseok Koh } 23567d6bf6b8SYongseok Koh pkt = rte_pktmbuf_alloc(rxq->mp); 23577d6bf6b8SYongseok Koh if (unlikely(pkt == NULL)) { 23587d6bf6b8SYongseok Koh ++rxq->stats.rx_nombuf; 23597d6bf6b8SYongseok Koh break; 23607d6bf6b8SYongseok Koh } 23617d6bf6b8SYongseok Koh len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT; 23627d6bf6b8SYongseok Koh assert((int)len >= (rxq->crc_present << 2)); 23637d6bf6b8SYongseok Koh if (rxq->crc_present) 236435b2d13fSOlivier Matz len -= RTE_ETHER_CRC_LEN; 23651787eb7bSYongseok Koh offset = strd_idx * strd_sz + strd_shift; 23667d6bf6b8SYongseok Koh addr = RTE_PTR_ADD(mlx5_mprq_buf_addr(buf), offset); 23677d6bf6b8SYongseok Koh /* Initialize the offload flag. */ 23687d6bf6b8SYongseok Koh pkt->ol_flags = 0; 23697d6bf6b8SYongseok Koh /* 23707d6bf6b8SYongseok Koh * Memcpy packets to the target mbuf if: 23717d6bf6b8SYongseok Koh * - The size of packet is smaller than mprq_max_memcpy_len. 23727d6bf6b8SYongseok Koh * - Out of buffer in the Mempool for Multi-Packet RQ. 23737d6bf6b8SYongseok Koh */ 23747d6bf6b8SYongseok Koh if (len <= rxq->mprq_max_memcpy_len || rxq->mprq_repl == NULL) { 23757d6bf6b8SYongseok Koh /* 23767d6bf6b8SYongseok Koh * When memcpy'ing packet due to out-of-buffer, the 23777d6bf6b8SYongseok Koh * packet must be smaller than the target mbuf. 23787d6bf6b8SYongseok Koh */ 23797d6bf6b8SYongseok Koh if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) { 23807d6bf6b8SYongseok Koh rte_pktmbuf_free_seg(pkt); 23817d6bf6b8SYongseok Koh ++rxq->stats.idropped; 23827d6bf6b8SYongseok Koh continue; 23837d6bf6b8SYongseok Koh } 23847d6bf6b8SYongseok Koh rte_memcpy(rte_pktmbuf_mtod(pkt, void *), addr, len); 23857d6bf6b8SYongseok Koh } else { 23867d6bf6b8SYongseok Koh rte_iova_t buf_iova; 23877d6bf6b8SYongseok Koh struct rte_mbuf_ext_shared_info *shinfo; 23881787eb7bSYongseok Koh uint16_t buf_len = strd_cnt * strd_sz; 23897d6bf6b8SYongseok Koh 23907d6bf6b8SYongseok Koh /* Increment the refcnt of the whole chunk. */ 23917d6bf6b8SYongseok Koh rte_atomic16_add_return(&buf->refcnt, 1); 23927d6bf6b8SYongseok Koh assert((uint16_t)rte_atomic16_read(&buf->refcnt) <= 23937d6bf6b8SYongseok Koh strd_n + 1); 23947d6bf6b8SYongseok Koh addr = RTE_PTR_SUB(addr, RTE_PKTMBUF_HEADROOM); 23957d6bf6b8SYongseok Koh /* 23967d6bf6b8SYongseok Koh * MLX5 device doesn't use iova but it is necessary in a 23977d6bf6b8SYongseok Koh * case where the Rx packet is transmitted via a 23987d6bf6b8SYongseok Koh * different PMD. 23997d6bf6b8SYongseok Koh */ 24007d6bf6b8SYongseok Koh buf_iova = rte_mempool_virt2iova(buf) + 24017d6bf6b8SYongseok Koh RTE_PTR_DIFF(addr, buf); 24027d6bf6b8SYongseok Koh shinfo = rte_pktmbuf_ext_shinfo_init_helper(addr, 24037d6bf6b8SYongseok Koh &buf_len, mlx5_mprq_buf_free_cb, buf); 24047d6bf6b8SYongseok Koh /* 24057d6bf6b8SYongseok Koh * EXT_ATTACHED_MBUF will be set to pkt->ol_flags when 24067d6bf6b8SYongseok Koh * attaching the stride to mbuf and more offload flags 24077d6bf6b8SYongseok Koh * will be added below by calling rxq_cq_to_mbuf(). 24087d6bf6b8SYongseok Koh * Other fields will be overwritten. 24097d6bf6b8SYongseok Koh */ 24107d6bf6b8SYongseok Koh rte_pktmbuf_attach_extbuf(pkt, addr, buf_iova, buf_len, 24117d6bf6b8SYongseok Koh shinfo); 24127d6bf6b8SYongseok Koh rte_pktmbuf_reset_headroom(pkt); 24137d6bf6b8SYongseok Koh assert(pkt->ol_flags == EXT_ATTACHED_MBUF); 24147d6bf6b8SYongseok Koh /* 24157d6bf6b8SYongseok Koh * Prevent potential overflow due to MTU change through 24167d6bf6b8SYongseok Koh * kernel interface. 24177d6bf6b8SYongseok Koh */ 24187d6bf6b8SYongseok Koh if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) { 24197d6bf6b8SYongseok Koh rte_pktmbuf_free_seg(pkt); 24207d6bf6b8SYongseok Koh ++rxq->stats.idropped; 24217d6bf6b8SYongseok Koh continue; 24227d6bf6b8SYongseok Koh } 24237d6bf6b8SYongseok Koh } 24247d6bf6b8SYongseok Koh rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res); 24257d6bf6b8SYongseok Koh PKT_LEN(pkt) = len; 24267d6bf6b8SYongseok Koh DATA_LEN(pkt) = len; 24277d6bf6b8SYongseok Koh PORT(pkt) = rxq->port_id; 24287d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 24297d6bf6b8SYongseok Koh /* Increment bytes counter. */ 24307d6bf6b8SYongseok Koh rxq->stats.ibytes += PKT_LEN(pkt); 24317d6bf6b8SYongseok Koh #endif 24327d6bf6b8SYongseok Koh /* Return packet. */ 24337d6bf6b8SYongseok Koh *(pkts++) = pkt; 24347d6bf6b8SYongseok Koh ++i; 24357d6bf6b8SYongseok Koh } 24367d6bf6b8SYongseok Koh /* Update the consumer indexes. */ 24371787eb7bSYongseok Koh rxq->consumed_strd = consumed_strd; 24380cfdc180SYongseok Koh rte_cio_wmb(); 24397d6bf6b8SYongseok Koh *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 24407d6bf6b8SYongseok Koh if (rq_ci != rxq->rq_ci) { 24417d6bf6b8SYongseok Koh rxq->rq_ci = rq_ci; 24420cfdc180SYongseok Koh rte_cio_wmb(); 24437d6bf6b8SYongseok Koh *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 24447d6bf6b8SYongseok Koh } 24457d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 24467d6bf6b8SYongseok Koh /* Increment packets counter. */ 24477d6bf6b8SYongseok Koh rxq->stats.ipackets += i; 24487d6bf6b8SYongseok Koh #endif 24497d6bf6b8SYongseok Koh return i; 24507d6bf6b8SYongseok Koh } 24517d6bf6b8SYongseok Koh 24522e22920bSAdrien Mazarguil /** 24532e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 24542e22920bSAdrien Mazarguil * 24552e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 24562e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 24572e22920bSAdrien Mazarguil * 24582e22920bSAdrien Mazarguil * @param dpdk_txq 24592e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 24602e22920bSAdrien Mazarguil * @param[in] pkts 24612e22920bSAdrien Mazarguil * Packets to transmit. 24622e22920bSAdrien Mazarguil * @param pkts_n 24632e22920bSAdrien Mazarguil * Number of packets in array. 24642e22920bSAdrien Mazarguil * 24652e22920bSAdrien Mazarguil * @return 24662e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 24672e22920bSAdrien Mazarguil */ 24682e22920bSAdrien Mazarguil uint16_t 246956f08e16SNélio Laranjeiro removed_tx_burst(void *dpdk_txq __rte_unused, 247056f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 247156f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 24722e22920bSAdrien Mazarguil { 24732aac5b5dSYongseok Koh rte_mb(); 24742e22920bSAdrien Mazarguil return 0; 24752e22920bSAdrien Mazarguil } 24762e22920bSAdrien Mazarguil 24772e22920bSAdrien Mazarguil /** 24782e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 24792e22920bSAdrien Mazarguil * 24802e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 24812e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 24822e22920bSAdrien Mazarguil * 24832e22920bSAdrien Mazarguil * @param dpdk_rxq 24842e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 24852e22920bSAdrien Mazarguil * @param[out] pkts 24862e22920bSAdrien Mazarguil * Array to store received packets. 24872e22920bSAdrien Mazarguil * @param pkts_n 24882e22920bSAdrien Mazarguil * Maximum number of packets in array. 24892e22920bSAdrien Mazarguil * 24902e22920bSAdrien Mazarguil * @return 24912e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 24922e22920bSAdrien Mazarguil */ 24932e22920bSAdrien Mazarguil uint16_t 249456f08e16SNélio Laranjeiro removed_rx_burst(void *dpdk_txq __rte_unused, 249556f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 249656f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 24972e22920bSAdrien Mazarguil { 24982aac5b5dSYongseok Koh rte_mb(); 24992e22920bSAdrien Mazarguil return 0; 25002e22920bSAdrien Mazarguil } 25016cb559d6SYongseok Koh 25026cb559d6SYongseok Koh /* 25036cb559d6SYongseok Koh * Vectorized Rx/Tx routines are not compiled in when required vector 25046cb559d6SYongseok Koh * instructions are not supported on a target architecture. The following null 25056cb559d6SYongseok Koh * stubs are needed for linkage when those are not included outside of this file 25066cb559d6SYongseok Koh * (e.g. mlx5_rxtx_vec_sse.c for x86). 25076cb559d6SYongseok Koh */ 25086cb559d6SYongseok Koh 250981bede55SKeith Wiles __rte_weak uint16_t 251056f08e16SNélio Laranjeiro mlx5_tx_burst_raw_vec(void *dpdk_txq __rte_unused, 251156f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 251256f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 25136cb559d6SYongseok Koh { 25146cb559d6SYongseok Koh return 0; 25156cb559d6SYongseok Koh } 25166cb559d6SYongseok Koh 251781bede55SKeith Wiles __rte_weak uint16_t 251856f08e16SNélio Laranjeiro mlx5_tx_burst_vec(void *dpdk_txq __rte_unused, 251956f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 252056f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 25216cb559d6SYongseok Koh { 25226cb559d6SYongseok Koh return 0; 25236cb559d6SYongseok Koh } 25246cb559d6SYongseok Koh 252581bede55SKeith Wiles __rte_weak uint16_t 252656f08e16SNélio Laranjeiro mlx5_rx_burst_vec(void *dpdk_txq __rte_unused, 252756f08e16SNélio Laranjeiro struct rte_mbuf **pkts __rte_unused, 252856f08e16SNélio Laranjeiro uint16_t pkts_n __rte_unused) 25296cb559d6SYongseok Koh { 25306cb559d6SYongseok Koh return 0; 25316cb559d6SYongseok Koh } 25326cb559d6SYongseok Koh 253381bede55SKeith Wiles __rte_weak int 2534af4f09f2SNélio Laranjeiro mlx5_check_raw_vec_tx_support(struct rte_eth_dev *dev __rte_unused) 25356cb559d6SYongseok Koh { 25366cb559d6SYongseok Koh return -ENOTSUP; 25376cb559d6SYongseok Koh } 25386cb559d6SYongseok Koh 253981bede55SKeith Wiles __rte_weak int 2540af4f09f2SNélio Laranjeiro mlx5_check_vec_tx_support(struct rte_eth_dev *dev __rte_unused) 25416cb559d6SYongseok Koh { 25426cb559d6SYongseok Koh return -ENOTSUP; 25436cb559d6SYongseok Koh } 25446cb559d6SYongseok Koh 254581bede55SKeith Wiles __rte_weak int 2546af4f09f2SNélio Laranjeiro mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused) 25476cb559d6SYongseok Koh { 25486cb559d6SYongseok Koh return -ENOTSUP; 25496cb559d6SYongseok Koh } 25506cb559d6SYongseok Koh 255181bede55SKeith Wiles __rte_weak int 2552af4f09f2SNélio Laranjeiro mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused) 25536cb559d6SYongseok Koh { 25546cb559d6SYongseok Koh return -ENOTSUP; 25556cb559d6SYongseok Koh } 2556