12e22920bSAdrien Mazarguil /*- 22e22920bSAdrien Mazarguil * BSD LICENSE 32e22920bSAdrien Mazarguil * 42e22920bSAdrien Mazarguil * Copyright 2015 6WIND S.A. 52e22920bSAdrien Mazarguil * Copyright 2015 Mellanox. 62e22920bSAdrien Mazarguil * 72e22920bSAdrien Mazarguil * Redistribution and use in source and binary forms, with or without 82e22920bSAdrien Mazarguil * modification, are permitted provided that the following conditions 92e22920bSAdrien Mazarguil * are met: 102e22920bSAdrien Mazarguil * 112e22920bSAdrien Mazarguil * * Redistributions of source code must retain the above copyright 122e22920bSAdrien Mazarguil * notice, this list of conditions and the following disclaimer. 132e22920bSAdrien Mazarguil * * Redistributions in binary form must reproduce the above copyright 142e22920bSAdrien Mazarguil * notice, this list of conditions and the following disclaimer in 152e22920bSAdrien Mazarguil * the documentation and/or other materials provided with the 162e22920bSAdrien Mazarguil * distribution. 172e22920bSAdrien Mazarguil * * Neither the name of 6WIND S.A. nor the names of its 182e22920bSAdrien Mazarguil * contributors may be used to endorse or promote products derived 192e22920bSAdrien Mazarguil * from this software without specific prior written permission. 202e22920bSAdrien Mazarguil * 212e22920bSAdrien Mazarguil * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 222e22920bSAdrien Mazarguil * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 232e22920bSAdrien Mazarguil * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 242e22920bSAdrien Mazarguil * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 252e22920bSAdrien Mazarguil * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 262e22920bSAdrien Mazarguil * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 272e22920bSAdrien Mazarguil * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 282e22920bSAdrien Mazarguil * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 292e22920bSAdrien Mazarguil * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 302e22920bSAdrien Mazarguil * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 312e22920bSAdrien Mazarguil * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 322e22920bSAdrien Mazarguil */ 332e22920bSAdrien Mazarguil 342e22920bSAdrien Mazarguil #include <assert.h> 352e22920bSAdrien Mazarguil #include <stdint.h> 362e22920bSAdrien Mazarguil #include <string.h> 372e22920bSAdrien Mazarguil #include <stdlib.h> 382e22920bSAdrien Mazarguil 392e22920bSAdrien Mazarguil /* Verbs header. */ 402e22920bSAdrien Mazarguil /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */ 412e22920bSAdrien Mazarguil #ifdef PEDANTIC 42fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic" 432e22920bSAdrien Mazarguil #endif 442e22920bSAdrien Mazarguil #include <infiniband/verbs.h> 456218063bSNélio Laranjeiro #include <infiniband/mlx5_hw.h> 466218063bSNélio Laranjeiro #include <infiniband/arch.h> 472e22920bSAdrien Mazarguil #ifdef PEDANTIC 48fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 492e22920bSAdrien Mazarguil #endif 502e22920bSAdrien Mazarguil 512e22920bSAdrien Mazarguil /* DPDK headers don't like -pedantic. */ 522e22920bSAdrien Mazarguil #ifdef PEDANTIC 53fc5b160fSBruce Richardson #pragma GCC diagnostic ignored "-Wpedantic" 542e22920bSAdrien Mazarguil #endif 552e22920bSAdrien Mazarguil #include <rte_mbuf.h> 562e22920bSAdrien Mazarguil #include <rte_mempool.h> 572e22920bSAdrien Mazarguil #include <rte_prefetch.h> 582e22920bSAdrien Mazarguil #include <rte_common.h> 592e22920bSAdrien Mazarguil #include <rte_branch_prediction.h> 606218063bSNélio Laranjeiro #include <rte_ether.h> 612e22920bSAdrien Mazarguil #ifdef PEDANTIC 62fc5b160fSBruce Richardson #pragma GCC diagnostic error "-Wpedantic" 632e22920bSAdrien Mazarguil #endif 642e22920bSAdrien Mazarguil 652e22920bSAdrien Mazarguil #include "mlx5.h" 662e22920bSAdrien Mazarguil #include "mlx5_utils.h" 672e22920bSAdrien Mazarguil #include "mlx5_rxtx.h" 68f3db9489SYaacov Hazan #include "mlx5_autoconf.h" 692e22920bSAdrien Mazarguil #include "mlx5_defs.h" 706218063bSNélio Laranjeiro #include "mlx5_prm.h" 716218063bSNélio Laranjeiro 72c0583d98SJerin Jacob static __rte_always_inline uint32_t 73c0583d98SJerin Jacob rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe); 74ff1807a3SNélio Laranjeiro 75c0583d98SJerin Jacob static __rte_always_inline int 76ff1807a3SNélio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 77c0583d98SJerin Jacob uint16_t cqe_cnt, uint32_t *rss_hash); 78ff1807a3SNélio Laranjeiro 79c0583d98SJerin Jacob static __rte_always_inline uint32_t 80c0583d98SJerin Jacob rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe); 81ff1807a3SNélio Laranjeiro 826cb559d6SYongseok Koh /* 836cb559d6SYongseok Koh * The index to the array should have: 846cb559d6SYongseok Koh * bit[1:0] = l3_hdr_type, bit[2] = tunneled, bit[3] = outer_l3_type 8599c12dccSNélio Laranjeiro */ 866cb559d6SYongseok Koh const uint32_t mlx5_ptype_table[] = { 876cb559d6SYongseok Koh RTE_PTYPE_UNKNOWN, 886cb559d6SYongseok Koh RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, /* b0001 */ 896cb559d6SYongseok Koh RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, /* b0010 */ 906cb559d6SYongseok Koh RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN, 916cb559d6SYongseok Koh RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 926cb559d6SYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, /* b0101 */ 936cb559d6SYongseok Koh RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | 946cb559d6SYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, /* b0110 */ 956cb559d6SYongseok Koh RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN, 966cb559d6SYongseok Koh RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, /* b1001 */ 976cb559d6SYongseok Koh RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, /* b1010 */ 986cb559d6SYongseok Koh RTE_PTYPE_UNKNOWN, RTE_PTYPE_UNKNOWN, 996cb559d6SYongseok Koh RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1006cb559d6SYongseok Koh RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, /* b1101 */ 1016cb559d6SYongseok Koh RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | 1026cb559d6SYongseok Koh RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, /* b1110 */ 1036cb559d6SYongseok Koh RTE_PTYPE_ALL_MASK /* b1111 */ 1046cb559d6SYongseok Koh }; 105fdcb0f53SNélio Laranjeiro 1062e22920bSAdrien Mazarguil /** 1076ce84bd8SYongseok Koh * Return the size of tailroom of WQ. 1086ce84bd8SYongseok Koh * 1096ce84bd8SYongseok Koh * @param txq 1106ce84bd8SYongseok Koh * Pointer to TX queue structure. 1116ce84bd8SYongseok Koh * @param addr 1126ce84bd8SYongseok Koh * Pointer to tail of WQ. 1136ce84bd8SYongseok Koh * 1146ce84bd8SYongseok Koh * @return 1156ce84bd8SYongseok Koh * Size of tailroom. 1166ce84bd8SYongseok Koh */ 1176ce84bd8SYongseok Koh static inline size_t 1186ce84bd8SYongseok Koh tx_mlx5_wq_tailroom(struct txq *txq, void *addr) 1196ce84bd8SYongseok Koh { 1206ce84bd8SYongseok Koh size_t tailroom; 1216ce84bd8SYongseok Koh tailroom = (uintptr_t)(txq->wqes) + 1226ce84bd8SYongseok Koh (1 << txq->wqe_n) * MLX5_WQE_SIZE - 1236ce84bd8SYongseok Koh (uintptr_t)addr; 1246ce84bd8SYongseok Koh return tailroom; 1256ce84bd8SYongseok Koh } 1266ce84bd8SYongseok Koh 1276ce84bd8SYongseok Koh /** 1286ce84bd8SYongseok Koh * Copy data to tailroom of circular queue. 1296ce84bd8SYongseok Koh * 1306ce84bd8SYongseok Koh * @param dst 1316ce84bd8SYongseok Koh * Pointer to destination. 1326ce84bd8SYongseok Koh * @param src 1336ce84bd8SYongseok Koh * Pointer to source. 1346ce84bd8SYongseok Koh * @param n 1356ce84bd8SYongseok Koh * Number of bytes to copy. 1366ce84bd8SYongseok Koh * @param base 1376ce84bd8SYongseok Koh * Pointer to head of queue. 1386ce84bd8SYongseok Koh * @param tailroom 1396ce84bd8SYongseok Koh * Size of tailroom from dst. 1406ce84bd8SYongseok Koh * 1416ce84bd8SYongseok Koh * @return 1426ce84bd8SYongseok Koh * Pointer after copied data. 1436ce84bd8SYongseok Koh */ 1446ce84bd8SYongseok Koh static inline void * 1456ce84bd8SYongseok Koh mlx5_copy_to_wq(void *dst, const void *src, size_t n, 1466ce84bd8SYongseok Koh void *base, size_t tailroom) 1476ce84bd8SYongseok Koh { 1486ce84bd8SYongseok Koh void *ret; 1496ce84bd8SYongseok Koh 1506ce84bd8SYongseok Koh if (n > tailroom) { 1516ce84bd8SYongseok Koh rte_memcpy(dst, src, tailroom); 1526ce84bd8SYongseok Koh rte_memcpy(base, (void *)((uintptr_t)src + tailroom), 1536ce84bd8SYongseok Koh n - tailroom); 1546ce84bd8SYongseok Koh ret = (uint8_t *)base + n - tailroom; 1556ce84bd8SYongseok Koh } else { 1566ce84bd8SYongseok Koh rte_memcpy(dst, src, n); 1576ce84bd8SYongseok Koh ret = (n == tailroom) ? base : (uint8_t *)dst + n; 1586ce84bd8SYongseok Koh } 1596ce84bd8SYongseok Koh return ret; 1606ce84bd8SYongseok Koh } 1616ce84bd8SYongseok Koh 1626ce84bd8SYongseok Koh /** 1638788fec1SOlivier Matz * DPDK callback to check the status of a tx descriptor. 1648788fec1SOlivier Matz * 1658788fec1SOlivier Matz * @param tx_queue 1668788fec1SOlivier Matz * The tx queue. 1678788fec1SOlivier Matz * @param[in] offset 1688788fec1SOlivier Matz * The index of the descriptor in the ring. 1698788fec1SOlivier Matz * 1708788fec1SOlivier Matz * @return 1718788fec1SOlivier Matz * The status of the tx descriptor. 1728788fec1SOlivier Matz */ 1738788fec1SOlivier Matz int 1748788fec1SOlivier Matz mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset) 1758788fec1SOlivier Matz { 1768788fec1SOlivier Matz struct txq *txq = tx_queue; 1778c819a69SYongseok Koh uint16_t used; 1788788fec1SOlivier Matz 1796cb559d6SYongseok Koh mlx5_tx_complete(txq); 1808c819a69SYongseok Koh used = txq->elts_head - txq->elts_tail; 1818788fec1SOlivier Matz if (offset < used) 1828788fec1SOlivier Matz return RTE_ETH_TX_DESC_FULL; 1838788fec1SOlivier Matz return RTE_ETH_TX_DESC_DONE; 1848788fec1SOlivier Matz } 1858788fec1SOlivier Matz 1868788fec1SOlivier Matz /** 1878788fec1SOlivier Matz * DPDK callback to check the status of a rx descriptor. 1888788fec1SOlivier Matz * 1898788fec1SOlivier Matz * @param rx_queue 1908788fec1SOlivier Matz * The rx queue. 1918788fec1SOlivier Matz * @param[in] offset 1928788fec1SOlivier Matz * The index of the descriptor in the ring. 1938788fec1SOlivier Matz * 1948788fec1SOlivier Matz * @return 1958788fec1SOlivier Matz * The status of the tx descriptor. 1968788fec1SOlivier Matz */ 1978788fec1SOlivier Matz int 1988788fec1SOlivier Matz mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 1998788fec1SOlivier Matz { 2008788fec1SOlivier Matz struct rxq *rxq = rx_queue; 2018788fec1SOlivier Matz struct rxq_zip *zip = &rxq->zip; 2028788fec1SOlivier Matz volatile struct mlx5_cqe *cqe; 2038788fec1SOlivier Matz const unsigned int cqe_n = (1 << rxq->cqe_n); 2048788fec1SOlivier Matz const unsigned int cqe_cnt = cqe_n - 1; 2058788fec1SOlivier Matz unsigned int cq_ci; 2068788fec1SOlivier Matz unsigned int used; 2078788fec1SOlivier Matz 2088788fec1SOlivier Matz /* if we are processing a compressed cqe */ 2098788fec1SOlivier Matz if (zip->ai) { 2108788fec1SOlivier Matz used = zip->cqe_cnt - zip->ca; 2118788fec1SOlivier Matz cq_ci = zip->cq_ci; 2128788fec1SOlivier Matz } else { 2138788fec1SOlivier Matz used = 0; 2148788fec1SOlivier Matz cq_ci = rxq->cq_ci; 2158788fec1SOlivier Matz } 2168788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 2178788fec1SOlivier Matz while (check_cqe(cqe, cqe_n, cq_ci) == 0) { 2188788fec1SOlivier Matz int8_t op_own; 2198788fec1SOlivier Matz unsigned int n; 2208788fec1SOlivier Matz 2218788fec1SOlivier Matz op_own = cqe->op_own; 2228788fec1SOlivier Matz if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 2238788fec1SOlivier Matz n = ntohl(cqe->byte_cnt); 2248788fec1SOlivier Matz else 2258788fec1SOlivier Matz n = 1; 2268788fec1SOlivier Matz cq_ci += n; 2278788fec1SOlivier Matz used += n; 2288788fec1SOlivier Matz cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 2298788fec1SOlivier Matz } 2308788fec1SOlivier Matz used = RTE_MIN(used, (1U << rxq->elts_n) - 1); 2318788fec1SOlivier Matz if (offset < used) 2328788fec1SOlivier Matz return RTE_ETH_RX_DESC_DONE; 2338788fec1SOlivier Matz return RTE_ETH_RX_DESC_AVAIL; 2348788fec1SOlivier Matz } 2358788fec1SOlivier Matz 2368788fec1SOlivier Matz /** 2372e22920bSAdrien Mazarguil * DPDK callback for TX. 2382e22920bSAdrien Mazarguil * 2392e22920bSAdrien Mazarguil * @param dpdk_txq 2402e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 2412e22920bSAdrien Mazarguil * @param[in] pkts 2422e22920bSAdrien Mazarguil * Packets to transmit. 2432e22920bSAdrien Mazarguil * @param pkts_n 2442e22920bSAdrien Mazarguil * Number of packets in array. 2452e22920bSAdrien Mazarguil * 2462e22920bSAdrien Mazarguil * @return 2472e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 2482e22920bSAdrien Mazarguil */ 2492e22920bSAdrien Mazarguil uint16_t 2502e22920bSAdrien Mazarguil mlx5_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 2512e22920bSAdrien Mazarguil { 2522e22920bSAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq; 2531d88ba17SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 2548c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 2558c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 256c3d62cc9SAdrien Mazarguil unsigned int i = 0; 257a5bf6af9SAdrien Mazarguil unsigned int j = 0; 2583f13f8c2SShahaf Shuler unsigned int k = 0; 2598c819a69SYongseok Koh uint16_t max_elts; 260ab76eab3SYongseok Koh unsigned int max_inline = txq->max_inline; 261ab76eab3SYongseok Koh const unsigned int inline_en = !!max_inline && txq->inline_en; 262f04f1d51SNélio Laranjeiro uint16_t max_wqe; 263c305090bSAdrien Mazarguil unsigned int comp; 2649a7fa9f7SNélio Laranjeiro volatile struct mlx5_wqe_v *wqe = NULL; 265ac180a21SYongseok Koh volatile struct mlx5_wqe_ctrl *last_wqe = NULL; 2666579c27cSNélio Laranjeiro unsigned int segs_n = 0; 2676579c27cSNélio Laranjeiro struct rte_mbuf *buf = NULL; 2686579c27cSNélio Laranjeiro uint8_t *raw; 2692e22920bSAdrien Mazarguil 2701d88ba17SNélio Laranjeiro if (unlikely(!pkts_n)) 2711d88ba17SNélio Laranjeiro return 0; 2725e1d11ecSNelio Laranjeiro /* Prefetch first packet cacheline. */ 273c3d62cc9SAdrien Mazarguil rte_prefetch0(*pkts); 2741d88ba17SNélio Laranjeiro /* Start processing. */ 2756cb559d6SYongseok Koh mlx5_tx_complete(txq); 2768c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 277f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 278f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 279f04f1d51SNélio Laranjeiro return 0; 280c3d62cc9SAdrien Mazarguil do { 2819a7fa9f7SNélio Laranjeiro volatile rte_v128u32_t *dseg = NULL; 282573f54afSNélio Laranjeiro uint32_t length; 2838688b2f8SNélio Laranjeiro unsigned int ds = 0; 284ac180a21SYongseok Koh unsigned int sg = 0; /* counter of additional segs attached. */ 2856579c27cSNélio Laranjeiro uintptr_t addr; 2869a7fa9f7SNélio Laranjeiro uint64_t naddr; 2870d637a34SNélio Laranjeiro uint16_t pkt_inline_sz = MLX5_WQE_DWORD_SIZE + 2; 2883f13f8c2SShahaf Shuler uint16_t tso_header_sz = 0; 289eef822ddSNélio Laranjeiro uint16_t ehdr; 2909a7fa9f7SNélio Laranjeiro uint8_t cs_flags = 0; 2913f13f8c2SShahaf Shuler uint64_t tso = 0; 29283daf156SShahaf Shuler uint16_t tso_segsz = 0; 2936579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 2946579c27cSNélio Laranjeiro uint32_t total_length = 0; 2956579c27cSNélio Laranjeiro #endif 2962e22920bSAdrien Mazarguil 2976579c27cSNélio Laranjeiro /* first_seg */ 2983730e6c6SYongseok Koh buf = *pkts; 2996579c27cSNélio Laranjeiro segs_n = buf->nb_segs; 300c3d62cc9SAdrien Mazarguil /* 301c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 302c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 303c3d62cc9SAdrien Mazarguil */ 304a5bf6af9SAdrien Mazarguil assert(segs_n); 3058c819a69SYongseok Koh if (max_elts < segs_n) 306c3d62cc9SAdrien Mazarguil break; 3078c819a69SYongseok Koh max_elts -= segs_n; 3086579c27cSNélio Laranjeiro --segs_n; 309f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 310f04f1d51SNélio Laranjeiro break; 3119a7fa9f7SNélio Laranjeiro wqe = (volatile struct mlx5_wqe_v *) 312fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci); 313fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 3143730e6c6SYongseok Koh if (pkts_n - i > 1) 3153730e6c6SYongseok Koh rte_prefetch0(*(pkts + 1)); 3166579c27cSNélio Laranjeiro addr = rte_pktmbuf_mtod(buf, uintptr_t); 3172e22920bSAdrien Mazarguil length = DATA_LEN(buf); 318eef822ddSNélio Laranjeiro ehdr = (((uint8_t *)addr)[1] << 8) | 319eef822ddSNélio Laranjeiro ((uint8_t *)addr)[0]; 3206579c27cSNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 3216579c27cSNélio Laranjeiro total_length = length; 3226579c27cSNélio Laranjeiro #endif 323959be52eSNélio Laranjeiro if (length < (MLX5_WQE_DWORD_SIZE + 2)) 324959be52eSNélio Laranjeiro break; 3252e22920bSAdrien Mazarguil /* Update element. */ 3268c819a69SYongseok Koh (*txq->elts)[elts_head & elts_m] = buf; 3275e1d11ecSNelio Laranjeiro /* Prefetch next buffer data. */ 3283730e6c6SYongseok Koh if (pkts_n - i > 1) 3293730e6c6SYongseok Koh rte_prefetch0( 3303730e6c6SYongseok Koh rte_pktmbuf_mtod(*(pkts + 1), volatile void *)); 3311d88ba17SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 3321d88ba17SNélio Laranjeiro if (buf->ol_flags & 3331d88ba17SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) { 334f5fde520SShahaf Shuler const uint64_t is_tunneled = buf->ol_flags & 335f5fde520SShahaf Shuler (PKT_TX_TUNNEL_GRE | 336f5fde520SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 337f5fde520SShahaf Shuler 338f5fde520SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 339f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_INNER_CSUM | 340f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_INNER_CSUM; 341f5fde520SShahaf Shuler if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM) 342f5fde520SShahaf Shuler cs_flags |= MLX5_ETH_WQE_L3_CSUM; 343f5fde520SShahaf Shuler } else { 344f5fde520SShahaf Shuler cs_flags = MLX5_ETH_WQE_L3_CSUM | 345f5fde520SShahaf Shuler MLX5_ETH_WQE_L4_CSUM; 346f5fde520SShahaf Shuler } 3471d88ba17SNélio Laranjeiro } 348b8fe952eSNélio Laranjeiro raw = ((uint8_t *)(uintptr_t)wqe) + 2 * MLX5_WQE_DWORD_SIZE; 3496579c27cSNélio Laranjeiro /* Replace the Ethernet type by the VLAN if necessary. */ 3506579c27cSNélio Laranjeiro if (buf->ol_flags & PKT_TX_VLAN_PKT) { 3516579c27cSNélio Laranjeiro uint32_t vlan = htonl(0x81000000 | buf->vlan_tci); 3520d637a34SNélio Laranjeiro unsigned int len = 2 * ETHER_ADDR_LEN - 2; 3536579c27cSNélio Laranjeiro 3540d637a34SNélio Laranjeiro addr += 2; 3550d637a34SNélio Laranjeiro length -= 2; 3560d637a34SNélio Laranjeiro /* Copy Destination and source mac address. */ 3570d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr), len); 3580d637a34SNélio Laranjeiro /* Copy VLAN. */ 3590d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len, &vlan, sizeof(vlan)); 3600d637a34SNélio Laranjeiro /* Copy missing two bytes to end the DSeg. */ 3610d637a34SNélio Laranjeiro memcpy((uint8_t *)raw + len + sizeof(vlan), 3620d637a34SNélio Laranjeiro ((uint8_t *)addr) + len, 2); 3630d637a34SNélio Laranjeiro addr += len + 2; 3640d637a34SNélio Laranjeiro length -= (len + 2); 3650d637a34SNélio Laranjeiro } else { 3660d637a34SNélio Laranjeiro memcpy((uint8_t *)raw, ((uint8_t *)addr) + 2, 3670d637a34SNélio Laranjeiro MLX5_WQE_DWORD_SIZE); 3680d637a34SNélio Laranjeiro length -= pkt_inline_sz; 3690d637a34SNélio Laranjeiro addr += pkt_inline_sz; 3706579c27cSNélio Laranjeiro } 3713f13f8c2SShahaf Shuler if (txq->tso_en) { 3723f13f8c2SShahaf Shuler tso = buf->ol_flags & PKT_TX_TCP_SEG; 3733f13f8c2SShahaf Shuler if (tso) { 3743f13f8c2SShahaf Shuler uintptr_t end = (uintptr_t) 3753f13f8c2SShahaf Shuler (((uintptr_t)txq->wqes) + 3763f13f8c2SShahaf Shuler (1 << txq->wqe_n) * 3773f13f8c2SShahaf Shuler MLX5_WQE_SIZE); 3783f13f8c2SShahaf Shuler unsigned int copy_b; 3793f13f8c2SShahaf Shuler uint8_t vlan_sz = (buf->ol_flags & 3803f13f8c2SShahaf Shuler PKT_TX_VLAN_PKT) ? 4 : 0; 381b247f346SShahaf Shuler const uint64_t is_tunneled = 382b247f346SShahaf Shuler buf->ol_flags & 383b247f346SShahaf Shuler (PKT_TX_TUNNEL_GRE | 384b247f346SShahaf Shuler PKT_TX_TUNNEL_VXLAN); 3853f13f8c2SShahaf Shuler 3863f13f8c2SShahaf Shuler tso_header_sz = buf->l2_len + vlan_sz + 3873f13f8c2SShahaf Shuler buf->l3_len + buf->l4_len; 38883daf156SShahaf Shuler tso_segsz = buf->tso_segsz; 3893f13f8c2SShahaf Shuler 390b247f346SShahaf Shuler if (is_tunneled && txq->tunnel_en) { 391b247f346SShahaf Shuler tso_header_sz += buf->outer_l2_len + 392b247f346SShahaf Shuler buf->outer_l3_len; 3932a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM; 3942a6c96beSShahaf Shuler } else { 3952a6c96beSShahaf Shuler cs_flags |= MLX5_ETH_WQE_L4_CSUM; 396b247f346SShahaf Shuler } 3973f13f8c2SShahaf Shuler if (unlikely(tso_header_sz > 3983f13f8c2SShahaf Shuler MLX5_MAX_TSO_HEADER)) 3993f13f8c2SShahaf Shuler break; 4003f13f8c2SShahaf Shuler copy_b = tso_header_sz - pkt_inline_sz; 4013f13f8c2SShahaf Shuler /* First seg must contain all headers. */ 4023f13f8c2SShahaf Shuler assert(copy_b <= length); 4033f13f8c2SShahaf Shuler raw += MLX5_WQE_DWORD_SIZE; 4043f13f8c2SShahaf Shuler if (copy_b && 4053f13f8c2SShahaf Shuler ((end - (uintptr_t)raw) > copy_b)) { 4063f13f8c2SShahaf Shuler uint16_t n = (MLX5_WQE_DS(copy_b) - 4073f13f8c2SShahaf Shuler 1 + 3) / 4; 4083f13f8c2SShahaf Shuler 4093f13f8c2SShahaf Shuler if (unlikely(max_wqe < n)) 4103f13f8c2SShahaf Shuler break; 4113f13f8c2SShahaf Shuler max_wqe -= n; 4123f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 4133f13f8c2SShahaf Shuler (void *)addr, copy_b); 4143f13f8c2SShahaf Shuler addr += copy_b; 4153f13f8c2SShahaf Shuler length -= copy_b; 4163f13f8c2SShahaf Shuler pkt_inline_sz += copy_b; 4173f13f8c2SShahaf Shuler /* 4183f13f8c2SShahaf Shuler * Another DWORD will be added 4193f13f8c2SShahaf Shuler * in the inline part. 4203f13f8c2SShahaf Shuler */ 4213f13f8c2SShahaf Shuler raw += MLX5_WQE_DS(copy_b) * 4223f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE - 4233f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 4243f13f8c2SShahaf Shuler } else { 4253f13f8c2SShahaf Shuler /* NOP WQE. */ 4263f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 4273f13f8c2SShahaf Shuler htonl(txq->wqe_ci << 8), 4283f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | 1), 4293f13f8c2SShahaf Shuler 0, 4303f13f8c2SShahaf Shuler 0, 4313f13f8c2SShahaf Shuler }; 4323f13f8c2SShahaf Shuler ds = 1; 4333f13f8c2SShahaf Shuler total_length = 0; 4343f13f8c2SShahaf Shuler k++; 4353f13f8c2SShahaf Shuler goto next_wqe; 4363f13f8c2SShahaf Shuler } 4373f13f8c2SShahaf Shuler } 4383f13f8c2SShahaf Shuler } 4396579c27cSNélio Laranjeiro /* Inline if enough room. */ 440ab76eab3SYongseok Koh if (inline_en || tso) { 441fdcb0f53SNélio Laranjeiro uintptr_t end = (uintptr_t) 442fdcb0f53SNélio Laranjeiro (((uintptr_t)txq->wqes) + 443fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * MLX5_WQE_SIZE); 444ab76eab3SYongseok Koh unsigned int inline_room = max_inline * 4458fcd6c2cSNélio Laranjeiro RTE_CACHE_LINE_SIZE - 4463f13f8c2SShahaf Shuler (pkt_inline_sz - 2); 447ab76eab3SYongseok Koh uintptr_t addr_end = (addr + inline_room) & 4486579c27cSNélio Laranjeiro ~(RTE_CACHE_LINE_SIZE - 1); 4498fcd6c2cSNélio Laranjeiro unsigned int copy_b = (addr_end > addr) ? 4508fcd6c2cSNélio Laranjeiro RTE_MIN((addr_end - addr), length) : 4518fcd6c2cSNélio Laranjeiro 0; 4526579c27cSNélio Laranjeiro 4538fcd6c2cSNélio Laranjeiro raw += MLX5_WQE_DWORD_SIZE; 4548fcd6c2cSNélio Laranjeiro if (copy_b && ((end - (uintptr_t)raw) > copy_b)) { 455f04f1d51SNélio Laranjeiro /* 456f04f1d51SNélio Laranjeiro * One Dseg remains in the current WQE. To 457f04f1d51SNélio Laranjeiro * keep the computation positive, it is 458f04f1d51SNélio Laranjeiro * removed after the bytes to Dseg conversion. 459f04f1d51SNélio Laranjeiro */ 4608fcd6c2cSNélio Laranjeiro uint16_t n = (MLX5_WQE_DS(copy_b) - 1 + 3) / 4; 4618fcd6c2cSNélio Laranjeiro 462f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < n)) 463f04f1d51SNélio Laranjeiro break; 464f04f1d51SNélio Laranjeiro max_wqe -= n; 4653f13f8c2SShahaf Shuler if (tso) { 4663f13f8c2SShahaf Shuler uint32_t inl = 4673f13f8c2SShahaf Shuler htonl(copy_b | MLX5_INLINE_SEG); 4683f13f8c2SShahaf Shuler 4693f13f8c2SShahaf Shuler pkt_inline_sz = 4703f13f8c2SShahaf Shuler MLX5_WQE_DS(tso_header_sz) * 4713f13f8c2SShahaf Shuler MLX5_WQE_DWORD_SIZE; 4723f13f8c2SShahaf Shuler rte_memcpy((void *)raw, 4733f13f8c2SShahaf Shuler (void *)&inl, sizeof(inl)); 4743f13f8c2SShahaf Shuler raw += sizeof(inl); 4753f13f8c2SShahaf Shuler pkt_inline_sz += sizeof(inl); 4763f13f8c2SShahaf Shuler } 4776579c27cSNélio Laranjeiro rte_memcpy((void *)raw, (void *)addr, copy_b); 4786579c27cSNélio Laranjeiro addr += copy_b; 4796579c27cSNélio Laranjeiro length -= copy_b; 4806579c27cSNélio Laranjeiro pkt_inline_sz += copy_b; 4816579c27cSNélio Laranjeiro } 4826579c27cSNélio Laranjeiro /* 483786b5c2dSShahaf Shuler * 2 DWORDs consumed by the WQE header + ETH segment + 4846579c27cSNélio Laranjeiro * the size of the inline part of the packet. 4856579c27cSNélio Laranjeiro */ 4866579c27cSNélio Laranjeiro ds = 2 + MLX5_WQE_DS(pkt_inline_sz - 2); 4876579c27cSNélio Laranjeiro if (length > 0) { 488f04f1d51SNélio Laranjeiro if (ds % (MLX5_WQE_SIZE / 489f04f1d51SNélio Laranjeiro MLX5_WQE_DWORD_SIZE) == 0) { 490f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 491f04f1d51SNélio Laranjeiro break; 492f04f1d51SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 493f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + 494f04f1d51SNélio Laranjeiro ds / 4); 495f04f1d51SNélio Laranjeiro } else { 4969a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 4976579c27cSNélio Laranjeiro ((uintptr_t)wqe + 4986579c27cSNélio Laranjeiro (ds * MLX5_WQE_DWORD_SIZE)); 499f04f1d51SNélio Laranjeiro } 5006579c27cSNélio Laranjeiro goto use_dseg; 5016579c27cSNélio Laranjeiro } else if (!segs_n) { 5026579c27cSNélio Laranjeiro goto next_pkt; 5036579c27cSNélio Laranjeiro } else { 504786b5c2dSShahaf Shuler /* dseg will be advance as part of next_seg */ 505786b5c2dSShahaf Shuler dseg = (volatile rte_v128u32_t *) 506786b5c2dSShahaf Shuler ((uintptr_t)wqe + 507786b5c2dSShahaf Shuler ((ds - 1) * MLX5_WQE_DWORD_SIZE)); 5086579c27cSNélio Laranjeiro goto next_seg; 5096579c27cSNélio Laranjeiro } 5106579c27cSNélio Laranjeiro } else { 5116579c27cSNélio Laranjeiro /* 5126579c27cSNélio Laranjeiro * No inline has been done in the packet, only the 5136579c27cSNélio Laranjeiro * Ethernet Header as been stored. 5146579c27cSNélio Laranjeiro */ 5159a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 5166579c27cSNélio Laranjeiro ((uintptr_t)wqe + (3 * MLX5_WQE_DWORD_SIZE)); 5176579c27cSNélio Laranjeiro ds = 3; 5186579c27cSNélio Laranjeiro use_dseg: 5196579c27cSNélio Laranjeiro /* Add the remaining packet as a simple ds. */ 5209a7fa9f7SNélio Laranjeiro naddr = htonll(addr); 5219a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 5229a7fa9f7SNélio Laranjeiro htonl(length), 5236cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 5249a7fa9f7SNélio Laranjeiro naddr, 5259a7fa9f7SNélio Laranjeiro naddr >> 32, 5266579c27cSNélio Laranjeiro }; 5276579c27cSNélio Laranjeiro ++ds; 5286579c27cSNélio Laranjeiro if (!segs_n) 5296579c27cSNélio Laranjeiro goto next_pkt; 5306579c27cSNélio Laranjeiro } 5316579c27cSNélio Laranjeiro next_seg: 5326579c27cSNélio Laranjeiro assert(buf); 5336579c27cSNélio Laranjeiro assert(ds); 5346579c27cSNélio Laranjeiro assert(wqe); 535a5bf6af9SAdrien Mazarguil /* 536a5bf6af9SAdrien Mazarguil * Spill on next WQE when the current one does not have 537a5bf6af9SAdrien Mazarguil * enough room left. Size of WQE must a be a multiple 538a5bf6af9SAdrien Mazarguil * of data segment size. 539a5bf6af9SAdrien Mazarguil */ 5408688b2f8SNélio Laranjeiro assert(!(MLX5_WQE_SIZE % MLX5_WQE_DWORD_SIZE)); 5416579c27cSNélio Laranjeiro if (!(ds % (MLX5_WQE_SIZE / MLX5_WQE_DWORD_SIZE))) { 542f04f1d51SNélio Laranjeiro if (unlikely(--max_wqe == 0)) 543f04f1d51SNélio Laranjeiro break; 5449a7fa9f7SNélio Laranjeiro dseg = (volatile rte_v128u32_t *) 545f04f1d51SNélio Laranjeiro tx_mlx5_wqe(txq, txq->wqe_ci + ds / 4); 546f04f1d51SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, 547f04f1d51SNélio Laranjeiro txq->wqe_ci + ds / 4 + 1)); 5486579c27cSNélio Laranjeiro } else { 549a5bf6af9SAdrien Mazarguil ++dseg; 5506579c27cSNélio Laranjeiro } 551a5bf6af9SAdrien Mazarguil ++ds; 552a5bf6af9SAdrien Mazarguil buf = buf->next; 553a5bf6af9SAdrien Mazarguil assert(buf); 5546579c27cSNélio Laranjeiro length = DATA_LEN(buf); 555a5bf6af9SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 5566579c27cSNélio Laranjeiro total_length += length; 557a5bf6af9SAdrien Mazarguil #endif 5586579c27cSNélio Laranjeiro /* Store segment information. */ 5599a7fa9f7SNélio Laranjeiro naddr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)); 5609a7fa9f7SNélio Laranjeiro *dseg = (rte_v128u32_t){ 5619a7fa9f7SNélio Laranjeiro htonl(length), 5626cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 5639a7fa9f7SNélio Laranjeiro naddr, 5649a7fa9f7SNélio Laranjeiro naddr >> 32, 5656579c27cSNélio Laranjeiro }; 5668c819a69SYongseok Koh (*txq->elts)[++elts_head & elts_m] = buf; 567ac180a21SYongseok Koh ++sg; 568ac180a21SYongseok Koh /* Advance counter only if all segs are successfully posted. */ 5693730e6c6SYongseok Koh if (sg < segs_n) 5706579c27cSNélio Laranjeiro goto next_seg; 5713730e6c6SYongseok Koh else 572ac180a21SYongseok Koh j += sg; 5736579c27cSNélio Laranjeiro next_pkt: 5748c819a69SYongseok Koh ++elts_head; 5753730e6c6SYongseok Koh ++pkts; 5766579c27cSNélio Laranjeiro ++i; 577b8fe952eSNélio Laranjeiro /* Initialize known and common part of the WQE structure. */ 5783f13f8c2SShahaf Shuler if (tso) { 5793f13f8c2SShahaf Shuler wqe->ctrl = (rte_v128u32_t){ 5803f13f8c2SShahaf Shuler htonl((txq->wqe_ci << 8) | MLX5_OPCODE_TSO), 5813f13f8c2SShahaf Shuler htonl(txq->qp_num_8s | ds), 5823f13f8c2SShahaf Shuler 0, 5833f13f8c2SShahaf Shuler 0, 5843f13f8c2SShahaf Shuler }; 5853f13f8c2SShahaf Shuler wqe->eseg = (rte_v128u32_t){ 5863f13f8c2SShahaf Shuler 0, 58783daf156SShahaf Shuler cs_flags | (htons(tso_segsz) << 16), 5883f13f8c2SShahaf Shuler 0, 5893f13f8c2SShahaf Shuler (ehdr << 16) | htons(tso_header_sz), 5903f13f8c2SShahaf Shuler }; 5913f13f8c2SShahaf Shuler } else { 5929a7fa9f7SNélio Laranjeiro wqe->ctrl = (rte_v128u32_t){ 5939a7fa9f7SNélio Laranjeiro htonl((txq->wqe_ci << 8) | MLX5_OPCODE_SEND), 5949a7fa9f7SNélio Laranjeiro htonl(txq->qp_num_8s | ds), 5959a7fa9f7SNélio Laranjeiro 0, 5969a7fa9f7SNélio Laranjeiro 0, 5979a7fa9f7SNélio Laranjeiro }; 5989a7fa9f7SNélio Laranjeiro wqe->eseg = (rte_v128u32_t){ 5999a7fa9f7SNélio Laranjeiro 0, 6009a7fa9f7SNélio Laranjeiro cs_flags, 6019a7fa9f7SNélio Laranjeiro 0, 602eef822ddSNélio Laranjeiro (ehdr << 16) | htons(pkt_inline_sz), 6039a7fa9f7SNélio Laranjeiro }; 6043f13f8c2SShahaf Shuler } 6053f13f8c2SShahaf Shuler next_wqe: 6066579c27cSNélio Laranjeiro txq->wqe_ci += (ds + 3) / 4; 607ac180a21SYongseok Koh /* Save the last successful WQE for completion request */ 608ac180a21SYongseok Koh last_wqe = (volatile struct mlx5_wqe_ctrl *)wqe; 60987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 610573f54afSNélio Laranjeiro /* Increment sent bytes counter. */ 6116579c27cSNélio Laranjeiro txq->stats.obytes += total_length; 61287011737SAdrien Mazarguil #endif 6133730e6c6SYongseok Koh } while (i < pkts_n); 6142e22920bSAdrien Mazarguil /* Take a shortcut if nothing must be sent. */ 6153f13f8c2SShahaf Shuler if (unlikely((i + k) == 0)) 6162e22920bSAdrien Mazarguil return 0; 6178c819a69SYongseok Koh txq->elts_head += (i + j); 618c305090bSAdrien Mazarguil /* Check whether completion threshold has been reached. */ 6193f13f8c2SShahaf Shuler comp = txq->elts_comp + i + j + k; 620c305090bSAdrien Mazarguil if (comp >= MLX5_TX_COMP_THRESH) { 621c305090bSAdrien Mazarguil /* Request completion on last WQE. */ 622ac180a21SYongseok Koh last_wqe->ctrl2 = htonl(8); 623c305090bSAdrien Mazarguil /* Save elts_head in unused "immediate" field of WQE. */ 624ac180a21SYongseok Koh last_wqe->ctrl3 = txq->elts_head; 625c305090bSAdrien Mazarguil txq->elts_comp = 0; 626c305090bSAdrien Mazarguil } else { 627c305090bSAdrien Mazarguil txq->elts_comp = comp; 628c305090bSAdrien Mazarguil } 62987011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 63087011737SAdrien Mazarguil /* Increment sent packets counter. */ 63187011737SAdrien Mazarguil txq->stats.opackets += i; 63287011737SAdrien Mazarguil #endif 6332e22920bSAdrien Mazarguil /* Ring QP doorbell. */ 634ac180a21SYongseok Koh mlx5_tx_dbrec(txq, (volatile struct mlx5_wqe *)last_wqe); 6352e22920bSAdrien Mazarguil return i; 6362e22920bSAdrien Mazarguil } 6372e22920bSAdrien Mazarguil 6382e22920bSAdrien Mazarguil /** 639230189d9SNélio Laranjeiro * Open a MPW session. 640230189d9SNélio Laranjeiro * 641230189d9SNélio Laranjeiro * @param txq 642230189d9SNélio Laranjeiro * Pointer to TX queue structure. 643230189d9SNélio Laranjeiro * @param mpw 644230189d9SNélio Laranjeiro * Pointer to MPW session structure. 645230189d9SNélio Laranjeiro * @param length 646230189d9SNélio Laranjeiro * Packet length. 647230189d9SNélio Laranjeiro */ 648230189d9SNélio Laranjeiro static inline void 649230189d9SNélio Laranjeiro mlx5_mpw_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 650230189d9SNélio Laranjeiro { 651a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 652230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg (*dseg)[MLX5_MPW_DSEG_MAX] = 653230189d9SNélio Laranjeiro (volatile struct mlx5_wqe_data_seg (*)[]) 654fdcb0f53SNélio Laranjeiro tx_mlx5_wqe(txq, idx + 1); 655230189d9SNélio Laranjeiro 656230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_OPENED; 657230189d9SNélio Laranjeiro mpw->pkts_n = 0; 658230189d9SNélio Laranjeiro mpw->len = length; 659230189d9SNélio Laranjeiro mpw->total_len = 0; 660fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 6618688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 6628688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 6638688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 6648688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 6658688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 6668688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 667c904ae25SNélio Laranjeiro (txq->wqe_ci << 8) | MLX5_OPCODE_TSO); 6688688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 6698688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 6708688b2f8SNélio Laranjeiro mpw->data.dseg[0] = (volatile struct mlx5_wqe_data_seg *) 6718688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 6728688b2f8SNélio Laranjeiro mpw->data.dseg[1] = (volatile struct mlx5_wqe_data_seg *) 6738688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (3 * MLX5_WQE_DWORD_SIZE)); 674230189d9SNélio Laranjeiro mpw->data.dseg[2] = &(*dseg)[0]; 675230189d9SNélio Laranjeiro mpw->data.dseg[3] = &(*dseg)[1]; 676230189d9SNélio Laranjeiro mpw->data.dseg[4] = &(*dseg)[2]; 677230189d9SNélio Laranjeiro } 678230189d9SNélio Laranjeiro 679230189d9SNélio Laranjeiro /** 680230189d9SNélio Laranjeiro * Close a MPW session. 681230189d9SNélio Laranjeiro * 682230189d9SNélio Laranjeiro * @param txq 683230189d9SNélio Laranjeiro * Pointer to TX queue structure. 684230189d9SNélio Laranjeiro * @param mpw 685230189d9SNélio Laranjeiro * Pointer to MPW session structure. 686230189d9SNélio Laranjeiro */ 687230189d9SNélio Laranjeiro static inline void 688230189d9SNélio Laranjeiro mlx5_mpw_close(struct txq *txq, struct mlx5_mpw *mpw) 689230189d9SNélio Laranjeiro { 690230189d9SNélio Laranjeiro unsigned int num = mpw->pkts_n; 691230189d9SNélio Laranjeiro 692230189d9SNélio Laranjeiro /* 693230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 694230189d9SNélio Laranjeiro * count as 2. 695230189d9SNélio Laranjeiro */ 6968688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | (2 + num)); 697230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 698230189d9SNélio Laranjeiro if (num < 3) 699230189d9SNélio Laranjeiro ++txq->wqe_ci; 700230189d9SNélio Laranjeiro else 701230189d9SNélio Laranjeiro txq->wqe_ci += 2; 702fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 703fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 704230189d9SNélio Laranjeiro } 705230189d9SNélio Laranjeiro 706230189d9SNélio Laranjeiro /** 707230189d9SNélio Laranjeiro * DPDK callback for TX with MPW support. 708230189d9SNélio Laranjeiro * 709230189d9SNélio Laranjeiro * @param dpdk_txq 710230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 711230189d9SNélio Laranjeiro * @param[in] pkts 712230189d9SNélio Laranjeiro * Packets to transmit. 713230189d9SNélio Laranjeiro * @param pkts_n 714230189d9SNélio Laranjeiro * Number of packets in array. 715230189d9SNélio Laranjeiro * 716230189d9SNélio Laranjeiro * @return 717230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 718230189d9SNélio Laranjeiro */ 719230189d9SNélio Laranjeiro uint16_t 720230189d9SNélio Laranjeiro mlx5_tx_burst_mpw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 721230189d9SNélio Laranjeiro { 722230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 723230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 7248c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 7258c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 726c3d62cc9SAdrien Mazarguil unsigned int i = 0; 727a5bf6af9SAdrien Mazarguil unsigned int j = 0; 7288c819a69SYongseok Koh uint16_t max_elts; 729f04f1d51SNélio Laranjeiro uint16_t max_wqe; 730230189d9SNélio Laranjeiro unsigned int comp; 731230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 732230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 733230189d9SNélio Laranjeiro }; 734230189d9SNélio Laranjeiro 735c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 736c3d62cc9SAdrien Mazarguil return 0; 737230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 738fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 739fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 740230189d9SNélio Laranjeiro /* Start processing. */ 7416cb559d6SYongseok Koh mlx5_tx_complete(txq); 7428c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 743f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 744f04f1d51SNélio Laranjeiro if (unlikely(!max_wqe)) 745f04f1d51SNélio Laranjeiro return 0; 746c3d62cc9SAdrien Mazarguil do { 747a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 748230189d9SNélio Laranjeiro uint32_t length; 749a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 750230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 751230189d9SNélio Laranjeiro 752c3d62cc9SAdrien Mazarguil /* 753c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 754c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 755c3d62cc9SAdrien Mazarguil */ 756a5bf6af9SAdrien Mazarguil assert(segs_n); 7578c819a69SYongseok Koh if (max_elts < segs_n) 758c3d62cc9SAdrien Mazarguil break; 759a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 760a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 761a5bf6af9SAdrien Mazarguil break; 7628c819a69SYongseok Koh max_elts -= segs_n; 763c3d62cc9SAdrien Mazarguil --pkts_n; 764230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 765230189d9SNélio Laranjeiro if (buf->ol_flags & 766230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 767230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 768a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 769a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 770a5bf6af9SAdrien Mazarguil assert(length); 771230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 772230189d9SNélio Laranjeiro if ((mpw.state == MLX5_MPW_STATE_OPENED) && 773230189d9SNélio Laranjeiro ((mpw.len != length) || 774a5bf6af9SAdrien Mazarguil (segs_n != 1) || 7758688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags))) 776230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 777230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 778f04f1d51SNélio Laranjeiro /* 779f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 780f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use such 781f04f1d51SNélio Laranjeiro * resources. 782f04f1d51SNélio Laranjeiro */ 783f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 784f04f1d51SNélio Laranjeiro break; 785f04f1d51SNélio Laranjeiro max_wqe -= 2; 786230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 7878688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 788230189d9SNélio Laranjeiro } 789a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 790a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 791a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 792a5bf6af9SAdrien Mazarguil length = 0; 793a5bf6af9SAdrien Mazarguil #endif 794a5bf6af9SAdrien Mazarguil do { 795a5bf6af9SAdrien Mazarguil volatile struct mlx5_wqe_data_seg *dseg; 796a5bf6af9SAdrien Mazarguil uintptr_t addr; 797a5bf6af9SAdrien Mazarguil 798a5bf6af9SAdrien Mazarguil assert(buf); 7998c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 800230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 801a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 802230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 803a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 8046cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 805230189d9SNélio Laranjeiro .addr = htonll(addr), 806230189d9SNélio Laranjeiro }; 807a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 808a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 809a5bf6af9SAdrien Mazarguil #endif 810a5bf6af9SAdrien Mazarguil buf = buf->next; 811230189d9SNélio Laranjeiro ++mpw.pkts_n; 812a5bf6af9SAdrien Mazarguil ++j; 813a5bf6af9SAdrien Mazarguil } while (--segs_n); 814a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 815230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 816230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 817230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 818230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 819230189d9SNélio Laranjeiro txq->stats.obytes += length; 820230189d9SNélio Laranjeiro #endif 821c3d62cc9SAdrien Mazarguil ++i; 822c3d62cc9SAdrien Mazarguil } while (pkts_n); 823230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 824230189d9SNélio Laranjeiro if (unlikely(i == 0)) 825230189d9SNélio Laranjeiro return 0; 826230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 827a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 828a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 829230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 8308688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 831230189d9SNélio Laranjeiro 832230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 8338688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 834230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 8358688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 836230189d9SNélio Laranjeiro txq->elts_comp = 0; 837230189d9SNélio Laranjeiro } else { 838230189d9SNélio Laranjeiro txq->elts_comp = comp; 839230189d9SNélio Laranjeiro } 840230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 841230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 842230189d9SNélio Laranjeiro txq->stats.opackets += i; 843230189d9SNélio Laranjeiro #endif 844230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 845230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) 846230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 84730807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 848230189d9SNélio Laranjeiro txq->elts_head = elts_head; 849230189d9SNélio Laranjeiro return i; 850230189d9SNélio Laranjeiro } 851230189d9SNélio Laranjeiro 852230189d9SNélio Laranjeiro /** 853230189d9SNélio Laranjeiro * Open a MPW inline session. 854230189d9SNélio Laranjeiro * 855230189d9SNélio Laranjeiro * @param txq 856230189d9SNélio Laranjeiro * Pointer to TX queue structure. 857230189d9SNélio Laranjeiro * @param mpw 858230189d9SNélio Laranjeiro * Pointer to MPW session structure. 859230189d9SNélio Laranjeiro * @param length 860230189d9SNélio Laranjeiro * Packet length. 861230189d9SNélio Laranjeiro */ 862230189d9SNélio Laranjeiro static inline void 863230189d9SNélio Laranjeiro mlx5_mpw_inline_new(struct txq *txq, struct mlx5_mpw *mpw, uint32_t length) 864230189d9SNélio Laranjeiro { 865a821d09dSNélio Laranjeiro uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 8668688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl; 867230189d9SNélio Laranjeiro 868230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_INL_STATE_OPENED; 869230189d9SNélio Laranjeiro mpw->pkts_n = 0; 870230189d9SNélio Laranjeiro mpw->len = length; 871230189d9SNélio Laranjeiro mpw->total_len = 0; 872fdcb0f53SNélio Laranjeiro mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 8738688b2f8SNélio Laranjeiro mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_MPW << 24) | 874230189d9SNélio Laranjeiro (txq->wqe_ci << 8) | 875c904ae25SNélio Laranjeiro MLX5_OPCODE_TSO); 8768688b2f8SNélio Laranjeiro mpw->wqe->ctrl[2] = 0; 8778688b2f8SNélio Laranjeiro mpw->wqe->ctrl[3] = 0; 8788688b2f8SNélio Laranjeiro mpw->wqe->eseg.mss = htons(length); 8798688b2f8SNélio Laranjeiro mpw->wqe->eseg.inline_hdr_sz = 0; 8808688b2f8SNélio Laranjeiro mpw->wqe->eseg.cs_flags = 0; 8818688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd0 = 0; 8828688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd1 = 0; 8838688b2f8SNélio Laranjeiro mpw->wqe->eseg.rsvd2 = 0; 8848688b2f8SNélio Laranjeiro inl = (struct mlx5_wqe_inl_small *) 8858688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + 2 * MLX5_WQE_DWORD_SIZE); 8868688b2f8SNélio Laranjeiro mpw->data.raw = (uint8_t *)&inl->raw; 887230189d9SNélio Laranjeiro } 888230189d9SNélio Laranjeiro 889230189d9SNélio Laranjeiro /** 890230189d9SNélio Laranjeiro * Close a MPW inline session. 891230189d9SNélio Laranjeiro * 892230189d9SNélio Laranjeiro * @param txq 893230189d9SNélio Laranjeiro * Pointer to TX queue structure. 894230189d9SNélio Laranjeiro * @param mpw 895230189d9SNélio Laranjeiro * Pointer to MPW session structure. 896230189d9SNélio Laranjeiro */ 897230189d9SNélio Laranjeiro static inline void 898230189d9SNélio Laranjeiro mlx5_mpw_inline_close(struct txq *txq, struct mlx5_mpw *mpw) 899230189d9SNélio Laranjeiro { 900230189d9SNélio Laranjeiro unsigned int size; 9018688b2f8SNélio Laranjeiro struct mlx5_wqe_inl_small *inl = (struct mlx5_wqe_inl_small *) 9028688b2f8SNélio Laranjeiro (((uintptr_t)mpw->wqe) + (2 * MLX5_WQE_DWORD_SIZE)); 903230189d9SNélio Laranjeiro 9048688b2f8SNélio Laranjeiro size = MLX5_WQE_SIZE - MLX5_MWQE64_INL_DATA + mpw->total_len; 905230189d9SNélio Laranjeiro /* 906230189d9SNélio Laranjeiro * Store size in multiple of 16 bytes. Control and Ethernet segments 907230189d9SNélio Laranjeiro * count as 2. 908230189d9SNélio Laranjeiro */ 9098688b2f8SNélio Laranjeiro mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(size)); 910230189d9SNélio Laranjeiro mpw->state = MLX5_MPW_STATE_CLOSED; 9118688b2f8SNélio Laranjeiro inl->byte_cnt = htonl(mpw->total_len | MLX5_INLINE_SEG); 9128688b2f8SNélio Laranjeiro txq->wqe_ci += (size + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 913230189d9SNélio Laranjeiro } 914230189d9SNélio Laranjeiro 915230189d9SNélio Laranjeiro /** 916230189d9SNélio Laranjeiro * DPDK callback for TX with MPW inline support. 917230189d9SNélio Laranjeiro * 918230189d9SNélio Laranjeiro * @param dpdk_txq 919230189d9SNélio Laranjeiro * Generic pointer to TX queue structure. 920230189d9SNélio Laranjeiro * @param[in] pkts 921230189d9SNélio Laranjeiro * Packets to transmit. 922230189d9SNélio Laranjeiro * @param pkts_n 923230189d9SNélio Laranjeiro * Number of packets in array. 924230189d9SNélio Laranjeiro * 925230189d9SNélio Laranjeiro * @return 926230189d9SNélio Laranjeiro * Number of packets successfully transmitted (<= pkts_n). 927230189d9SNélio Laranjeiro */ 928230189d9SNélio Laranjeiro uint16_t 929230189d9SNélio Laranjeiro mlx5_tx_burst_mpw_inline(void *dpdk_txq, struct rte_mbuf **pkts, 930230189d9SNélio Laranjeiro uint16_t pkts_n) 931230189d9SNélio Laranjeiro { 932230189d9SNélio Laranjeiro struct txq *txq = (struct txq *)dpdk_txq; 933230189d9SNélio Laranjeiro uint16_t elts_head = txq->elts_head; 9348c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 9358c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 936c3d62cc9SAdrien Mazarguil unsigned int i = 0; 937a5bf6af9SAdrien Mazarguil unsigned int j = 0; 9388c819a69SYongseok Koh uint16_t max_elts; 939f04f1d51SNélio Laranjeiro uint16_t max_wqe; 940230189d9SNélio Laranjeiro unsigned int comp; 9410e8679fcSNélio Laranjeiro unsigned int inline_room = txq->max_inline * RTE_CACHE_LINE_SIZE; 942230189d9SNélio Laranjeiro struct mlx5_mpw mpw = { 943230189d9SNélio Laranjeiro .state = MLX5_MPW_STATE_CLOSED, 944230189d9SNélio Laranjeiro }; 945f04f1d51SNélio Laranjeiro /* 946f04f1d51SNélio Laranjeiro * Compute the maximum number of WQE which can be consumed by inline 947f04f1d51SNélio Laranjeiro * code. 948f04f1d51SNélio Laranjeiro * - 2 DSEG for: 949f04f1d51SNélio Laranjeiro * - 1 control segment, 950f04f1d51SNélio Laranjeiro * - 1 Ethernet segment, 951f04f1d51SNélio Laranjeiro * - N Dseg from the inline request. 952f04f1d51SNélio Laranjeiro */ 953f04f1d51SNélio Laranjeiro const unsigned int wqe_inl_n = 954f04f1d51SNélio Laranjeiro ((2 * MLX5_WQE_DWORD_SIZE + 955f04f1d51SNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE) + 956f04f1d51SNélio Laranjeiro RTE_CACHE_LINE_SIZE - 1) / RTE_CACHE_LINE_SIZE; 957230189d9SNélio Laranjeiro 958c3d62cc9SAdrien Mazarguil if (unlikely(!pkts_n)) 959c3d62cc9SAdrien Mazarguil return 0; 960230189d9SNélio Laranjeiro /* Prefetch first packet cacheline. */ 961fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci)); 962fdcb0f53SNélio Laranjeiro rte_prefetch0(tx_mlx5_wqe(txq, txq->wqe_ci + 1)); 963230189d9SNélio Laranjeiro /* Start processing. */ 9646cb559d6SYongseok Koh mlx5_tx_complete(txq); 9658c819a69SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 966c3d62cc9SAdrien Mazarguil do { 967a5bf6af9SAdrien Mazarguil struct rte_mbuf *buf = *(pkts++); 968230189d9SNélio Laranjeiro uintptr_t addr; 969230189d9SNélio Laranjeiro uint32_t length; 970a5bf6af9SAdrien Mazarguil unsigned int segs_n = buf->nb_segs; 971230189d9SNélio Laranjeiro uint32_t cs_flags = 0; 972230189d9SNélio Laranjeiro 973c3d62cc9SAdrien Mazarguil /* 974c3d62cc9SAdrien Mazarguil * Make sure there is enough room to store this packet and 975c3d62cc9SAdrien Mazarguil * that one ring entry remains unused. 976c3d62cc9SAdrien Mazarguil */ 977a5bf6af9SAdrien Mazarguil assert(segs_n); 9788c819a69SYongseok Koh if (max_elts < segs_n) 979c3d62cc9SAdrien Mazarguil break; 980a5bf6af9SAdrien Mazarguil /* Do not bother with large packets MPW cannot handle. */ 981a5bf6af9SAdrien Mazarguil if (segs_n > MLX5_MPW_DSEG_MAX) 982a5bf6af9SAdrien Mazarguil break; 9838c819a69SYongseok Koh max_elts -= segs_n; 984c3d62cc9SAdrien Mazarguil --pkts_n; 985f04f1d51SNélio Laranjeiro /* 986f04f1d51SNélio Laranjeiro * Compute max_wqe in case less WQE were consumed in previous 987f04f1d51SNélio Laranjeiro * iteration. 988f04f1d51SNélio Laranjeiro */ 989f04f1d51SNélio Laranjeiro max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 990230189d9SNélio Laranjeiro /* Should we enable HW CKSUM offload */ 991230189d9SNélio Laranjeiro if (buf->ol_flags & 992230189d9SNélio Laranjeiro (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 993230189d9SNélio Laranjeiro cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 994a5bf6af9SAdrien Mazarguil /* Retrieve packet information. */ 995a5bf6af9SAdrien Mazarguil length = PKT_LEN(buf); 996230189d9SNélio Laranjeiro /* Start new session if packet differs. */ 997230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 998230189d9SNélio Laranjeiro if ((mpw.len != length) || 999a5bf6af9SAdrien Mazarguil (segs_n != 1) || 10008688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) 1001230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1002230189d9SNélio Laranjeiro } else if (mpw.state == MLX5_MPW_INL_STATE_OPENED) { 1003230189d9SNélio Laranjeiro if ((mpw.len != length) || 1004a5bf6af9SAdrien Mazarguil (segs_n != 1) || 1005230189d9SNélio Laranjeiro (length > inline_room) || 10068688b2f8SNélio Laranjeiro (mpw.wqe->eseg.cs_flags != cs_flags)) { 1007230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 10080e8679fcSNélio Laranjeiro inline_room = 10090e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1010230189d9SNélio Laranjeiro } 1011230189d9SNélio Laranjeiro } 1012230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_CLOSED) { 1013a5bf6af9SAdrien Mazarguil if ((segs_n != 1) || 1014a5bf6af9SAdrien Mazarguil (length > inline_room)) { 1015f04f1d51SNélio Laranjeiro /* 1016f04f1d51SNélio Laranjeiro * Multi-Packet WQE consumes at most two WQE. 1017f04f1d51SNélio Laranjeiro * mlx5_mpw_new() expects to be able to use 1018f04f1d51SNélio Laranjeiro * such resources. 1019f04f1d51SNélio Laranjeiro */ 1020f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < 2)) 1021f04f1d51SNélio Laranjeiro break; 1022f04f1d51SNélio Laranjeiro max_wqe -= 2; 1023230189d9SNélio Laranjeiro mlx5_mpw_new(txq, &mpw, length); 10248688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1025230189d9SNélio Laranjeiro } else { 1026f04f1d51SNélio Laranjeiro if (unlikely(max_wqe < wqe_inl_n)) 1027f04f1d51SNélio Laranjeiro break; 1028f04f1d51SNélio Laranjeiro max_wqe -= wqe_inl_n; 1029230189d9SNélio Laranjeiro mlx5_mpw_inline_new(txq, &mpw, length); 10308688b2f8SNélio Laranjeiro mpw.wqe->eseg.cs_flags = cs_flags; 1031230189d9SNélio Laranjeiro } 1032230189d9SNélio Laranjeiro } 1033a5bf6af9SAdrien Mazarguil /* Multi-segment packets must be alone in their MPW. */ 1034a5bf6af9SAdrien Mazarguil assert((segs_n == 1) || (mpw.pkts_n == 0)); 1035230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_STATE_OPENED) { 10360e8679fcSNélio Laranjeiro assert(inline_room == 10370e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE); 1038a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1039a5bf6af9SAdrien Mazarguil length = 0; 1040a5bf6af9SAdrien Mazarguil #endif 1041a5bf6af9SAdrien Mazarguil do { 1042230189d9SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *dseg; 1043230189d9SNélio Laranjeiro 1044a5bf6af9SAdrien Mazarguil assert(buf); 10458c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1046230189d9SNélio Laranjeiro dseg = mpw.data.dseg[mpw.pkts_n]; 1047a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 1048230189d9SNélio Laranjeiro *dseg = (struct mlx5_wqe_data_seg){ 1049a5bf6af9SAdrien Mazarguil .byte_count = htonl(DATA_LEN(buf)), 10506cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 1051230189d9SNélio Laranjeiro .addr = htonll(addr), 1052230189d9SNélio Laranjeiro }; 1053a5bf6af9SAdrien Mazarguil #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 1054a5bf6af9SAdrien Mazarguil length += DATA_LEN(buf); 1055a5bf6af9SAdrien Mazarguil #endif 1056a5bf6af9SAdrien Mazarguil buf = buf->next; 1057230189d9SNélio Laranjeiro ++mpw.pkts_n; 1058a5bf6af9SAdrien Mazarguil ++j; 1059a5bf6af9SAdrien Mazarguil } while (--segs_n); 1060a5bf6af9SAdrien Mazarguil assert(length == mpw.len); 1061230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) 1062230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 1063230189d9SNélio Laranjeiro } else { 1064230189d9SNélio Laranjeiro unsigned int max; 1065230189d9SNélio Laranjeiro 1066230189d9SNélio Laranjeiro assert(mpw.state == MLX5_MPW_INL_STATE_OPENED); 1067230189d9SNélio Laranjeiro assert(length <= inline_room); 1068a5bf6af9SAdrien Mazarguil assert(length == DATA_LEN(buf)); 1069a5bf6af9SAdrien Mazarguil addr = rte_pktmbuf_mtod(buf, uintptr_t); 10708c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 1071230189d9SNélio Laranjeiro /* Maximum number of bytes before wrapping. */ 1072fdcb0f53SNélio Laranjeiro max = ((((uintptr_t)(txq->wqes)) + 1073fdcb0f53SNélio Laranjeiro (1 << txq->wqe_n) * 1074fdcb0f53SNélio Laranjeiro MLX5_WQE_SIZE) - 1075230189d9SNélio Laranjeiro (uintptr_t)mpw.data.raw); 1076230189d9SNélio Laranjeiro if (length > max) { 1077230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1078230189d9SNélio Laranjeiro (void *)addr, 1079230189d9SNélio Laranjeiro max); 1080fdcb0f53SNélio Laranjeiro mpw.data.raw = (volatile void *)txq->wqes; 1081230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1082230189d9SNélio Laranjeiro (void *)(addr + max), 1083230189d9SNélio Laranjeiro length - max); 1084230189d9SNélio Laranjeiro mpw.data.raw += length - max; 1085230189d9SNélio Laranjeiro } else { 1086230189d9SNélio Laranjeiro rte_memcpy((void *)(uintptr_t)mpw.data.raw, 1087230189d9SNélio Laranjeiro (void *)addr, 1088230189d9SNélio Laranjeiro length); 108916c64768SYongseok Koh 109016c64768SYongseok Koh if (length == max) 109116c64768SYongseok Koh mpw.data.raw = 109216c64768SYongseok Koh (volatile void *)txq->wqes; 109316c64768SYongseok Koh else 1094230189d9SNélio Laranjeiro mpw.data.raw += length; 1095230189d9SNélio Laranjeiro } 1096230189d9SNélio Laranjeiro ++mpw.pkts_n; 109776bf1574SYongseok Koh mpw.total_len += length; 1098a5bf6af9SAdrien Mazarguil ++j; 1099230189d9SNélio Laranjeiro if (mpw.pkts_n == MLX5_MPW_DSEG_MAX) { 1100230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 11010e8679fcSNélio Laranjeiro inline_room = 11020e8679fcSNélio Laranjeiro txq->max_inline * RTE_CACHE_LINE_SIZE; 1103230189d9SNélio Laranjeiro } else { 1104230189d9SNélio Laranjeiro inline_room -= length; 1105230189d9SNélio Laranjeiro } 1106230189d9SNélio Laranjeiro } 1107230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1108230189d9SNélio Laranjeiro /* Increment sent bytes counter. */ 1109230189d9SNélio Laranjeiro txq->stats.obytes += length; 1110230189d9SNélio Laranjeiro #endif 1111c3d62cc9SAdrien Mazarguil ++i; 1112c3d62cc9SAdrien Mazarguil } while (pkts_n); 1113230189d9SNélio Laranjeiro /* Take a shortcut if nothing must be sent. */ 1114230189d9SNélio Laranjeiro if (unlikely(i == 0)) 1115230189d9SNélio Laranjeiro return 0; 1116230189d9SNélio Laranjeiro /* Check whether completion threshold has been reached. */ 1117a5bf6af9SAdrien Mazarguil /* "j" includes both packets and segments. */ 1118a5bf6af9SAdrien Mazarguil comp = txq->elts_comp + j; 1119230189d9SNélio Laranjeiro if (comp >= MLX5_TX_COMP_THRESH) { 11208688b2f8SNélio Laranjeiro volatile struct mlx5_wqe *wqe = mpw.wqe; 1121230189d9SNélio Laranjeiro 1122230189d9SNélio Laranjeiro /* Request completion on last WQE. */ 11238688b2f8SNélio Laranjeiro wqe->ctrl[2] = htonl(8); 1124230189d9SNélio Laranjeiro /* Save elts_head in unused "immediate" field of WQE. */ 11258688b2f8SNélio Laranjeiro wqe->ctrl[3] = elts_head; 1126230189d9SNélio Laranjeiro txq->elts_comp = 0; 1127230189d9SNélio Laranjeiro } else { 1128230189d9SNélio Laranjeiro txq->elts_comp = comp; 1129230189d9SNélio Laranjeiro } 1130230189d9SNélio Laranjeiro #ifdef MLX5_PMD_SOFT_COUNTERS 1131230189d9SNélio Laranjeiro /* Increment sent packets counter. */ 1132230189d9SNélio Laranjeiro txq->stats.opackets += i; 1133230189d9SNélio Laranjeiro #endif 1134230189d9SNélio Laranjeiro /* Ring QP doorbell. */ 1135230189d9SNélio Laranjeiro if (mpw.state == MLX5_MPW_INL_STATE_OPENED) 1136230189d9SNélio Laranjeiro mlx5_mpw_inline_close(txq, &mpw); 1137230189d9SNélio Laranjeiro else if (mpw.state == MLX5_MPW_STATE_OPENED) 1138230189d9SNélio Laranjeiro mlx5_mpw_close(txq, &mpw); 113930807f62SNélio Laranjeiro mlx5_tx_dbrec(txq, mpw.wqe); 1140230189d9SNélio Laranjeiro txq->elts_head = elts_head; 1141230189d9SNélio Laranjeiro return i; 1142230189d9SNélio Laranjeiro } 1143230189d9SNélio Laranjeiro 1144230189d9SNélio Laranjeiro /** 11456ce84bd8SYongseok Koh * Open an Enhanced MPW session. 11466ce84bd8SYongseok Koh * 11476ce84bd8SYongseok Koh * @param txq 11486ce84bd8SYongseok Koh * Pointer to TX queue structure. 11496ce84bd8SYongseok Koh * @param mpw 11506ce84bd8SYongseok Koh * Pointer to MPW session structure. 11516ce84bd8SYongseok Koh * @param length 11526ce84bd8SYongseok Koh * Packet length. 11536ce84bd8SYongseok Koh */ 11546ce84bd8SYongseok Koh static inline void 11556ce84bd8SYongseok Koh mlx5_empw_new(struct txq *txq, struct mlx5_mpw *mpw, int padding) 11566ce84bd8SYongseok Koh { 11576ce84bd8SYongseok Koh uint16_t idx = txq->wqe_ci & ((1 << txq->wqe_n) - 1); 11586ce84bd8SYongseok Koh 11596ce84bd8SYongseok Koh mpw->state = MLX5_MPW_ENHANCED_STATE_OPENED; 11606ce84bd8SYongseok Koh mpw->pkts_n = 0; 11616ce84bd8SYongseok Koh mpw->total_len = sizeof(struct mlx5_wqe); 11626ce84bd8SYongseok Koh mpw->wqe = (volatile struct mlx5_wqe *)tx_mlx5_wqe(txq, idx); 11636ce84bd8SYongseok Koh mpw->wqe->ctrl[0] = htonl((MLX5_OPC_MOD_ENHANCED_MPSW << 24) | 11646ce84bd8SYongseok Koh (txq->wqe_ci << 8) | 11656ce84bd8SYongseok Koh MLX5_OPCODE_ENHANCED_MPSW); 11666ce84bd8SYongseok Koh mpw->wqe->ctrl[2] = 0; 11676ce84bd8SYongseok Koh mpw->wqe->ctrl[3] = 0; 11686ce84bd8SYongseok Koh memset((void *)(uintptr_t)&mpw->wqe->eseg, 0, MLX5_WQE_DWORD_SIZE); 11696ce84bd8SYongseok Koh if (unlikely(padding)) { 11706ce84bd8SYongseok Koh uintptr_t addr = (uintptr_t)(mpw->wqe + 1); 11716ce84bd8SYongseok Koh 11726ce84bd8SYongseok Koh /* Pad the first 2 DWORDs with zero-length inline header. */ 11736ce84bd8SYongseok Koh *(volatile uint32_t *)addr = htonl(MLX5_INLINE_SEG); 11746ce84bd8SYongseok Koh *(volatile uint32_t *)(addr + MLX5_WQE_DWORD_SIZE) = 11756ce84bd8SYongseok Koh htonl(MLX5_INLINE_SEG); 11766ce84bd8SYongseok Koh mpw->total_len += 2 * MLX5_WQE_DWORD_SIZE; 11776ce84bd8SYongseok Koh /* Start from the next WQEBB. */ 11786ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(tx_mlx5_wqe(txq, idx + 1)); 11796ce84bd8SYongseok Koh } else { 11806ce84bd8SYongseok Koh mpw->data.raw = (volatile void *)(mpw->wqe + 1); 11816ce84bd8SYongseok Koh } 11826ce84bd8SYongseok Koh } 11836ce84bd8SYongseok Koh 11846ce84bd8SYongseok Koh /** 11856ce84bd8SYongseok Koh * Close an Enhanced MPW session. 11866ce84bd8SYongseok Koh * 11876ce84bd8SYongseok Koh * @param txq 11886ce84bd8SYongseok Koh * Pointer to TX queue structure. 11896ce84bd8SYongseok Koh * @param mpw 11906ce84bd8SYongseok Koh * Pointer to MPW session structure. 11916ce84bd8SYongseok Koh * 11926ce84bd8SYongseok Koh * @return 11936ce84bd8SYongseok Koh * Number of consumed WQEs. 11946ce84bd8SYongseok Koh */ 11956ce84bd8SYongseok Koh static inline uint16_t 11966ce84bd8SYongseok Koh mlx5_empw_close(struct txq *txq, struct mlx5_mpw *mpw) 11976ce84bd8SYongseok Koh { 11986ce84bd8SYongseok Koh uint16_t ret; 11996ce84bd8SYongseok Koh 12006ce84bd8SYongseok Koh /* Store size in multiple of 16 bytes. Control and Ethernet segments 12016ce84bd8SYongseok Koh * count as 2. 12026ce84bd8SYongseok Koh */ 12036ce84bd8SYongseok Koh mpw->wqe->ctrl[1] = htonl(txq->qp_num_8s | MLX5_WQE_DS(mpw->total_len)); 12046ce84bd8SYongseok Koh mpw->state = MLX5_MPW_STATE_CLOSED; 12056ce84bd8SYongseok Koh ret = (mpw->total_len + (MLX5_WQE_SIZE - 1)) / MLX5_WQE_SIZE; 12066ce84bd8SYongseok Koh txq->wqe_ci += ret; 12076ce84bd8SYongseok Koh return ret; 12086ce84bd8SYongseok Koh } 12096ce84bd8SYongseok Koh 12106ce84bd8SYongseok Koh /** 12116ce84bd8SYongseok Koh * DPDK callback for TX with Enhanced MPW support. 12126ce84bd8SYongseok Koh * 12136ce84bd8SYongseok Koh * @param dpdk_txq 12146ce84bd8SYongseok Koh * Generic pointer to TX queue structure. 12156ce84bd8SYongseok Koh * @param[in] pkts 12166ce84bd8SYongseok Koh * Packets to transmit. 12176ce84bd8SYongseok Koh * @param pkts_n 12186ce84bd8SYongseok Koh * Number of packets in array. 12196ce84bd8SYongseok Koh * 12206ce84bd8SYongseok Koh * @return 12216ce84bd8SYongseok Koh * Number of packets successfully transmitted (<= pkts_n). 12226ce84bd8SYongseok Koh */ 12236ce84bd8SYongseok Koh uint16_t 12246ce84bd8SYongseok Koh mlx5_tx_burst_empw(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 12256ce84bd8SYongseok Koh { 12266ce84bd8SYongseok Koh struct txq *txq = (struct txq *)dpdk_txq; 12276ce84bd8SYongseok Koh uint16_t elts_head = txq->elts_head; 12288c819a69SYongseok Koh const uint16_t elts_n = 1 << txq->elts_n; 12298c819a69SYongseok Koh const uint16_t elts_m = elts_n - 1; 12306ce84bd8SYongseok Koh unsigned int i = 0; 12316ce84bd8SYongseok Koh unsigned int j = 0; 12328c819a69SYongseok Koh uint16_t max_elts; 12336ce84bd8SYongseok Koh uint16_t max_wqe; 12346ce84bd8SYongseok Koh unsigned int max_inline = txq->max_inline * RTE_CACHE_LINE_SIZE; 12356ce84bd8SYongseok Koh unsigned int mpw_room = 0; 12366ce84bd8SYongseok Koh unsigned int inl_pad = 0; 12376ce84bd8SYongseok Koh uint32_t inl_hdr; 12386ce84bd8SYongseok Koh struct mlx5_mpw mpw = { 12396ce84bd8SYongseok Koh .state = MLX5_MPW_STATE_CLOSED, 12406ce84bd8SYongseok Koh }; 12416ce84bd8SYongseok Koh 12426ce84bd8SYongseok Koh if (unlikely(!pkts_n)) 12436ce84bd8SYongseok Koh return 0; 12446ce84bd8SYongseok Koh /* Start processing. */ 12456cb559d6SYongseok Koh mlx5_tx_complete(txq); 12466ce84bd8SYongseok Koh max_elts = (elts_n - (elts_head - txq->elts_tail)); 12476ce84bd8SYongseok Koh /* A CQE slot must always be available. */ 12486ce84bd8SYongseok Koh assert((1u << txq->cqe_n) - (txq->cq_pi - txq->cq_ci)); 12496ce84bd8SYongseok Koh max_wqe = (1u << txq->wqe_n) - (txq->wqe_ci - txq->wqe_pi); 12506ce84bd8SYongseok Koh if (unlikely(!max_wqe)) 12516ce84bd8SYongseok Koh return 0; 12526ce84bd8SYongseok Koh do { 12536ce84bd8SYongseok Koh struct rte_mbuf *buf = *(pkts++); 12546ce84bd8SYongseok Koh uintptr_t addr; 12556ce84bd8SYongseok Koh uint64_t naddr; 12566ce84bd8SYongseok Koh unsigned int n; 12576ce84bd8SYongseok Koh unsigned int do_inline = 0; /* Whether inline is possible. */ 12586ce84bd8SYongseok Koh uint32_t length; 12596ce84bd8SYongseok Koh unsigned int segs_n = buf->nb_segs; 12606ce84bd8SYongseok Koh uint32_t cs_flags = 0; 12616ce84bd8SYongseok Koh 12626ce84bd8SYongseok Koh /* 12636ce84bd8SYongseok Koh * Make sure there is enough room to store this packet and 12646ce84bd8SYongseok Koh * that one ring entry remains unused. 12656ce84bd8SYongseok Koh */ 12666ce84bd8SYongseok Koh assert(segs_n); 12678c819a69SYongseok Koh if (max_elts - j < segs_n) 12686ce84bd8SYongseok Koh break; 12696ce84bd8SYongseok Koh /* Do not bother with large packets MPW cannot handle. */ 12706ce84bd8SYongseok Koh if (segs_n > MLX5_MPW_DSEG_MAX) 12716ce84bd8SYongseok Koh break; 12726ce84bd8SYongseok Koh /* Should we enable HW CKSUM offload. */ 12736ce84bd8SYongseok Koh if (buf->ol_flags & 12746ce84bd8SYongseok Koh (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM)) 12756ce84bd8SYongseok Koh cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; 12766ce84bd8SYongseok Koh /* Retrieve packet information. */ 12776ce84bd8SYongseok Koh length = PKT_LEN(buf); 12786ce84bd8SYongseok Koh /* Start new session if: 12796ce84bd8SYongseok Koh * - multi-segment packet 12806ce84bd8SYongseok Koh * - no space left even for a dseg 12816ce84bd8SYongseok Koh * - next packet can be inlined with a new WQE 12826ce84bd8SYongseok Koh * - cs_flag differs 12836ce84bd8SYongseok Koh * It can't be MLX5_MPW_STATE_OPENED as always have a single 12846ce84bd8SYongseok Koh * segmented packet. 12856ce84bd8SYongseok Koh */ 12866ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) { 12876ce84bd8SYongseok Koh if ((segs_n != 1) || 12886ce84bd8SYongseok Koh (inl_pad + sizeof(struct mlx5_wqe_data_seg) > 12896ce84bd8SYongseok Koh mpw_room) || 12906ce84bd8SYongseok Koh (length <= txq->inline_max_packet_sz && 12916ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length > 12926ce84bd8SYongseok Koh mpw_room) || 12936ce84bd8SYongseok Koh (mpw.wqe->eseg.cs_flags != cs_flags)) 12946ce84bd8SYongseok Koh max_wqe -= mlx5_empw_close(txq, &mpw); 12956ce84bd8SYongseok Koh } 12966ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_CLOSED)) { 12976ce84bd8SYongseok Koh if (unlikely(segs_n != 1)) { 12986ce84bd8SYongseok Koh /* Fall back to legacy MPW. 12996ce84bd8SYongseok Koh * A MPW session consumes 2 WQEs at most to 13006ce84bd8SYongseok Koh * include MLX5_MPW_DSEG_MAX pointers. 13016ce84bd8SYongseok Koh */ 13026ce84bd8SYongseok Koh if (unlikely(max_wqe < 2)) 13036ce84bd8SYongseok Koh break; 13046ce84bd8SYongseok Koh mlx5_mpw_new(txq, &mpw, length); 13056ce84bd8SYongseok Koh } else { 13066ce84bd8SYongseok Koh /* In Enhanced MPW, inline as much as the budget 13076ce84bd8SYongseok Koh * is allowed. The remaining space is to be 13086ce84bd8SYongseok Koh * filled with dsegs. If the title WQEBB isn't 13096ce84bd8SYongseok Koh * padded, it will have 2 dsegs there. 13106ce84bd8SYongseok Koh */ 13116ce84bd8SYongseok Koh mpw_room = RTE_MIN(MLX5_WQE_SIZE_MAX, 13126ce84bd8SYongseok Koh (max_inline ? max_inline : 13136ce84bd8SYongseok Koh pkts_n * MLX5_WQE_DWORD_SIZE) + 13146ce84bd8SYongseok Koh MLX5_WQE_SIZE); 13156ce84bd8SYongseok Koh if (unlikely(max_wqe * MLX5_WQE_SIZE < 13166ce84bd8SYongseok Koh mpw_room)) 13176ce84bd8SYongseok Koh break; 13186ce84bd8SYongseok Koh /* Don't pad the title WQEBB to not waste WQ. */ 13196ce84bd8SYongseok Koh mlx5_empw_new(txq, &mpw, 0); 13206ce84bd8SYongseok Koh mpw_room -= mpw.total_len; 13216ce84bd8SYongseok Koh inl_pad = 0; 13226ce84bd8SYongseok Koh do_inline = 13236ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 13246ce84bd8SYongseok Koh sizeof(inl_hdr) + length <= mpw_room && 13256ce84bd8SYongseok Koh !txq->mpw_hdr_dseg; 13266ce84bd8SYongseok Koh } 13276ce84bd8SYongseok Koh mpw.wqe->eseg.cs_flags = cs_flags; 13286ce84bd8SYongseok Koh } else { 13296ce84bd8SYongseok Koh /* Evaluate whether the next packet can be inlined. 13306ce84bd8SYongseok Koh * Inlininig is possible when: 13316ce84bd8SYongseok Koh * - length is less than configured value 13326ce84bd8SYongseok Koh * - length fits for remaining space 13336ce84bd8SYongseok Koh * - not required to fill the title WQEBB with dsegs 13346ce84bd8SYongseok Koh */ 13356ce84bd8SYongseok Koh do_inline = 13366ce84bd8SYongseok Koh length <= txq->inline_max_packet_sz && 13376ce84bd8SYongseok Koh inl_pad + sizeof(inl_hdr) + length <= 13386ce84bd8SYongseok Koh mpw_room && 13396ce84bd8SYongseok Koh (!txq->mpw_hdr_dseg || 13406ce84bd8SYongseok Koh mpw.total_len >= MLX5_WQE_SIZE); 13416ce84bd8SYongseok Koh } 13426ce84bd8SYongseok Koh /* Multi-segment packets must be alone in their MPW. */ 13436ce84bd8SYongseok Koh assert((segs_n == 1) || (mpw.pkts_n == 0)); 13446ce84bd8SYongseok Koh if (unlikely(mpw.state == MLX5_MPW_STATE_OPENED)) { 13456ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 13466ce84bd8SYongseok Koh length = 0; 13476ce84bd8SYongseok Koh #endif 13486ce84bd8SYongseok Koh do { 13496ce84bd8SYongseok Koh volatile struct mlx5_wqe_data_seg *dseg; 13506ce84bd8SYongseok Koh 13516ce84bd8SYongseok Koh assert(buf); 13528c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 13536ce84bd8SYongseok Koh dseg = mpw.data.dseg[mpw.pkts_n]; 13546ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 13556ce84bd8SYongseok Koh *dseg = (struct mlx5_wqe_data_seg){ 13566ce84bd8SYongseok Koh .byte_count = htonl(DATA_LEN(buf)), 13576cb559d6SYongseok Koh .lkey = mlx5_tx_mb2mr(txq, buf), 13586ce84bd8SYongseok Koh .addr = htonll(addr), 13596ce84bd8SYongseok Koh }; 13606ce84bd8SYongseok Koh #if defined(MLX5_PMD_SOFT_COUNTERS) || !defined(NDEBUG) 13616ce84bd8SYongseok Koh length += DATA_LEN(buf); 13626ce84bd8SYongseok Koh #endif 13636ce84bd8SYongseok Koh buf = buf->next; 13646ce84bd8SYongseok Koh ++j; 13656ce84bd8SYongseok Koh ++mpw.pkts_n; 13666ce84bd8SYongseok Koh } while (--segs_n); 13676ce84bd8SYongseok Koh /* A multi-segmented packet takes one MPW session. 13686ce84bd8SYongseok Koh * TODO: Pack more multi-segmented packets if possible. 13696ce84bd8SYongseok Koh */ 13706ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 13716ce84bd8SYongseok Koh if (mpw.pkts_n < 3) 13726ce84bd8SYongseok Koh max_wqe--; 13736ce84bd8SYongseok Koh else 13746ce84bd8SYongseok Koh max_wqe -= 2; 13756ce84bd8SYongseok Koh } else if (do_inline) { 13766ce84bd8SYongseok Koh /* Inline packet into WQE. */ 13776ce84bd8SYongseok Koh unsigned int max; 13786ce84bd8SYongseok Koh 13796ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 13806ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 13816ce84bd8SYongseok Koh inl_hdr = htonl(length | MLX5_INLINE_SEG); 13826ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 13836ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 13846ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + inl_pad); 13856ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 13866ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 13876ce84bd8SYongseok Koh /* Copy inline header. */ 13886ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 13896ce84bd8SYongseok Koh mlx5_copy_to_wq( 13906ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 13916ce84bd8SYongseok Koh &inl_hdr, 13926ce84bd8SYongseok Koh sizeof(inl_hdr), 13936ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 13946ce84bd8SYongseok Koh max); 13956ce84bd8SYongseok Koh max = tx_mlx5_wq_tailroom(txq, 13966ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw); 13976ce84bd8SYongseok Koh /* Copy packet data. */ 13986ce84bd8SYongseok Koh mpw.data.raw = (volatile void *) 13996ce84bd8SYongseok Koh mlx5_copy_to_wq( 14006ce84bd8SYongseok Koh (void *)(uintptr_t)mpw.data.raw, 14016ce84bd8SYongseok Koh (void *)addr, 14026ce84bd8SYongseok Koh length, 14036ce84bd8SYongseok Koh (void *)(uintptr_t)txq->wqes, 14046ce84bd8SYongseok Koh max); 14056ce84bd8SYongseok Koh ++mpw.pkts_n; 14066ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(inl_hdr) + length); 14076ce84bd8SYongseok Koh /* No need to get completion as the entire packet is 14086ce84bd8SYongseok Koh * copied to WQ. Free the buf right away. 14096ce84bd8SYongseok Koh */ 14106ce84bd8SYongseok Koh rte_pktmbuf_free_seg(buf); 14116ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(inl_hdr) + length); 14126ce84bd8SYongseok Koh /* Add pad in the next packet if any. */ 14136ce84bd8SYongseok Koh inl_pad = (((uintptr_t)mpw.data.raw + 14146ce84bd8SYongseok Koh (MLX5_WQE_DWORD_SIZE - 1)) & 14156ce84bd8SYongseok Koh ~(MLX5_WQE_DWORD_SIZE - 1)) - 14166ce84bd8SYongseok Koh (uintptr_t)mpw.data.raw; 14176ce84bd8SYongseok Koh } else { 14186ce84bd8SYongseok Koh /* No inline. Load a dseg of packet pointer. */ 14196ce84bd8SYongseok Koh volatile rte_v128u32_t *dseg; 14206ce84bd8SYongseok Koh 14216ce84bd8SYongseok Koh assert(mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED); 14226ce84bd8SYongseok Koh assert((inl_pad + sizeof(*dseg)) <= mpw_room); 14236ce84bd8SYongseok Koh assert(length == DATA_LEN(buf)); 14246ce84bd8SYongseok Koh if (!tx_mlx5_wq_tailroom(txq, 14256ce84bd8SYongseok Koh (void *)((uintptr_t)mpw.data.raw 14266ce84bd8SYongseok Koh + inl_pad))) 14276ce84bd8SYongseok Koh dseg = (volatile void *)txq->wqes; 14286ce84bd8SYongseok Koh else 14296ce84bd8SYongseok Koh dseg = (volatile void *) 14306ce84bd8SYongseok Koh ((uintptr_t)mpw.data.raw + 14316ce84bd8SYongseok Koh inl_pad); 14328c819a69SYongseok Koh (*txq->elts)[elts_head++ & elts_m] = buf; 14336ce84bd8SYongseok Koh addr = rte_pktmbuf_mtod(buf, uintptr_t); 14346ce84bd8SYongseok Koh for (n = 0; n * RTE_CACHE_LINE_SIZE < length; n++) 14356ce84bd8SYongseok Koh rte_prefetch2((void *)(addr + 14366ce84bd8SYongseok Koh n * RTE_CACHE_LINE_SIZE)); 14376ce84bd8SYongseok Koh naddr = htonll(addr); 14386ce84bd8SYongseok Koh *dseg = (rte_v128u32_t) { 14396ce84bd8SYongseok Koh htonl(length), 14406cb559d6SYongseok Koh mlx5_tx_mb2mr(txq, buf), 14416ce84bd8SYongseok Koh naddr, 14426ce84bd8SYongseok Koh naddr >> 32, 14436ce84bd8SYongseok Koh }; 14446ce84bd8SYongseok Koh mpw.data.raw = (volatile void *)(dseg + 1); 14456ce84bd8SYongseok Koh mpw.total_len += (inl_pad + sizeof(*dseg)); 14466ce84bd8SYongseok Koh ++j; 14476ce84bd8SYongseok Koh ++mpw.pkts_n; 14486ce84bd8SYongseok Koh mpw_room -= (inl_pad + sizeof(*dseg)); 14496ce84bd8SYongseok Koh inl_pad = 0; 14506ce84bd8SYongseok Koh } 14516ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 14526ce84bd8SYongseok Koh /* Increment sent bytes counter. */ 14536ce84bd8SYongseok Koh txq->stats.obytes += length; 14546ce84bd8SYongseok Koh #endif 14556ce84bd8SYongseok Koh ++i; 14566ce84bd8SYongseok Koh } while (i < pkts_n); 14576ce84bd8SYongseok Koh /* Take a shortcut if nothing must be sent. */ 14586ce84bd8SYongseok Koh if (unlikely(i == 0)) 14596ce84bd8SYongseok Koh return 0; 14606ce84bd8SYongseok Koh /* Check whether completion threshold has been reached. */ 14616ce84bd8SYongseok Koh if (txq->elts_comp + j >= MLX5_TX_COMP_THRESH || 14626ce84bd8SYongseok Koh (uint16_t)(txq->wqe_ci - txq->mpw_comp) >= 14636ce84bd8SYongseok Koh (1 << txq->wqe_n) / MLX5_TX_COMP_THRESH_INLINE_DIV) { 14646ce84bd8SYongseok Koh volatile struct mlx5_wqe *wqe = mpw.wqe; 14656ce84bd8SYongseok Koh 14666ce84bd8SYongseok Koh /* Request completion on last WQE. */ 14676ce84bd8SYongseok Koh wqe->ctrl[2] = htonl(8); 14686ce84bd8SYongseok Koh /* Save elts_head in unused "immediate" field of WQE. */ 14696ce84bd8SYongseok Koh wqe->ctrl[3] = elts_head; 14706ce84bd8SYongseok Koh txq->elts_comp = 0; 14716ce84bd8SYongseok Koh txq->mpw_comp = txq->wqe_ci; 14726ce84bd8SYongseok Koh txq->cq_pi++; 14736ce84bd8SYongseok Koh } else { 14746ce84bd8SYongseok Koh txq->elts_comp += j; 14756ce84bd8SYongseok Koh } 14766ce84bd8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS 14776ce84bd8SYongseok Koh /* Increment sent packets counter. */ 14786ce84bd8SYongseok Koh txq->stats.opackets += i; 14796ce84bd8SYongseok Koh #endif 14806ce84bd8SYongseok Koh if (mpw.state == MLX5_MPW_ENHANCED_STATE_OPENED) 14816ce84bd8SYongseok Koh mlx5_empw_close(txq, &mpw); 14826ce84bd8SYongseok Koh else if (mpw.state == MLX5_MPW_STATE_OPENED) 14836ce84bd8SYongseok Koh mlx5_mpw_close(txq, &mpw); 14846ce84bd8SYongseok Koh /* Ring QP doorbell. */ 14856ce84bd8SYongseok Koh mlx5_tx_dbrec(txq, mpw.wqe); 14866ce84bd8SYongseok Koh txq->elts_head = elts_head; 14876ce84bd8SYongseok Koh return i; 14886ce84bd8SYongseok Koh } 14896ce84bd8SYongseok Koh 14906ce84bd8SYongseok Koh /** 149167fa62bcSAdrien Mazarguil * Translate RX completion flags to packet type. 149267fa62bcSAdrien Mazarguil * 14936218063bSNélio Laranjeiro * @param[in] cqe 14946218063bSNélio Laranjeiro * Pointer to CQE. 149567fa62bcSAdrien Mazarguil * 149678a38edfSJianfeng Tan * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 149778a38edfSJianfeng Tan * 149867fa62bcSAdrien Mazarguil * @return 149967fa62bcSAdrien Mazarguil * Packet type for struct rte_mbuf. 150067fa62bcSAdrien Mazarguil */ 150167fa62bcSAdrien Mazarguil static inline uint32_t 150297267b8eSNelio Laranjeiro rxq_cq_to_pkt_type(volatile struct mlx5_cqe *cqe) 150367fa62bcSAdrien Mazarguil { 150467fa62bcSAdrien Mazarguil uint32_t pkt_type; 15050603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 150667fa62bcSAdrien Mazarguil 15070603df73SNélio Laranjeiro if (cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) { 150867fa62bcSAdrien Mazarguil pkt_type = 150967fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1510350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV4_PACKET, 1511501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN) | 151267fa62bcSAdrien Mazarguil TRANSPOSE(flags, 1513350f4c48SNelio Laranjeiro MLX5_CQE_RX_IPV6_PACKET, 1514501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN); 15150603df73SNélio Laranjeiro pkt_type |= ((cqe->pkt_info & MLX5_CQE_RX_OUTER_PACKET) ? 15160603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV6_EXT_UNKNOWN : 15170603df73SNélio Laranjeiro RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 15180603df73SNélio Laranjeiro } else { 151967fa62bcSAdrien Mazarguil pkt_type = 152067fa62bcSAdrien Mazarguil TRANSPOSE(flags, 15216218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV6, 1522501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV6_EXT_UNKNOWN) | 152367fa62bcSAdrien Mazarguil TRANSPOSE(flags, 15246218063bSNélio Laranjeiro MLX5_CQE_L3_HDR_TYPE_IPV4, 1525501505c5SMatthieu Ternisien d'Ouville RTE_PTYPE_L3_IPV4_EXT_UNKNOWN); 15260603df73SNélio Laranjeiro } 152767fa62bcSAdrien Mazarguil return pkt_type; 152867fa62bcSAdrien Mazarguil } 152967fa62bcSAdrien Mazarguil 153067fa62bcSAdrien Mazarguil /** 153199c12dccSNélio Laranjeiro * Get size of the next packet for a given CQE. For compressed CQEs, the 153299c12dccSNélio Laranjeiro * consumer index is updated only once all packets of the current one have 153399c12dccSNélio Laranjeiro * been processed. 153499c12dccSNélio Laranjeiro * 153599c12dccSNélio Laranjeiro * @param rxq 153699c12dccSNélio Laranjeiro * Pointer to RX queue. 153799c12dccSNélio Laranjeiro * @param cqe 153899c12dccSNélio Laranjeiro * CQE to process. 1539ecf60761SNélio Laranjeiro * @param[out] rss_hash 1540ecf60761SNélio Laranjeiro * Packet RSS Hash result. 154199c12dccSNélio Laranjeiro * 154299c12dccSNélio Laranjeiro * @return 154399c12dccSNélio Laranjeiro * Packet size in bytes (0 if there is none), -1 in case of completion 154499c12dccSNélio Laranjeiro * with error. 154599c12dccSNélio Laranjeiro */ 154699c12dccSNélio Laranjeiro static inline int 154797267b8eSNelio Laranjeiro mlx5_rx_poll_len(struct rxq *rxq, volatile struct mlx5_cqe *cqe, 1548ecf60761SNélio Laranjeiro uint16_t cqe_cnt, uint32_t *rss_hash) 154999c12dccSNélio Laranjeiro { 155099c12dccSNélio Laranjeiro struct rxq_zip *zip = &rxq->zip; 155199c12dccSNélio Laranjeiro uint16_t cqe_n = cqe_cnt + 1; 155299c12dccSNélio Laranjeiro int len = 0; 1553d2e842d0SYongseok Koh uint16_t idx, end; 155499c12dccSNélio Laranjeiro 155599c12dccSNélio Laranjeiro /* Process compressed data in the CQE and mini arrays. */ 155699c12dccSNélio Laranjeiro if (zip->ai) { 155799c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 155899c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 15594aff4bcbSYongseok Koh (uintptr_t)(&(*rxq->cqes)[zip->ca & cqe_cnt].pkt_info); 156099c12dccSNélio Laranjeiro 156199c12dccSNélio Laranjeiro len = ntohl((*mc)[zip->ai & 7].byte_cnt); 1562ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[zip->ai & 7].rx_hash_result); 156399c12dccSNélio Laranjeiro if ((++zip->ai & 7) == 0) { 1564d2e842d0SYongseok Koh /* Invalidate consumed CQEs */ 1565d2e842d0SYongseok Koh idx = zip->ca; 1566d2e842d0SYongseok Koh end = zip->na; 1567d2e842d0SYongseok Koh while (idx != end) { 1568d2e842d0SYongseok Koh (*rxq->cqes)[idx & cqe_cnt].op_own = 1569d2e842d0SYongseok Koh MLX5_CQE_INVALIDATE; 1570d2e842d0SYongseok Koh ++idx; 1571d2e842d0SYongseok Koh } 157299c12dccSNélio Laranjeiro /* 157399c12dccSNélio Laranjeiro * Increment consumer index to skip the number of 157499c12dccSNélio Laranjeiro * CQEs consumed. Hardware leaves holes in the CQ 157599c12dccSNélio Laranjeiro * ring for software use. 157699c12dccSNélio Laranjeiro */ 157799c12dccSNélio Laranjeiro zip->ca = zip->na; 157899c12dccSNélio Laranjeiro zip->na += 8; 157999c12dccSNélio Laranjeiro } 158099c12dccSNélio Laranjeiro if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 1581d2e842d0SYongseok Koh /* Invalidate the rest */ 1582d2e842d0SYongseok Koh idx = zip->ca; 1583d2e842d0SYongseok Koh end = zip->cq_ci; 158499c12dccSNélio Laranjeiro 158599c12dccSNélio Laranjeiro while (idx != end) { 158697267b8eSNelio Laranjeiro (*rxq->cqes)[idx & cqe_cnt].op_own = 158799c12dccSNélio Laranjeiro MLX5_CQE_INVALIDATE; 158899c12dccSNélio Laranjeiro ++idx; 158999c12dccSNélio Laranjeiro } 159099c12dccSNélio Laranjeiro rxq->cq_ci = zip->cq_ci; 159199c12dccSNélio Laranjeiro zip->ai = 0; 159299c12dccSNélio Laranjeiro } 159399c12dccSNélio Laranjeiro /* No compressed data, get next CQE and verify if it is compressed. */ 159499c12dccSNélio Laranjeiro } else { 159599c12dccSNélio Laranjeiro int ret; 159699c12dccSNélio Laranjeiro int8_t op_own; 159799c12dccSNélio Laranjeiro 159897267b8eSNelio Laranjeiro ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 159999c12dccSNélio Laranjeiro if (unlikely(ret == 1)) 160099c12dccSNélio Laranjeiro return 0; 160199c12dccSNélio Laranjeiro ++rxq->cq_ci; 160299c12dccSNélio Laranjeiro op_own = cqe->op_own; 160399c12dccSNélio Laranjeiro if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 160499c12dccSNélio Laranjeiro volatile struct mlx5_mini_cqe8 (*mc)[8] = 160599c12dccSNélio Laranjeiro (volatile struct mlx5_mini_cqe8 (*)[8]) 160699c12dccSNélio Laranjeiro (uintptr_t)(&(*rxq->cqes)[rxq->cq_ci & 16074aff4bcbSYongseok Koh cqe_cnt].pkt_info); 160899c12dccSNélio Laranjeiro 160999c12dccSNélio Laranjeiro /* Fix endianness. */ 161099c12dccSNélio Laranjeiro zip->cqe_cnt = ntohl(cqe->byte_cnt); 161199c12dccSNélio Laranjeiro /* 161299c12dccSNélio Laranjeiro * Current mini array position is the one returned by 161399c12dccSNélio Laranjeiro * check_cqe64(). 161499c12dccSNélio Laranjeiro * 161599c12dccSNélio Laranjeiro * If completion comprises several mini arrays, as a 161699c12dccSNélio Laranjeiro * special case the second one is located 7 CQEs after 161799c12dccSNélio Laranjeiro * the initial CQE instead of 8 for subsequent ones. 161899c12dccSNélio Laranjeiro */ 1619d2e842d0SYongseok Koh zip->ca = rxq->cq_ci; 162099c12dccSNélio Laranjeiro zip->na = zip->ca + 7; 162199c12dccSNélio Laranjeiro /* Compute the next non compressed CQE. */ 162299c12dccSNélio Laranjeiro --rxq->cq_ci; 162399c12dccSNélio Laranjeiro zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 162499c12dccSNélio Laranjeiro /* Get packet size to return. */ 162599c12dccSNélio Laranjeiro len = ntohl((*mc)[0].byte_cnt); 1626ecf60761SNélio Laranjeiro *rss_hash = ntohl((*mc)[0].rx_hash_result); 162799c12dccSNélio Laranjeiro zip->ai = 1; 1628d2e842d0SYongseok Koh /* Prefetch all the entries to be invalidated */ 1629d2e842d0SYongseok Koh idx = zip->ca; 1630d2e842d0SYongseok Koh end = zip->cq_ci; 1631d2e842d0SYongseok Koh while (idx != end) { 1632d2e842d0SYongseok Koh rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_cnt]); 1633d2e842d0SYongseok Koh ++idx; 1634d2e842d0SYongseok Koh } 163599c12dccSNélio Laranjeiro } else { 163699c12dccSNélio Laranjeiro len = ntohl(cqe->byte_cnt); 1637ecf60761SNélio Laranjeiro *rss_hash = ntohl(cqe->rx_hash_res); 163899c12dccSNélio Laranjeiro } 163999c12dccSNélio Laranjeiro /* Error while receiving packet. */ 164099c12dccSNélio Laranjeiro if (unlikely(MLX5_CQE_OPCODE(op_own) == MLX5_CQE_RESP_ERR)) 164199c12dccSNélio Laranjeiro return -1; 164299c12dccSNélio Laranjeiro } 164399c12dccSNélio Laranjeiro return len; 164499c12dccSNélio Laranjeiro } 164599c12dccSNélio Laranjeiro 164699c12dccSNélio Laranjeiro /** 164767fa62bcSAdrien Mazarguil * Translate RX completion flags to offload flags. 164867fa62bcSAdrien Mazarguil * 164967fa62bcSAdrien Mazarguil * @param[in] rxq 165067fa62bcSAdrien Mazarguil * Pointer to RX queue structure. 16516218063bSNélio Laranjeiro * @param[in] cqe 16526218063bSNélio Laranjeiro * Pointer to CQE. 165367fa62bcSAdrien Mazarguil * 165467fa62bcSAdrien Mazarguil * @return 165567fa62bcSAdrien Mazarguil * Offload flags (ol_flags) for struct rte_mbuf. 165667fa62bcSAdrien Mazarguil */ 165767fa62bcSAdrien Mazarguil static inline uint32_t 165897267b8eSNelio Laranjeiro rxq_cq_to_ol_flags(struct rxq *rxq, volatile struct mlx5_cqe *cqe) 165967fa62bcSAdrien Mazarguil { 166067fa62bcSAdrien Mazarguil uint32_t ol_flags = 0; 16610603df73SNélio Laranjeiro uint16_t flags = ntohs(cqe->hdr_type_etc); 166267fa62bcSAdrien Mazarguil 16630603df73SNélio Laranjeiro ol_flags = 16640603df73SNélio Laranjeiro TRANSPOSE(flags, 16650603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 16660603df73SNélio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 16670603df73SNélio Laranjeiro TRANSPOSE(flags, 16680603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 166983e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 167097267b8eSNelio Laranjeiro if ((cqe->pkt_info & MLX5_CQE_RX_TUNNEL_PACKET) && (rxq->csum_l2tun)) 167167fa62bcSAdrien Mazarguil ol_flags |= 16720603df73SNélio Laranjeiro TRANSPOSE(flags, 16730603df73SNélio Laranjeiro MLX5_CQE_RX_L3_HDR_VALID, 167483e9d9a3SNelio Laranjeiro PKT_RX_IP_CKSUM_GOOD) | 16750603df73SNélio Laranjeiro TRANSPOSE(flags, 16760603df73SNélio Laranjeiro MLX5_CQE_RX_L4_HDR_VALID, 167783e9d9a3SNelio Laranjeiro PKT_RX_L4_CKSUM_GOOD); 167867fa62bcSAdrien Mazarguil return ol_flags; 167967fa62bcSAdrien Mazarguil } 168067fa62bcSAdrien Mazarguil 168167fa62bcSAdrien Mazarguil /** 16822e22920bSAdrien Mazarguil * DPDK callback for RX. 16832e22920bSAdrien Mazarguil * 16842e22920bSAdrien Mazarguil * @param dpdk_rxq 16852e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 16862e22920bSAdrien Mazarguil * @param[out] pkts 16872e22920bSAdrien Mazarguil * Array to store received packets. 16882e22920bSAdrien Mazarguil * @param pkts_n 16892e22920bSAdrien Mazarguil * Maximum number of packets in array. 16902e22920bSAdrien Mazarguil * 16912e22920bSAdrien Mazarguil * @return 16922e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 16932e22920bSAdrien Mazarguil */ 16942e22920bSAdrien Mazarguil uint16_t 16952e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 16962e22920bSAdrien Mazarguil { 16976218063bSNélio Laranjeiro struct rxq *rxq = dpdk_rxq; 1698b4b12e55SNélio Laranjeiro const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 1699e2f116eeSNélio Laranjeiro const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 17009964b965SNélio Laranjeiro const unsigned int sges_n = rxq->sges_n; 17019964b965SNélio Laranjeiro struct rte_mbuf *pkt = NULL; 17029964b965SNélio Laranjeiro struct rte_mbuf *seg = NULL; 170397267b8eSNelio Laranjeiro volatile struct mlx5_cqe *cqe = 170497267b8eSNelio Laranjeiro &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 17059964b965SNélio Laranjeiro unsigned int i = 0; 17069964b965SNélio Laranjeiro unsigned int rq_ci = rxq->rq_ci << sges_n; 17074e66a6feSNelio Laranjeiro int len = 0; /* keep its value across iterations. */ 17082e22920bSAdrien Mazarguil 17099964b965SNélio Laranjeiro while (pkts_n) { 17109964b965SNélio Laranjeiro unsigned int idx = rq_ci & wqe_cnt; 17119964b965SNélio Laranjeiro volatile struct mlx5_wqe_data_seg *wqe = &(*rxq->wqes)[idx]; 17129964b965SNélio Laranjeiro struct rte_mbuf *rep = (*rxq->elts)[idx]; 1713ecf60761SNélio Laranjeiro uint32_t rss_hash_res = 0; 17149964b965SNélio Laranjeiro 17159964b965SNélio Laranjeiro if (pkt) 17169964b965SNélio Laranjeiro NEXT(seg) = rep; 17179964b965SNélio Laranjeiro seg = rep; 17189964b965SNélio Laranjeiro rte_prefetch0(seg); 17196218063bSNélio Laranjeiro rte_prefetch0(cqe); 17209964b965SNélio Laranjeiro rte_prefetch0(wqe); 1721fbfd9955SOlivier Matz rep = rte_mbuf_raw_alloc(rxq->mp); 17222e22920bSAdrien Mazarguil if (unlikely(rep == NULL)) { 172315a756b6SSagi Grimberg ++rxq->stats.rx_nombuf; 172415a756b6SSagi Grimberg if (!pkt) { 172515a756b6SSagi Grimberg /* 172615a756b6SSagi Grimberg * no buffers before we even started, 172715a756b6SSagi Grimberg * bail out silently. 172815a756b6SSagi Grimberg */ 172915a756b6SSagi Grimberg break; 173015a756b6SSagi Grimberg } 1731a1bdb71aSNélio Laranjeiro while (pkt != seg) { 1732a1bdb71aSNélio Laranjeiro assert(pkt != (*rxq->elts)[idx]); 1733fe5fe382SNélio Laranjeiro rep = NEXT(pkt); 17348f094a9aSOlivier Matz NEXT(pkt) = NULL; 17358f094a9aSOlivier Matz NB_SEGS(pkt) = 1; 17361f88c0a2SOlivier Matz rte_mbuf_raw_free(pkt); 1737fe5fe382SNélio Laranjeiro pkt = rep; 17389964b965SNélio Laranjeiro } 17396218063bSNélio Laranjeiro break; 17402e22920bSAdrien Mazarguil } 17419964b965SNélio Laranjeiro if (!pkt) { 174297267b8eSNelio Laranjeiro cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 1743ecf60761SNélio Laranjeiro len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, 1744ecf60761SNélio Laranjeiro &rss_hash_res); 1745ecf60761SNélio Laranjeiro if (!len) { 17461f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 17476218063bSNélio Laranjeiro break; 17486218063bSNélio Laranjeiro } 174999c12dccSNélio Laranjeiro if (unlikely(len == -1)) { 175099c12dccSNélio Laranjeiro /* RX error, packet is likely too large. */ 17511f88c0a2SOlivier Matz rte_mbuf_raw_free(rep); 175299c12dccSNélio Laranjeiro ++rxq->stats.idropped; 175399c12dccSNélio Laranjeiro goto skip; 175499c12dccSNélio Laranjeiro } 17559964b965SNélio Laranjeiro pkt = seg; 17569964b965SNélio Laranjeiro assert(len >= (rxq->crc_present << 2)); 17579964b965SNélio Laranjeiro /* Update packet information. */ 1758*48dfc20fSYongseok Koh pkt->packet_type = rxq_cq_to_pkt_type(cqe); 17590ac64846SMaxime Leroy pkt->ol_flags = 0; 176036ba0c00SNélio Laranjeiro if (rss_hash_res && rxq->rss_hash) { 1761ecf60761SNélio Laranjeiro pkt->hash.rss = rss_hash_res; 1762ecf60761SNélio Laranjeiro pkt->ol_flags = PKT_RX_RSS_HASH; 1763ecf60761SNélio Laranjeiro } 1764c604f619SNélio Laranjeiro if (rxq->mark && 1765c604f619SNélio Laranjeiro MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) { 1766b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR; 1767b268a3eeSNélio Laranjeiro if (cqe->sop_drop_qpn != 1768b268a3eeSNélio Laranjeiro htonl(MLX5_FLOW_MARK_DEFAULT)) { 1769b268a3eeSNélio Laranjeiro uint32_t mark = cqe->sop_drop_qpn; 1770b268a3eeSNélio Laranjeiro 1771b268a3eeSNélio Laranjeiro pkt->ol_flags |= PKT_RX_FDIR_ID; 1772ea3bc3b1SNélio Laranjeiro pkt->hash.fdir.hi = 1773b268a3eeSNélio Laranjeiro mlx5_flow_mark_get(mark); 1774b268a3eeSNélio Laranjeiro } 1775ea3bc3b1SNélio Laranjeiro } 1776*48dfc20fSYongseok Koh if (rxq->csum | rxq->csum_l2tun) 17776703d836SNélio Laranjeiro pkt->ol_flags |= rxq_cq_to_ol_flags(rxq, cqe); 17786703d836SNélio Laranjeiro if (rxq->vlan_strip && 17796703d836SNélio Laranjeiro (cqe->hdr_type_etc & 17806703d836SNélio Laranjeiro htons(MLX5_CQE_VLAN_STRIPPED))) { 17816218063bSNélio Laranjeiro pkt->ol_flags |= PKT_RX_VLAN_PKT | 1782b37b528dSOlivier Matz PKT_RX_VLAN_STRIPPED; 17836218063bSNélio Laranjeiro pkt->vlan_tci = ntohs(cqe->vlan_info); 1784f3db9489SYaacov Hazan } 17856218063bSNélio Laranjeiro if (rxq->crc_present) 17866218063bSNélio Laranjeiro len -= ETHER_CRC_LEN; 17876218063bSNélio Laranjeiro PKT_LEN(pkt) = len; 17889964b965SNélio Laranjeiro } 17899964b965SNélio Laranjeiro DATA_LEN(rep) = DATA_LEN(seg); 17909964b965SNélio Laranjeiro PKT_LEN(rep) = PKT_LEN(seg); 17919964b965SNélio Laranjeiro SET_DATA_OFF(rep, DATA_OFF(seg)); 17929964b965SNélio Laranjeiro PORT(rep) = PORT(seg); 17939964b965SNélio Laranjeiro (*rxq->elts)[idx] = rep; 17949964b965SNélio Laranjeiro /* 17959964b965SNélio Laranjeiro * Fill NIC descriptor with the new buffer. The lkey and size 17969964b965SNélio Laranjeiro * of the buffers are already known, only the buffer address 17979964b965SNélio Laranjeiro * changes. 17989964b965SNélio Laranjeiro */ 17999964b965SNélio Laranjeiro wqe->addr = htonll(rte_pktmbuf_mtod(rep, uintptr_t)); 18009964b965SNélio Laranjeiro if (len > DATA_LEN(seg)) { 18019964b965SNélio Laranjeiro len -= DATA_LEN(seg); 18029964b965SNélio Laranjeiro ++NB_SEGS(pkt); 18039964b965SNélio Laranjeiro ++rq_ci; 18049964b965SNélio Laranjeiro continue; 18059964b965SNélio Laranjeiro } 18069964b965SNélio Laranjeiro DATA_LEN(seg) = len; 180787011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 180887011737SAdrien Mazarguil /* Increment bytes counter. */ 18099964b965SNélio Laranjeiro rxq->stats.ibytes += PKT_LEN(pkt); 181087011737SAdrien Mazarguil #endif 18116218063bSNélio Laranjeiro /* Return packet. */ 18126218063bSNélio Laranjeiro *(pkts++) = pkt; 18139964b965SNélio Laranjeiro pkt = NULL; 18149964b965SNélio Laranjeiro --pkts_n; 18159964b965SNélio Laranjeiro ++i; 181699c12dccSNélio Laranjeiro skip: 18179964b965SNélio Laranjeiro /* Align consumer index to the next stride. */ 18189964b965SNélio Laranjeiro rq_ci >>= sges_n; 18196218063bSNélio Laranjeiro ++rq_ci; 18209964b965SNélio Laranjeiro rq_ci <<= sges_n; 18212e22920bSAdrien Mazarguil } 18229964b965SNélio Laranjeiro if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci))) 18232e22920bSAdrien Mazarguil return 0; 18246218063bSNélio Laranjeiro /* Update the consumer index. */ 18259964b965SNélio Laranjeiro rxq->rq_ci = rq_ci >> sges_n; 18266218063bSNélio Laranjeiro rte_wmb(); 18276218063bSNélio Laranjeiro *rxq->cq_db = htonl(rxq->cq_ci); 18286218063bSNélio Laranjeiro rte_wmb(); 18296218063bSNélio Laranjeiro *rxq->rq_db = htonl(rxq->rq_ci); 183087011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS 183187011737SAdrien Mazarguil /* Increment packets counter. */ 18329964b965SNélio Laranjeiro rxq->stats.ipackets += i; 183387011737SAdrien Mazarguil #endif 18349964b965SNélio Laranjeiro return i; 18352e22920bSAdrien Mazarguil } 18362e22920bSAdrien Mazarguil 18372e22920bSAdrien Mazarguil /** 18382e22920bSAdrien Mazarguil * Dummy DPDK callback for TX. 18392e22920bSAdrien Mazarguil * 18402e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 18412e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 18422e22920bSAdrien Mazarguil * 18432e22920bSAdrien Mazarguil * @param dpdk_txq 18442e22920bSAdrien Mazarguil * Generic pointer to TX queue structure. 18452e22920bSAdrien Mazarguil * @param[in] pkts 18462e22920bSAdrien Mazarguil * Packets to transmit. 18472e22920bSAdrien Mazarguil * @param pkts_n 18482e22920bSAdrien Mazarguil * Number of packets in array. 18492e22920bSAdrien Mazarguil * 18502e22920bSAdrien Mazarguil * @return 18512e22920bSAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n). 18522e22920bSAdrien Mazarguil */ 18532e22920bSAdrien Mazarguil uint16_t 18542e22920bSAdrien Mazarguil removed_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 18552e22920bSAdrien Mazarguil { 18562e22920bSAdrien Mazarguil (void)dpdk_txq; 18572e22920bSAdrien Mazarguil (void)pkts; 18582e22920bSAdrien Mazarguil (void)pkts_n; 18592e22920bSAdrien Mazarguil return 0; 18602e22920bSAdrien Mazarguil } 18612e22920bSAdrien Mazarguil 18622e22920bSAdrien Mazarguil /** 18632e22920bSAdrien Mazarguil * Dummy DPDK callback for RX. 18642e22920bSAdrien Mazarguil * 18652e22920bSAdrien Mazarguil * This function is used to temporarily replace the real callback during 18662e22920bSAdrien Mazarguil * unsafe control operations on the queue, or in case of error. 18672e22920bSAdrien Mazarguil * 18682e22920bSAdrien Mazarguil * @param dpdk_rxq 18692e22920bSAdrien Mazarguil * Generic pointer to RX queue structure. 18702e22920bSAdrien Mazarguil * @param[out] pkts 18712e22920bSAdrien Mazarguil * Array to store received packets. 18722e22920bSAdrien Mazarguil * @param pkts_n 18732e22920bSAdrien Mazarguil * Maximum number of packets in array. 18742e22920bSAdrien Mazarguil * 18752e22920bSAdrien Mazarguil * @return 18762e22920bSAdrien Mazarguil * Number of packets successfully received (<= pkts_n). 18772e22920bSAdrien Mazarguil */ 18782e22920bSAdrien Mazarguil uint16_t 18792e22920bSAdrien Mazarguil removed_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 18802e22920bSAdrien Mazarguil { 18812e22920bSAdrien Mazarguil (void)dpdk_rxq; 18822e22920bSAdrien Mazarguil (void)pkts; 18832e22920bSAdrien Mazarguil (void)pkts_n; 18842e22920bSAdrien Mazarguil return 0; 18852e22920bSAdrien Mazarguil } 18866cb559d6SYongseok Koh 18876cb559d6SYongseok Koh /* 18886cb559d6SYongseok Koh * Vectorized Rx/Tx routines are not compiled in when required vector 18896cb559d6SYongseok Koh * instructions are not supported on a target architecture. The following null 18906cb559d6SYongseok Koh * stubs are needed for linkage when those are not included outside of this file 18916cb559d6SYongseok Koh * (e.g. mlx5_rxtx_vec_sse.c for x86). 18926cb559d6SYongseok Koh */ 18936cb559d6SYongseok Koh 18946cb559d6SYongseok Koh uint16_t __attribute__((weak)) 18956cb559d6SYongseok Koh mlx5_tx_burst_raw_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 18966cb559d6SYongseok Koh { 18976cb559d6SYongseok Koh (void)dpdk_txq; 18986cb559d6SYongseok Koh (void)pkts; 18996cb559d6SYongseok Koh (void)pkts_n; 19006cb559d6SYongseok Koh return 0; 19016cb559d6SYongseok Koh } 19026cb559d6SYongseok Koh 19036cb559d6SYongseok Koh uint16_t __attribute__((weak)) 19046cb559d6SYongseok Koh mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 19056cb559d6SYongseok Koh { 19066cb559d6SYongseok Koh (void)dpdk_txq; 19076cb559d6SYongseok Koh (void)pkts; 19086cb559d6SYongseok Koh (void)pkts_n; 19096cb559d6SYongseok Koh return 0; 19106cb559d6SYongseok Koh } 19116cb559d6SYongseok Koh 19126cb559d6SYongseok Koh uint16_t __attribute__((weak)) 19136cb559d6SYongseok Koh mlx5_rx_burst_vec(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 19146cb559d6SYongseok Koh { 19156cb559d6SYongseok Koh (void)dpdk_rxq; 19166cb559d6SYongseok Koh (void)pkts; 19176cb559d6SYongseok Koh (void)pkts_n; 19186cb559d6SYongseok Koh return 0; 19196cb559d6SYongseok Koh } 19206cb559d6SYongseok Koh 19216cb559d6SYongseok Koh int __attribute__((weak)) 19226cb559d6SYongseok Koh priv_check_raw_vec_tx_support(struct priv *priv) 19236cb559d6SYongseok Koh { 19246cb559d6SYongseok Koh (void)priv; 19256cb559d6SYongseok Koh return -ENOTSUP; 19266cb559d6SYongseok Koh } 19276cb559d6SYongseok Koh 19286cb559d6SYongseok Koh int __attribute__((weak)) 19296cb559d6SYongseok Koh priv_check_vec_tx_support(struct priv *priv) 19306cb559d6SYongseok Koh { 19316cb559d6SYongseok Koh (void)priv; 19326cb559d6SYongseok Koh return -ENOTSUP; 19336cb559d6SYongseok Koh } 19346cb559d6SYongseok Koh 19356cb559d6SYongseok Koh int __attribute__((weak)) 19366cb559d6SYongseok Koh rxq_check_vec_support(struct rxq *rxq) 19376cb559d6SYongseok Koh { 19386cb559d6SYongseok Koh (void)rxq; 19396cb559d6SYongseok Koh return -ENOTSUP; 19406cb559d6SYongseok Koh } 19416cb559d6SYongseok Koh 19426cb559d6SYongseok Koh int __attribute__((weak)) 19436cb559d6SYongseok Koh priv_check_vec_rx_support(struct priv *priv) 19446cb559d6SYongseok Koh { 19456cb559d6SYongseok Koh (void)priv; 19466cb559d6SYongseok Koh return -ENOTSUP; 19476cb559d6SYongseok Koh } 19486cb559d6SYongseok Koh 19496cb559d6SYongseok Koh void __attribute__((weak)) 19506cb559d6SYongseok Koh priv_prep_vec_rx_function(struct priv *priv) 19516cb559d6SYongseok Koh { 19526cb559d6SYongseok Koh (void)priv; 19536cb559d6SYongseok Koh } 1954