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