xref: /dpdk/drivers/net/mlx5/mlx5_rxtx.c (revision 38b4b397a57dfb0f892c8289ce1e724f6a37ba0b)
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>
2888c07335SMatan Azrad #include <rte_cycles.h>
292e22920bSAdrien Mazarguil 
302e22920bSAdrien Mazarguil #include "mlx5.h"
312e22920bSAdrien Mazarguil #include "mlx5_utils.h"
322e22920bSAdrien Mazarguil #include "mlx5_rxtx.h"
33f3db9489SYaacov Hazan #include "mlx5_autoconf.h"
342e22920bSAdrien Mazarguil #include "mlx5_defs.h"
356218063bSNélio Laranjeiro #include "mlx5_prm.h"
366218063bSNélio Laranjeiro 
37c0583d98SJerin Jacob static __rte_always_inline uint32_t
383cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe);
39ff1807a3SNélio Laranjeiro 
40c0583d98SJerin Jacob static __rte_always_inline int
4178142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
422e633f1fSYongseok Koh 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe);
43ff1807a3SNélio Laranjeiro 
44c0583d98SJerin Jacob static __rte_always_inline uint32_t
456ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
46ff1807a3SNélio Laranjeiro 
473e1f82a1SYongseok Koh static __rte_always_inline void
483e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
493e1f82a1SYongseok Koh 	       volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res);
503e1f82a1SYongseok Koh 
517d6bf6b8SYongseok Koh static __rte_always_inline void
527d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx);
537d6bf6b8SYongseok Koh 
5435c090eaSMatan Azrad static int
5535c090eaSMatan Azrad mlx5_queue_state_modify(struct rte_eth_dev *dev,
5635c090eaSMatan Azrad 			struct mlx5_mp_arg_queue_state_modify *sm);
5735c090eaSMatan Azrad 
58ea16068cSYongseok Koh uint32_t mlx5_ptype_table[] __rte_cache_aligned = {
59ea16068cSYongseok Koh 	[0xff] = RTE_PTYPE_ALL_MASK, /* Last entry for errored packet. */
60ea16068cSYongseok Koh };
61ea16068cSYongseok Koh 
625f8ba81cSXueming Li uint8_t mlx5_cksum_table[1 << 10] __rte_cache_aligned;
635f8ba81cSXueming Li uint8_t mlx5_swp_types_table[1 << 10] __rte_cache_aligned;
645f8ba81cSXueming Li 
65ea16068cSYongseok Koh /**
66ea16068cSYongseok Koh  * Build a table to translate Rx completion flags to packet type.
67ea16068cSYongseok Koh  *
68ea16068cSYongseok Koh  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
69ea16068cSYongseok Koh  */
70ea16068cSYongseok Koh void
71ea16068cSYongseok Koh mlx5_set_ptype_table(void)
72ea16068cSYongseok Koh {
73ea16068cSYongseok Koh 	unsigned int i;
74ea16068cSYongseok Koh 	uint32_t (*p)[RTE_DIM(mlx5_ptype_table)] = &mlx5_ptype_table;
75ea16068cSYongseok Koh 
769807f113SYongseok Koh 	/* Last entry must not be overwritten, reserved for errored packet. */
779807f113SYongseok Koh 	for (i = 0; i < RTE_DIM(mlx5_ptype_table) - 1; ++i)
78ea16068cSYongseok Koh 		(*p)[i] = RTE_PTYPE_UNKNOWN;
796cb559d6SYongseok Koh 	/*
806cb559d6SYongseok Koh 	 * The index to the array should have:
81ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
82ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
83ea16068cSYongseok Koh 	 * bit[5] = ip_frag
84ea16068cSYongseok Koh 	 * bit[6] = tunneled
85ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
8699c12dccSNélio Laranjeiro 	 */
873ca63b88SShahaf Shuler 	/* L2 */
883ca63b88SShahaf Shuler 	(*p)[0x00] = RTE_PTYPE_L2_ETHER;
89ea16068cSYongseok Koh 	/* L3 */
90ea16068cSYongseok Koh 	(*p)[0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
91ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
92ea16068cSYongseok Koh 	(*p)[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
93ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
94ea16068cSYongseok Koh 	/* Fragmented */
95ea16068cSYongseok Koh 	(*p)[0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
96ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
97ea16068cSYongseok Koh 	(*p)[0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
98ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
99ea16068cSYongseok Koh 	/* TCP */
100ea16068cSYongseok Koh 	(*p)[0x05] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
101ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
102ea16068cSYongseok Koh 	(*p)[0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
103ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
1040915e287SBin Huang 	(*p)[0x0d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1050915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1060915e287SBin Huang 	(*p)[0x0e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1070915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1080915e287SBin Huang 	(*p)[0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1090915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1100915e287SBin Huang 	(*p)[0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1110915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
112ea16068cSYongseok Koh 	/* UDP */
113ea16068cSYongseok Koh 	(*p)[0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
114ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
115ea16068cSYongseok Koh 	(*p)[0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
116ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
117ea16068cSYongseok Koh 	/* Repeat with outer_l3_type being set. Just in case. */
118ea16068cSYongseok Koh 	(*p)[0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
119ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
120ea16068cSYongseok Koh 	(*p)[0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
121ea16068cSYongseok Koh 		     RTE_PTYPE_L4_NONFRAG;
122ea16068cSYongseok Koh 	(*p)[0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
123ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
124ea16068cSYongseok Koh 	(*p)[0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
125ea16068cSYongseok Koh 		     RTE_PTYPE_L4_FRAG;
126ea16068cSYongseok Koh 	(*p)[0x85] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
127ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
128ea16068cSYongseok Koh 	(*p)[0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
129ea16068cSYongseok Koh 		     RTE_PTYPE_L4_TCP;
1300915e287SBin Huang 	(*p)[0x8d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1310915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1320915e287SBin Huang 	(*p)[0x8e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1330915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1340915e287SBin Huang 	(*p)[0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1350915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
1360915e287SBin Huang 	(*p)[0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1370915e287SBin Huang 		     RTE_PTYPE_L4_TCP;
138ea16068cSYongseok Koh 	(*p)[0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
139ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
140ea16068cSYongseok Koh 	(*p)[0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
141ea16068cSYongseok Koh 		     RTE_PTYPE_L4_UDP;
142ea16068cSYongseok Koh 	/* Tunneled - L3 */
1433cc08bc6SXueming Li 	(*p)[0x40] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
144ea16068cSYongseok Koh 	(*p)[0x41] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
145ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
146ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
147ea16068cSYongseok Koh 	(*p)[0x42] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
148ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
149ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
1503cc08bc6SXueming Li 	(*p)[0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
151ea16068cSYongseok Koh 	(*p)[0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
152ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
153ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
154ea16068cSYongseok Koh 	(*p)[0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
155ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
156ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_NONFRAG;
157ea16068cSYongseok Koh 	/* Tunneled - Fragmented */
158ea16068cSYongseok Koh 	(*p)[0x61] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
159ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
160ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
161ea16068cSYongseok Koh 	(*p)[0x62] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
162ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
163ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
164ea16068cSYongseok Koh 	(*p)[0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
165ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
166ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
167ea16068cSYongseok Koh 	(*p)[0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
168ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
169ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L4_FRAG;
170ea16068cSYongseok Koh 	/* Tunneled - TCP */
171ea16068cSYongseok Koh 	(*p)[0x45] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
172ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1736c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
174ea16068cSYongseok Koh 	(*p)[0x46] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
175ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1766c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
1770915e287SBin Huang 	(*p)[0x4d] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1780915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1790915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1800915e287SBin Huang 	(*p)[0x4e] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1810915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1820915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1830915e287SBin Huang 	(*p)[0x51] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1840915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1850915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1860915e287SBin Huang 	(*p)[0x52] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
1870915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1880915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
189ea16068cSYongseok Koh 	(*p)[0xc5] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
190ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1916c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
192ea16068cSYongseok Koh 	(*p)[0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
193ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
1946c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_TCP;
1950915e287SBin Huang 	(*p)[0xcd] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1960915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
1970915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
1980915e287SBin Huang 	(*p)[0xce] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
1990915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2000915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
2010915e287SBin Huang 	(*p)[0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
2020915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
2030915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
2040915e287SBin Huang 	(*p)[0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
2050915e287SBin Huang 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2060915e287SBin Huang 		     RTE_PTYPE_INNER_L4_TCP;
207ea16068cSYongseok Koh 	/* Tunneled - UDP */
208ea16068cSYongseok Koh 	(*p)[0x49] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
209ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
2106c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
211ea16068cSYongseok Koh 	(*p)[0x4a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
212ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2136c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
214ea16068cSYongseok Koh 	(*p)[0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
215ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
2166c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
217ea16068cSYongseok Koh 	(*p)[0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
218ea16068cSYongseok Koh 		     RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
2196c897093SYongseok Koh 		     RTE_PTYPE_INNER_L4_UDP;
220ea16068cSYongseok Koh }
221fdcb0f53SNélio Laranjeiro 
2222e22920bSAdrien Mazarguil /**
2235f8ba81cSXueming Li  * Build a table to translate packet to checksum type of Verbs.
2245f8ba81cSXueming Li  */
2255f8ba81cSXueming Li void
2265f8ba81cSXueming Li mlx5_set_cksum_table(void)
2275f8ba81cSXueming Li {
2285f8ba81cSXueming Li 	unsigned int i;
2295f8ba81cSXueming Li 	uint8_t v;
2305f8ba81cSXueming Li 
2315f8ba81cSXueming Li 	/*
2325f8ba81cSXueming Li 	 * The index should have:
2335f8ba81cSXueming Li 	 * bit[0] = PKT_TX_TCP_SEG
2345f8ba81cSXueming Li 	 * bit[2:3] = PKT_TX_UDP_CKSUM, PKT_TX_TCP_CKSUM
2355f8ba81cSXueming Li 	 * bit[4] = PKT_TX_IP_CKSUM
2365f8ba81cSXueming Li 	 * bit[8] = PKT_TX_OUTER_IP_CKSUM
2375f8ba81cSXueming Li 	 * bit[9] = tunnel
2385f8ba81cSXueming Li 	 */
2395f8ba81cSXueming Li 	for (i = 0; i < RTE_DIM(mlx5_cksum_table); ++i) {
2405f8ba81cSXueming Li 		v = 0;
2415f8ba81cSXueming Li 		if (i & (1 << 9)) {
2425f8ba81cSXueming Li 			/* Tunneled packet. */
2435f8ba81cSXueming Li 			if (i & (1 << 8)) /* Outer IP. */
2445f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_CSUM;
2455f8ba81cSXueming Li 			if (i & (1 << 4)) /* Inner IP. */
2465f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_INNER_CSUM;
2475f8ba81cSXueming Li 			if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
2485f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L4_INNER_CSUM;
2495f8ba81cSXueming Li 		} else {
2505f8ba81cSXueming Li 			/* No tunnel. */
2515f8ba81cSXueming Li 			if (i & (1 << 4)) /* IP. */
2525f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L3_CSUM;
2535f8ba81cSXueming Li 			if (i & (3 << 2 | 1 << 0)) /* L4 or TSO. */
2545f8ba81cSXueming Li 				v |= MLX5_ETH_WQE_L4_CSUM;
2555f8ba81cSXueming Li 		}
2565f8ba81cSXueming Li 		mlx5_cksum_table[i] = v;
2575f8ba81cSXueming Li 	}
2585f8ba81cSXueming Li }
2595f8ba81cSXueming Li 
2605f8ba81cSXueming Li /**
2615f8ba81cSXueming Li  * Build a table to translate packet type of mbuf to SWP type of Verbs.
2625f8ba81cSXueming Li  */
2635f8ba81cSXueming Li void
2645f8ba81cSXueming Li mlx5_set_swp_types_table(void)
2655f8ba81cSXueming Li {
2665f8ba81cSXueming Li 	unsigned int i;
2675f8ba81cSXueming Li 	uint8_t v;
2685f8ba81cSXueming Li 
2695f8ba81cSXueming Li 	/*
2705f8ba81cSXueming Li 	 * The index should have:
2715f8ba81cSXueming Li 	 * bit[0:1] = PKT_TX_L4_MASK
2725f8ba81cSXueming Li 	 * bit[4] = PKT_TX_IPV6
2735f8ba81cSXueming Li 	 * bit[8] = PKT_TX_OUTER_IPV6
2745f8ba81cSXueming Li 	 * bit[9] = PKT_TX_OUTER_UDP
2755f8ba81cSXueming Li 	 */
2765f8ba81cSXueming Li 	for (i = 0; i < RTE_DIM(mlx5_swp_types_table); ++i) {
2775f8ba81cSXueming Li 		v = 0;
2785f8ba81cSXueming Li 		if (i & (1 << 8))
2795f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L3_OUTER_IPV6;
2805f8ba81cSXueming Li 		if (i & (1 << 9))
2815f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L4_OUTER_UDP;
2825f8ba81cSXueming Li 		if (i & (1 << 4))
2835f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L3_INNER_IPV6;
2845f8ba81cSXueming Li 		if ((i & 3) == (PKT_TX_UDP_CKSUM >> 52))
2855f8ba81cSXueming Li 			v |= MLX5_ETH_WQE_L4_INNER_UDP;
2865f8ba81cSXueming Li 		mlx5_swp_types_table[i] = v;
2875f8ba81cSXueming Li 	}
2885f8ba81cSXueming Li }
2895f8ba81cSXueming Li 
2905f8ba81cSXueming Li /**
29126f04883STom Barbette  * Internal function to compute the number of used descriptors in an RX queue
2928788fec1SOlivier Matz  *
29326f04883STom Barbette  * @param rxq
29426f04883STom Barbette  *   The Rx queue.
2958788fec1SOlivier Matz  *
2968788fec1SOlivier Matz  * @return
29726f04883STom Barbette  *   The number of used rx descriptor.
2988788fec1SOlivier Matz  */
29926f04883STom Barbette static uint32_t
30026f04883STom Barbette rx_queue_count(struct mlx5_rxq_data *rxq)
3018788fec1SOlivier Matz {
3028788fec1SOlivier Matz 	struct rxq_zip *zip = &rxq->zip;
3038788fec1SOlivier Matz 	volatile struct mlx5_cqe *cqe;
3048788fec1SOlivier Matz 	const unsigned int cqe_n = (1 << rxq->cqe_n);
3058788fec1SOlivier Matz 	const unsigned int cqe_cnt = cqe_n - 1;
3068788fec1SOlivier Matz 	unsigned int cq_ci;
3078788fec1SOlivier Matz 	unsigned int used;
3088788fec1SOlivier Matz 
3098788fec1SOlivier Matz 	/* if we are processing a compressed cqe */
3108788fec1SOlivier Matz 	if (zip->ai) {
3118788fec1SOlivier Matz 		used = zip->cqe_cnt - zip->ca;
3128788fec1SOlivier Matz 		cq_ci = zip->cq_ci;
3138788fec1SOlivier Matz 	} else {
3148788fec1SOlivier Matz 		used = 0;
3158788fec1SOlivier Matz 		cq_ci = rxq->cq_ci;
3168788fec1SOlivier Matz 	}
3178788fec1SOlivier Matz 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
31888c07335SMatan Azrad 	while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) {
3198788fec1SOlivier Matz 		int8_t op_own;
3208788fec1SOlivier Matz 		unsigned int n;
3218788fec1SOlivier Matz 
3228788fec1SOlivier Matz 		op_own = cqe->op_own;
3238788fec1SOlivier Matz 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
3246b30a6a8SShachar Beiser 			n = rte_be_to_cpu_32(cqe->byte_cnt);
3258788fec1SOlivier Matz 		else
3268788fec1SOlivier Matz 			n = 1;
3278788fec1SOlivier Matz 		cq_ci += n;
3288788fec1SOlivier Matz 		used += n;
3298788fec1SOlivier Matz 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
3308788fec1SOlivier Matz 	}
3318788fec1SOlivier Matz 	used = RTE_MIN(used, (1U << rxq->elts_n) - 1);
33226f04883STom Barbette 	return used;
33326f04883STom Barbette }
33426f04883STom Barbette 
33526f04883STom Barbette /**
33626f04883STom Barbette  * DPDK callback to check the status of a rx descriptor.
33726f04883STom Barbette  *
33826f04883STom Barbette  * @param rx_queue
33926f04883STom Barbette  *   The Rx queue.
34026f04883STom Barbette  * @param[in] offset
34126f04883STom Barbette  *   The index of the descriptor in the ring.
34226f04883STom Barbette  *
34326f04883STom Barbette  * @return
34426f04883STom Barbette  *   The status of the tx descriptor.
34526f04883STom Barbette  */
34626f04883STom Barbette int
34726f04883STom Barbette mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
34826f04883STom Barbette {
34926f04883STom Barbette 	struct mlx5_rxq_data *rxq = rx_queue;
35026f04883STom Barbette 	struct mlx5_rxq_ctrl *rxq_ctrl =
35126f04883STom Barbette 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
35226f04883STom Barbette 	struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv);
35326f04883STom Barbette 
35426f04883STom Barbette 	if (dev->rx_pkt_burst != mlx5_rx_burst) {
35526f04883STom Barbette 		rte_errno = ENOTSUP;
35626f04883STom Barbette 		return -rte_errno;
35726f04883STom Barbette 	}
35826f04883STom Barbette 	if (offset >= (1 << rxq->elts_n)) {
35926f04883STom Barbette 		rte_errno = EINVAL;
36026f04883STom Barbette 		return -rte_errno;
36126f04883STom Barbette 	}
36226f04883STom Barbette 	if (offset < rx_queue_count(rxq))
3638788fec1SOlivier Matz 		return RTE_ETH_RX_DESC_DONE;
3648788fec1SOlivier Matz 	return RTE_ETH_RX_DESC_AVAIL;
3658788fec1SOlivier Matz }
3668788fec1SOlivier Matz 
3678788fec1SOlivier Matz /**
36826f04883STom Barbette  * DPDK callback to get the number of used descriptors in a RX queue
36926f04883STom Barbette  *
37026f04883STom Barbette  * @param dev
37126f04883STom Barbette  *   Pointer to the device structure.
37226f04883STom Barbette  *
37326f04883STom Barbette  * @param rx_queue_id
37426f04883STom Barbette  *   The Rx queue.
37526f04883STom Barbette  *
37626f04883STom Barbette  * @return
37726f04883STom Barbette  *   The number of used rx descriptor.
37826f04883STom Barbette  *   -EINVAL if the queue is invalid
37926f04883STom Barbette  */
38026f04883STom Barbette uint32_t
38126f04883STom Barbette mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
38226f04883STom Barbette {
383dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
38426f04883STom Barbette 	struct mlx5_rxq_data *rxq;
38526f04883STom Barbette 
38626f04883STom Barbette 	if (dev->rx_pkt_burst != mlx5_rx_burst) {
38726f04883STom Barbette 		rte_errno = ENOTSUP;
38826f04883STom Barbette 		return -rte_errno;
38926f04883STom Barbette 	}
39026f04883STom Barbette 	rxq = (*priv->rxqs)[rx_queue_id];
39126f04883STom Barbette 	if (!rxq) {
39226f04883STom Barbette 		rte_errno = EINVAL;
39326f04883STom Barbette 		return -rte_errno;
39426f04883STom Barbette 	}
39526f04883STom Barbette 	return rx_queue_count(rxq);
39626f04883STom Barbette }
39726f04883STom Barbette 
398066cfecdSMatan Azrad #define MLX5_SYSTEM_LOG_DIR "/var/log"
399066cfecdSMatan Azrad /**
400066cfecdSMatan Azrad  * Dump debug information to log file.
401066cfecdSMatan Azrad  *
402066cfecdSMatan Azrad  * @param fname
403066cfecdSMatan Azrad  *   The file name.
404066cfecdSMatan Azrad  * @param hex_title
405066cfecdSMatan Azrad  *   If not NULL this string is printed as a header to the output
406066cfecdSMatan Azrad  *   and the output will be in hexadecimal view.
407066cfecdSMatan Azrad  * @param buf
408066cfecdSMatan Azrad  *   This is the buffer address to print out.
409066cfecdSMatan Azrad  * @param len
410066cfecdSMatan Azrad  *   The number of bytes to dump out.
411066cfecdSMatan Azrad  */
412066cfecdSMatan Azrad void
413066cfecdSMatan Azrad mlx5_dump_debug_information(const char *fname, const char *hex_title,
414066cfecdSMatan Azrad 			    const void *buf, unsigned int hex_len)
415066cfecdSMatan Azrad {
416066cfecdSMatan Azrad 	FILE *fd;
417066cfecdSMatan Azrad 
418066cfecdSMatan Azrad 	MKSTR(path, "%s/%s", MLX5_SYSTEM_LOG_DIR, fname);
419066cfecdSMatan Azrad 	fd = fopen(path, "a+");
420066cfecdSMatan Azrad 	if (!fd) {
421066cfecdSMatan Azrad 		DRV_LOG(WARNING, "cannot open %s for debug dump\n",
422066cfecdSMatan Azrad 			path);
423066cfecdSMatan Azrad 		MKSTR(path2, "./%s", fname);
424066cfecdSMatan Azrad 		fd = fopen(path2, "a+");
425066cfecdSMatan Azrad 		if (!fd) {
426066cfecdSMatan Azrad 			DRV_LOG(ERR, "cannot open %s for debug dump\n",
427066cfecdSMatan Azrad 				path2);
428066cfecdSMatan Azrad 			return;
429066cfecdSMatan Azrad 		}
430066cfecdSMatan Azrad 		DRV_LOG(INFO, "New debug dump in file %s\n", path2);
431066cfecdSMatan Azrad 	} else {
432066cfecdSMatan Azrad 		DRV_LOG(INFO, "New debug dump in file %s\n", path);
433066cfecdSMatan Azrad 	}
434066cfecdSMatan Azrad 	if (hex_title)
435066cfecdSMatan Azrad 		rte_hexdump(fd, hex_title, buf, hex_len);
436066cfecdSMatan Azrad 	else
437066cfecdSMatan Azrad 		fprintf(fd, "%s", (const char *)buf);
438066cfecdSMatan Azrad 	fprintf(fd, "\n\n\n");
439066cfecdSMatan Azrad 	fclose(fd);
440066cfecdSMatan Azrad }
441066cfecdSMatan Azrad 
44226f04883STom Barbette /**
44335c090eaSMatan Azrad  * Move QP from error state to running state and initialize indexes.
444957e45fbSMatan Azrad  *
44535c090eaSMatan Azrad  * @param txq_ctrl
44635c090eaSMatan Azrad  *   Pointer to TX queue control structure.
447957e45fbSMatan Azrad  *
448957e45fbSMatan Azrad  * @return
44935c090eaSMatan Azrad  *   0 on success, else -1.
450957e45fbSMatan Azrad  */
451957e45fbSMatan Azrad static int
45235c090eaSMatan Azrad tx_recover_qp(struct mlx5_txq_ctrl *txq_ctrl)
453957e45fbSMatan Azrad {
45435c090eaSMatan Azrad 	struct mlx5_mp_arg_queue_state_modify sm = {
45535c090eaSMatan Azrad 			.is_wq = 0,
45635c090eaSMatan Azrad 			.queue_id = txq_ctrl->txq.idx,
457957e45fbSMatan Azrad 	};
45835c090eaSMatan Azrad 
45935c090eaSMatan Azrad 	if (mlx5_queue_state_modify(ETH_DEV(txq_ctrl->priv), &sm))
46035c090eaSMatan Azrad 		return -1;
46135c090eaSMatan Azrad 	txq_ctrl->txq.wqe_ci = 0;
46235c090eaSMatan Azrad 	txq_ctrl->txq.wqe_pi = 0;
46335c090eaSMatan Azrad 	txq_ctrl->txq.elts_comp = 0;
464957e45fbSMatan Azrad 	return 0;
465957e45fbSMatan Azrad }
466957e45fbSMatan Azrad 
467957e45fbSMatan Azrad /* Return 1 if the error CQE is signed otherwise, sign it and return 0. */
468957e45fbSMatan Azrad static int
469957e45fbSMatan Azrad check_err_cqe_seen(volatile struct mlx5_err_cqe *err_cqe)
470957e45fbSMatan Azrad {
471957e45fbSMatan Azrad 	static const uint8_t magic[] = "seen";
472957e45fbSMatan Azrad 	int ret = 1;
473957e45fbSMatan Azrad 	unsigned int i;
474957e45fbSMatan Azrad 
475957e45fbSMatan Azrad 	for (i = 0; i < sizeof(magic); ++i)
476957e45fbSMatan Azrad 		if (!ret || err_cqe->rsvd1[i] != magic[i]) {
477957e45fbSMatan Azrad 			ret = 0;
478957e45fbSMatan Azrad 			err_cqe->rsvd1[i] = magic[i];
479957e45fbSMatan Azrad 		}
480957e45fbSMatan Azrad 	return ret;
481957e45fbSMatan Azrad }
482957e45fbSMatan Azrad 
483957e45fbSMatan Azrad /**
484957e45fbSMatan Azrad  * Handle error CQE.
485957e45fbSMatan Azrad  *
486957e45fbSMatan Azrad  * @param txq
487957e45fbSMatan Azrad  *   Pointer to TX queue structure.
488957e45fbSMatan Azrad  * @param error_cqe
489957e45fbSMatan Azrad  *   Pointer to the error CQE.
490957e45fbSMatan Azrad  *
491957e45fbSMatan Azrad  * @return
492957e45fbSMatan Azrad  *   The last Tx buffer element to free.
493957e45fbSMatan Azrad  */
494957e45fbSMatan Azrad uint16_t
495957e45fbSMatan Azrad mlx5_tx_error_cqe_handle(struct mlx5_txq_data *txq,
496957e45fbSMatan Azrad 			 volatile struct mlx5_err_cqe *err_cqe)
497957e45fbSMatan Azrad {
498957e45fbSMatan Azrad 	if (err_cqe->syndrome != MLX5_CQE_SYNDROME_WR_FLUSH_ERR) {
499957e45fbSMatan Azrad 		const uint16_t wqe_m = ((1 << txq->wqe_n) - 1);
500957e45fbSMatan Azrad 		struct mlx5_txq_ctrl *txq_ctrl =
501957e45fbSMatan Azrad 				container_of(txq, struct mlx5_txq_ctrl, txq);
502957e45fbSMatan Azrad 		uint16_t new_wqe_pi = rte_be_to_cpu_16(err_cqe->wqe_counter);
503957e45fbSMatan Azrad 		int seen = check_err_cqe_seen(err_cqe);
504957e45fbSMatan Azrad 
505957e45fbSMatan Azrad 		if (!seen && txq_ctrl->dump_file_n <
506957e45fbSMatan Azrad 		    txq_ctrl->priv->config.max_dump_files_num) {
507957e45fbSMatan Azrad 			MKSTR(err_str, "Unexpected CQE error syndrome "
508957e45fbSMatan Azrad 			      "0x%02x CQN = %u SQN = %u wqe_counter = %u "
509957e45fbSMatan Azrad 			      "wq_ci = %u cq_ci = %u", err_cqe->syndrome,
510*38b4b397SViacheslav Ovsiienko 			      txq->cqe_s, txq->qp_num_8s >> 8,
511957e45fbSMatan Azrad 			      rte_be_to_cpu_16(err_cqe->wqe_counter),
512957e45fbSMatan Azrad 			      txq->wqe_ci, txq->cq_ci);
513957e45fbSMatan Azrad 			MKSTR(name, "dpdk_mlx5_port_%u_txq_%u_index_%u_%u",
514957e45fbSMatan Azrad 			      PORT_ID(txq_ctrl->priv), txq->idx,
515957e45fbSMatan Azrad 			      txq_ctrl->dump_file_n, (uint32_t)rte_rdtsc());
516957e45fbSMatan Azrad 			mlx5_dump_debug_information(name, NULL, err_str, 0);
517957e45fbSMatan Azrad 			mlx5_dump_debug_information(name, "MLX5 Error CQ:",
518957e45fbSMatan Azrad 						    (const void *)((uintptr_t)
519*38b4b397SViacheslav Ovsiienko 						    txq->cqes),
520957e45fbSMatan Azrad 						    sizeof(*err_cqe) *
521957e45fbSMatan Azrad 						    (1 << txq->cqe_n));
522957e45fbSMatan Azrad 			mlx5_dump_debug_information(name, "MLX5 Error SQ:",
523957e45fbSMatan Azrad 						    (const void *)((uintptr_t)
524a6bd4911SViacheslav Ovsiienko 						    txq->wqes),
525957e45fbSMatan Azrad 						    MLX5_WQE_SIZE *
526957e45fbSMatan Azrad 						    (1 << txq->wqe_n));
527957e45fbSMatan Azrad 			txq_ctrl->dump_file_n++;
528957e45fbSMatan Azrad 		}
529957e45fbSMatan Azrad 		if (!seen)
530957e45fbSMatan Azrad 			/*
531957e45fbSMatan Azrad 			 * Count errors in WQEs units.
532957e45fbSMatan Azrad 			 * Later it can be improved to count error packets,
533957e45fbSMatan Azrad 			 * for example, by SQ parsing to find how much packets
534957e45fbSMatan Azrad 			 * should be counted for each WQE.
535957e45fbSMatan Azrad 			 */
536957e45fbSMatan Azrad 			txq->stats.oerrors += ((txq->wqe_ci & wqe_m) -
537957e45fbSMatan Azrad 						new_wqe_pi) & wqe_m;
53835c090eaSMatan Azrad 		if (tx_recover_qp(txq_ctrl) == 0) {
539957e45fbSMatan Azrad 			txq->cq_ci++;
540957e45fbSMatan Azrad 			/* Release all the remaining buffers. */
541957e45fbSMatan Azrad 			return txq->elts_head;
542957e45fbSMatan Azrad 		}
543957e45fbSMatan Azrad 		/* Recovering failed - try again later on the same WQE. */
544957e45fbSMatan Azrad 	} else {
545957e45fbSMatan Azrad 		txq->cq_ci++;
546957e45fbSMatan Azrad 	}
547957e45fbSMatan Azrad 	/* Do not release buffers. */
548957e45fbSMatan Azrad 	return txq->elts_tail;
549957e45fbSMatan Azrad }
550957e45fbSMatan Azrad 
551957e45fbSMatan Azrad /**
55267fa62bcSAdrien Mazarguil  * Translate RX completion flags to packet type.
55367fa62bcSAdrien Mazarguil  *
5543cc08bc6SXueming Li  * @param[in] rxq
5553cc08bc6SXueming Li  *   Pointer to RX queue structure.
5566218063bSNélio Laranjeiro  * @param[in] cqe
5576218063bSNélio Laranjeiro  *   Pointer to CQE.
55867fa62bcSAdrien Mazarguil  *
55978a38edfSJianfeng Tan  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
56078a38edfSJianfeng Tan  *
56167fa62bcSAdrien Mazarguil  * @return
56267fa62bcSAdrien Mazarguil  *   Packet type for struct rte_mbuf.
56367fa62bcSAdrien Mazarguil  */
56467fa62bcSAdrien Mazarguil static inline uint32_t
5653cc08bc6SXueming Li rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe)
56667fa62bcSAdrien Mazarguil {
567ea16068cSYongseok Koh 	uint8_t idx;
568ea16068cSYongseok Koh 	uint8_t pinfo = cqe->pkt_info;
569ea16068cSYongseok Koh 	uint16_t ptype = cqe->hdr_type_etc;
57067fa62bcSAdrien Mazarguil 
571ea16068cSYongseok Koh 	/*
572ea16068cSYongseok Koh 	 * The index to the array should have:
573ea16068cSYongseok Koh 	 * bit[1:0] = l3_hdr_type
574ea16068cSYongseok Koh 	 * bit[4:2] = l4_hdr_type
575ea16068cSYongseok Koh 	 * bit[5] = ip_frag
576ea16068cSYongseok Koh 	 * bit[6] = tunneled
577ea16068cSYongseok Koh 	 * bit[7] = outer_l3_type
578ea16068cSYongseok Koh 	 */
579ea16068cSYongseok Koh 	idx = ((pinfo & 0x3) << 6) | ((ptype & 0xfc00) >> 10);
5803cc08bc6SXueming Li 	return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
58167fa62bcSAdrien Mazarguil }
58267fa62bcSAdrien Mazarguil 
58367fa62bcSAdrien Mazarguil /**
5846bb506ccSMatan Azrad  * Initialize Rx WQ and indexes.
5856bb506ccSMatan Azrad  *
5866bb506ccSMatan Azrad  * @param[in] rxq
5876bb506ccSMatan Azrad  *   Pointer to RX queue structure.
5886bb506ccSMatan Azrad  */
5896bb506ccSMatan Azrad void
5906bb506ccSMatan Azrad mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
5916bb506ccSMatan Azrad {
5926bb506ccSMatan Azrad 	const unsigned int wqe_n = 1 << rxq->elts_n;
5936bb506ccSMatan Azrad 	unsigned int i;
5946bb506ccSMatan Azrad 
5956bb506ccSMatan Azrad 	for (i = 0; (i != wqe_n); ++i) {
5966bb506ccSMatan Azrad 		volatile struct mlx5_wqe_data_seg *scat;
5976bb506ccSMatan Azrad 		uintptr_t addr;
5986bb506ccSMatan Azrad 		uint32_t byte_count;
5996bb506ccSMatan Azrad 
6006bb506ccSMatan Azrad 		if (mlx5_rxq_mprq_enabled(rxq)) {
6016bb506ccSMatan Azrad 			struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
6026bb506ccSMatan Azrad 
6036bb506ccSMatan Azrad 			scat = &((volatile struct mlx5_wqe_mprq *)
6046bb506ccSMatan Azrad 				rxq->wqes)[i].dseg;
6056bb506ccSMatan Azrad 			addr = (uintptr_t)mlx5_mprq_buf_addr(buf);
6066bb506ccSMatan Azrad 			byte_count = (1 << rxq->strd_sz_n) *
6076bb506ccSMatan Azrad 					(1 << rxq->strd_num_n);
6086bb506ccSMatan Azrad 		} else {
6096bb506ccSMatan Azrad 			struct rte_mbuf *buf = (*rxq->elts)[i];
6106bb506ccSMatan Azrad 
6116bb506ccSMatan Azrad 			scat = &((volatile struct mlx5_wqe_data_seg *)
6126bb506ccSMatan Azrad 					rxq->wqes)[i];
6136bb506ccSMatan Azrad 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
6146bb506ccSMatan Azrad 			byte_count = DATA_LEN(buf);
6156bb506ccSMatan Azrad 		}
6166bb506ccSMatan Azrad 		/* scat->addr must be able to store a pointer. */
6176bb506ccSMatan Azrad 		assert(sizeof(scat->addr) >= sizeof(uintptr_t));
6186bb506ccSMatan Azrad 		*scat = (struct mlx5_wqe_data_seg){
6196bb506ccSMatan Azrad 			.addr = rte_cpu_to_be_64(addr),
6206bb506ccSMatan Azrad 			.byte_count = rte_cpu_to_be_32(byte_count),
6216bb506ccSMatan Azrad 			.lkey = mlx5_rx_addr2mr(rxq, addr),
6226bb506ccSMatan Azrad 		};
6236bb506ccSMatan Azrad 	}
6246bb506ccSMatan Azrad 	rxq->consumed_strd = 0;
6256bb506ccSMatan Azrad 	rxq->decompressed = 0;
6266bb506ccSMatan Azrad 	rxq->rq_pi = 0;
6276bb506ccSMatan Azrad 	rxq->zip = (struct rxq_zip){
6286bb506ccSMatan Azrad 		.ai = 0,
6296bb506ccSMatan Azrad 	};
6306bb506ccSMatan Azrad 	/* Update doorbell counter. */
6316bb506ccSMatan Azrad 	rxq->rq_ci = wqe_n >> rxq->sges_n;
6326bb506ccSMatan Azrad 	rte_cio_wmb();
6336bb506ccSMatan Azrad 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
6346bb506ccSMatan Azrad }
6356bb506ccSMatan Azrad 
6366bb506ccSMatan Azrad /**
6372d77cb61SMatan Azrad  * Modify a Verbs queue state.
6382d77cb61SMatan Azrad  * This must be called from the primary process.
6392d77cb61SMatan Azrad  *
6402d77cb61SMatan Azrad  * @param dev
6412d77cb61SMatan Azrad  *   Pointer to Ethernet device.
6422d77cb61SMatan Azrad  * @param sm
6432d77cb61SMatan Azrad  *   State modify request parameters.
6442d77cb61SMatan Azrad  *
6452d77cb61SMatan Azrad  * @return
6462d77cb61SMatan Azrad  *   0 in case of success else non-zero value and rte_errno is set.
6472d77cb61SMatan Azrad  */
6482d77cb61SMatan Azrad int
6492d77cb61SMatan Azrad mlx5_queue_state_modify_primary(struct rte_eth_dev *dev,
6502d77cb61SMatan Azrad 			const struct mlx5_mp_arg_queue_state_modify *sm)
6512d77cb61SMatan Azrad {
6522d77cb61SMatan Azrad 	int ret;
6532d77cb61SMatan Azrad 	struct mlx5_priv *priv = dev->data->dev_private;
6542d77cb61SMatan Azrad 
6552d77cb61SMatan Azrad 	if (sm->is_wq) {
6562d77cb61SMatan Azrad 		struct ibv_wq_attr mod = {
6572d77cb61SMatan Azrad 			.attr_mask = IBV_WQ_ATTR_STATE,
6582d77cb61SMatan Azrad 			.wq_state = sm->state,
6592d77cb61SMatan Azrad 		};
6602d77cb61SMatan Azrad 		struct mlx5_rxq_data *rxq = (*priv->rxqs)[sm->queue_id];
6612d77cb61SMatan Azrad 		struct mlx5_rxq_ctrl *rxq_ctrl =
6622d77cb61SMatan Azrad 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
6632d77cb61SMatan Azrad 
6642d77cb61SMatan Azrad 		ret = mlx5_glue->modify_wq(rxq_ctrl->ibv->wq, &mod);
6652d77cb61SMatan Azrad 		if (ret) {
6662d77cb61SMatan Azrad 			DRV_LOG(ERR, "Cannot change Rx WQ state to %u  - %s\n",
6672d77cb61SMatan Azrad 					sm->state, strerror(errno));
6682d77cb61SMatan Azrad 			rte_errno = errno;
6692d77cb61SMatan Azrad 			return ret;
6702d77cb61SMatan Azrad 		}
67135c090eaSMatan Azrad 	} else {
67235c090eaSMatan Azrad 		struct mlx5_txq_data *txq = (*priv->txqs)[sm->queue_id];
67335c090eaSMatan Azrad 		struct mlx5_txq_ctrl *txq_ctrl =
67435c090eaSMatan Azrad 			container_of(txq, struct mlx5_txq_ctrl, txq);
67535c090eaSMatan Azrad 		struct ibv_qp_attr mod = {
67635c090eaSMatan Azrad 			.qp_state = IBV_QPS_RESET,
67735c090eaSMatan Azrad 			.port_num = (uint8_t)priv->ibv_port,
67835c090eaSMatan Azrad 		};
67935c090eaSMatan Azrad 		struct ibv_qp *qp = txq_ctrl->ibv->qp;
68035c090eaSMatan Azrad 
68135c090eaSMatan Azrad 		ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
68235c090eaSMatan Azrad 		if (ret) {
68335c090eaSMatan Azrad 			DRV_LOG(ERR, "Cannot change the Tx QP state to RESET "
68435c090eaSMatan Azrad 				"%s\n", strerror(errno));
68535c090eaSMatan Azrad 			rte_errno = errno;
68635c090eaSMatan Azrad 			return ret;
68735c090eaSMatan Azrad 		}
68835c090eaSMatan Azrad 		mod.qp_state = IBV_QPS_INIT;
68935c090eaSMatan Azrad 		ret = mlx5_glue->modify_qp(qp, &mod,
69035c090eaSMatan Azrad 					   (IBV_QP_STATE | IBV_QP_PORT));
69135c090eaSMatan Azrad 		if (ret) {
69235c090eaSMatan Azrad 			DRV_LOG(ERR, "Cannot change Tx QP state to INIT %s\n",
69335c090eaSMatan Azrad 				strerror(errno));
69435c090eaSMatan Azrad 			rte_errno = errno;
69535c090eaSMatan Azrad 			return ret;
69635c090eaSMatan Azrad 		}
69735c090eaSMatan Azrad 		mod.qp_state = IBV_QPS_RTR;
69835c090eaSMatan Azrad 		ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
69935c090eaSMatan Azrad 		if (ret) {
70035c090eaSMatan Azrad 			DRV_LOG(ERR, "Cannot change Tx QP state to RTR %s\n",
70135c090eaSMatan Azrad 				strerror(errno));
70235c090eaSMatan Azrad 			rte_errno = errno;
70335c090eaSMatan Azrad 			return ret;
70435c090eaSMatan Azrad 		}
70535c090eaSMatan Azrad 		mod.qp_state = IBV_QPS_RTS;
70635c090eaSMatan Azrad 		ret = mlx5_glue->modify_qp(qp, &mod, IBV_QP_STATE);
70735c090eaSMatan Azrad 		if (ret) {
70835c090eaSMatan Azrad 			DRV_LOG(ERR, "Cannot change Tx QP state to RTS %s\n",
70935c090eaSMatan Azrad 				strerror(errno));
71035c090eaSMatan Azrad 			rte_errno = errno;
71135c090eaSMatan Azrad 			return ret;
71235c090eaSMatan Azrad 		}
7132d77cb61SMatan Azrad 	}
7142d77cb61SMatan Azrad 	return 0;
7152d77cb61SMatan Azrad }
7162d77cb61SMatan Azrad 
7172d77cb61SMatan Azrad /**
7182d77cb61SMatan Azrad  * Modify a Verbs queue state.
7192d77cb61SMatan Azrad  *
7202d77cb61SMatan Azrad  * @param dev
7212d77cb61SMatan Azrad  *   Pointer to Ethernet device.
7222d77cb61SMatan Azrad  * @param sm
7232d77cb61SMatan Azrad  *   State modify request parameters.
7242d77cb61SMatan Azrad  *
7252d77cb61SMatan Azrad  * @return
7262d77cb61SMatan Azrad  *   0 in case of success else non-zero value.
7272d77cb61SMatan Azrad  */
7282d77cb61SMatan Azrad static int
7292d77cb61SMatan Azrad mlx5_queue_state_modify(struct rte_eth_dev *dev,
7302d77cb61SMatan Azrad 			struct mlx5_mp_arg_queue_state_modify *sm)
7312d77cb61SMatan Azrad {
7322d77cb61SMatan Azrad 	int ret = 0;
7332d77cb61SMatan Azrad 
7342d77cb61SMatan Azrad 	switch (rte_eal_process_type()) {
7352d77cb61SMatan Azrad 	case RTE_PROC_PRIMARY:
7362d77cb61SMatan Azrad 		ret = mlx5_queue_state_modify_primary(dev, sm);
7372d77cb61SMatan Azrad 		break;
7382d77cb61SMatan Azrad 	case RTE_PROC_SECONDARY:
7392d77cb61SMatan Azrad 		ret = mlx5_mp_req_queue_state_modify(dev, sm);
7402d77cb61SMatan Azrad 		break;
7412d77cb61SMatan Azrad 	default:
7422d77cb61SMatan Azrad 		break;
7432d77cb61SMatan Azrad 	}
7442d77cb61SMatan Azrad 	return ret;
7452d77cb61SMatan Azrad }
7462d77cb61SMatan Azrad 
7472d77cb61SMatan Azrad /**
74888c07335SMatan Azrad  * Handle a Rx error.
74988c07335SMatan Azrad  * The function inserts the RQ state to reset when the first error CQE is
75088c07335SMatan Azrad  * shown, then drains the CQ by the caller function loop. When the CQ is empty,
75188c07335SMatan Azrad  * it moves the RQ state to ready and initializes the RQ.
75288c07335SMatan Azrad  * Next CQE identification and error counting are in the caller responsibility.
75388c07335SMatan Azrad  *
75488c07335SMatan Azrad  * @param[in] rxq
75588c07335SMatan Azrad  *   Pointer to RX queue structure.
75688c07335SMatan Azrad  * @param[in] mbuf_prepare
75788c07335SMatan Azrad  *   Whether to prepare mbufs for the RQ.
75888c07335SMatan Azrad  *
75988c07335SMatan Azrad  * @return
76088c07335SMatan Azrad  *   -1 in case of recovery error, otherwise the CQE status.
76188c07335SMatan Azrad  */
76288c07335SMatan Azrad int
76388c07335SMatan Azrad mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t mbuf_prepare)
76488c07335SMatan Azrad {
76588c07335SMatan Azrad 	const uint16_t cqe_n = 1 << rxq->cqe_n;
76688c07335SMatan Azrad 	const uint16_t cqe_mask = cqe_n - 1;
76788c07335SMatan Azrad 	const unsigned int wqe_n = 1 << rxq->elts_n;
76888c07335SMatan Azrad 	struct mlx5_rxq_ctrl *rxq_ctrl =
76988c07335SMatan Azrad 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
77088c07335SMatan Azrad 	union {
77188c07335SMatan Azrad 		volatile struct mlx5_cqe *cqe;
77288c07335SMatan Azrad 		volatile struct mlx5_err_cqe *err_cqe;
77388c07335SMatan Azrad 	} u = {
77488c07335SMatan Azrad 		.cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask],
77588c07335SMatan Azrad 	};
7762d77cb61SMatan Azrad 	struct mlx5_mp_arg_queue_state_modify sm;
77788c07335SMatan Azrad 	int ret;
77888c07335SMatan Azrad 
77988c07335SMatan Azrad 	switch (rxq->err_state) {
78088c07335SMatan Azrad 	case MLX5_RXQ_ERR_STATE_NO_ERROR:
78188c07335SMatan Azrad 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET;
78288c07335SMatan Azrad 		/* Fall-through */
78388c07335SMatan Azrad 	case MLX5_RXQ_ERR_STATE_NEED_RESET:
7842d77cb61SMatan Azrad 		sm.is_wq = 1;
7852d77cb61SMatan Azrad 		sm.queue_id = rxq->idx;
7862d77cb61SMatan Azrad 		sm.state = IBV_WQS_RESET;
7872d77cb61SMatan Azrad 		if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv), &sm))
78888c07335SMatan Azrad 			return -1;
78988c07335SMatan Azrad 		if (rxq_ctrl->dump_file_n <
79088c07335SMatan Azrad 		    rxq_ctrl->priv->config.max_dump_files_num) {
79188c07335SMatan Azrad 			MKSTR(err_str, "Unexpected CQE error syndrome "
79288c07335SMatan Azrad 			      "0x%02x CQN = %u RQN = %u wqe_counter = %u"
79388c07335SMatan Azrad 			      " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome,
7942d77cb61SMatan Azrad 			      rxq->cqn, rxq_ctrl->wqn,
79588c07335SMatan Azrad 			      rte_be_to_cpu_16(u.err_cqe->wqe_counter),
79688c07335SMatan Azrad 			      rxq->rq_ci << rxq->sges_n, rxq->cq_ci);
79788c07335SMatan Azrad 			MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u",
79888c07335SMatan Azrad 			      rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc());
79988c07335SMatan Azrad 			mlx5_dump_debug_information(name, NULL, err_str, 0);
80088c07335SMatan Azrad 			mlx5_dump_debug_information(name, "MLX5 Error CQ:",
80188c07335SMatan Azrad 						    (const void *)((uintptr_t)
80288c07335SMatan Azrad 								    rxq->cqes),
80388c07335SMatan Azrad 						    sizeof(*u.cqe) * cqe_n);
80488c07335SMatan Azrad 			mlx5_dump_debug_information(name, "MLX5 Error RQ:",
80588c07335SMatan Azrad 						    (const void *)((uintptr_t)
80688c07335SMatan Azrad 								    rxq->wqes),
80788c07335SMatan Azrad 						    16 * wqe_n);
80888c07335SMatan Azrad 			rxq_ctrl->dump_file_n++;
80988c07335SMatan Azrad 		}
81088c07335SMatan Azrad 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY;
81188c07335SMatan Azrad 		/* Fall-through */
81288c07335SMatan Azrad 	case MLX5_RXQ_ERR_STATE_NEED_READY:
81388c07335SMatan Azrad 		ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci);
81488c07335SMatan Azrad 		if (ret == MLX5_CQE_STATUS_HW_OWN) {
81588c07335SMatan Azrad 			rte_cio_wmb();
81688c07335SMatan Azrad 			*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
81788c07335SMatan Azrad 			rte_cio_wmb();
81888c07335SMatan Azrad 			/*
81988c07335SMatan Azrad 			 * The RQ consumer index must be zeroed while moving
82088c07335SMatan Azrad 			 * from RESET state to RDY state.
82188c07335SMatan Azrad 			 */
82288c07335SMatan Azrad 			*rxq->rq_db = rte_cpu_to_be_32(0);
82388c07335SMatan Azrad 			rte_cio_wmb();
8242d77cb61SMatan Azrad 			sm.is_wq = 1;
8252d77cb61SMatan Azrad 			sm.queue_id = rxq->idx;
8262d77cb61SMatan Azrad 			sm.state = IBV_WQS_RDY;
8272d77cb61SMatan Azrad 			if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv),
8282d77cb61SMatan Azrad 						    &sm))
82988c07335SMatan Azrad 				return -1;
83088c07335SMatan Azrad 			if (mbuf_prepare) {
83188c07335SMatan Azrad 				const uint16_t q_mask = wqe_n - 1;
83288c07335SMatan Azrad 				uint16_t elt_idx;
83388c07335SMatan Azrad 				struct rte_mbuf **elt;
83488c07335SMatan Azrad 				int i;
83588c07335SMatan Azrad 				unsigned int n = wqe_n - (rxq->rq_ci -
83688c07335SMatan Azrad 							  rxq->rq_pi);
83788c07335SMatan Azrad 
83888c07335SMatan Azrad 				for (i = 0; i < (int)n; ++i) {
83988c07335SMatan Azrad 					elt_idx = (rxq->rq_ci + i) & q_mask;
84088c07335SMatan Azrad 					elt = &(*rxq->elts)[elt_idx];
84188c07335SMatan Azrad 					*elt = rte_mbuf_raw_alloc(rxq->mp);
84288c07335SMatan Azrad 					if (!*elt) {
84388c07335SMatan Azrad 						for (i--; i >= 0; --i) {
84488c07335SMatan Azrad 							elt_idx = (rxq->rq_ci +
84588c07335SMatan Azrad 								   i) & q_mask;
84688c07335SMatan Azrad 							elt = &(*rxq->elts)
84788c07335SMatan Azrad 								[elt_idx];
84888c07335SMatan Azrad 							rte_pktmbuf_free_seg
84988c07335SMatan Azrad 								(*elt);
85088c07335SMatan Azrad 						}
85188c07335SMatan Azrad 						return -1;
85288c07335SMatan Azrad 					}
85388c07335SMatan Azrad 				}
85488c07335SMatan Azrad 			}
85588c07335SMatan Azrad 			mlx5_rxq_initialize(rxq);
85688c07335SMatan Azrad 			rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
85788c07335SMatan Azrad 		}
85888c07335SMatan Azrad 		return ret;
85988c07335SMatan Azrad 	default:
86088c07335SMatan Azrad 		return -1;
86188c07335SMatan Azrad 	}
86288c07335SMatan Azrad }
86388c07335SMatan Azrad 
86488c07335SMatan Azrad /**
86599c12dccSNélio Laranjeiro  * Get size of the next packet for a given CQE. For compressed CQEs, the
86699c12dccSNélio Laranjeiro  * consumer index is updated only once all packets of the current one have
86799c12dccSNélio Laranjeiro  * been processed.
86899c12dccSNélio Laranjeiro  *
86999c12dccSNélio Laranjeiro  * @param rxq
87099c12dccSNélio Laranjeiro  *   Pointer to RX queue.
87199c12dccSNélio Laranjeiro  * @param cqe
87299c12dccSNélio Laranjeiro  *   CQE to process.
8732e633f1fSYongseok Koh  * @param[out] mcqe
8742e633f1fSYongseok Koh  *   Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
8752e633f1fSYongseok Koh  *   written.
87699c12dccSNélio Laranjeiro  *
87799c12dccSNélio Laranjeiro  * @return
87888c07335SMatan Azrad  *   0 in case of empty CQE, otherwise the packet size in bytes.
87999c12dccSNélio Laranjeiro  */
88099c12dccSNélio Laranjeiro static inline int
88178142aacSNélio Laranjeiro mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
8822e633f1fSYongseok Koh 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe)
88399c12dccSNélio Laranjeiro {
88499c12dccSNélio Laranjeiro 	struct rxq_zip *zip = &rxq->zip;
88599c12dccSNélio Laranjeiro 	uint16_t cqe_n = cqe_cnt + 1;
88688c07335SMatan Azrad 	int len;
887d2e842d0SYongseok Koh 	uint16_t idx, end;
88899c12dccSNélio Laranjeiro 
88988c07335SMatan Azrad 	do {
89088c07335SMatan Azrad 		len = 0;
89199c12dccSNélio Laranjeiro 		/* Process compressed data in the CQE and mini arrays. */
89299c12dccSNélio Laranjeiro 		if (zip->ai) {
89399c12dccSNélio Laranjeiro 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
89499c12dccSNélio Laranjeiro 				(volatile struct mlx5_mini_cqe8 (*)[8])
89588c07335SMatan Azrad 				(uintptr_t)(&(*rxq->cqes)[zip->ca &
89688c07335SMatan Azrad 							  cqe_cnt].pkt_info);
89799c12dccSNélio Laranjeiro 
8986b30a6a8SShachar Beiser 			len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt);
8992e633f1fSYongseok Koh 			*mcqe = &(*mc)[zip->ai & 7];
90099c12dccSNélio Laranjeiro 			if ((++zip->ai & 7) == 0) {
901d2e842d0SYongseok Koh 				/* Invalidate consumed CQEs */
902d2e842d0SYongseok Koh 				idx = zip->ca;
903d2e842d0SYongseok Koh 				end = zip->na;
904d2e842d0SYongseok Koh 				while (idx != end) {
905d2e842d0SYongseok Koh 					(*rxq->cqes)[idx & cqe_cnt].op_own =
906d2e842d0SYongseok Koh 						MLX5_CQE_INVALIDATE;
907d2e842d0SYongseok Koh 					++idx;
908d2e842d0SYongseok Koh 				}
90999c12dccSNélio Laranjeiro 				/*
91088c07335SMatan Azrad 				 * Increment consumer index to skip the number
91188c07335SMatan Azrad 				 * of CQEs consumed. Hardware leaves holes in
91288c07335SMatan Azrad 				 * the CQ ring for software use.
91399c12dccSNélio Laranjeiro 				 */
91499c12dccSNélio Laranjeiro 				zip->ca = zip->na;
91599c12dccSNélio Laranjeiro 				zip->na += 8;
91699c12dccSNélio Laranjeiro 			}
91799c12dccSNélio Laranjeiro 			if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
918d2e842d0SYongseok Koh 				/* Invalidate the rest */
919d2e842d0SYongseok Koh 				idx = zip->ca;
920d2e842d0SYongseok Koh 				end = zip->cq_ci;
92199c12dccSNélio Laranjeiro 
92299c12dccSNélio Laranjeiro 				while (idx != end) {
92397267b8eSNelio Laranjeiro 					(*rxq->cqes)[idx & cqe_cnt].op_own =
92499c12dccSNélio Laranjeiro 						MLX5_CQE_INVALIDATE;
92599c12dccSNélio Laranjeiro 					++idx;
92699c12dccSNélio Laranjeiro 				}
92799c12dccSNélio Laranjeiro 				rxq->cq_ci = zip->cq_ci;
92899c12dccSNélio Laranjeiro 				zip->ai = 0;
92999c12dccSNélio Laranjeiro 			}
93088c07335SMatan Azrad 		/*
93188c07335SMatan Azrad 		 * No compressed data, get next CQE and verify if it is
93288c07335SMatan Azrad 		 * compressed.
93388c07335SMatan Azrad 		 */
93499c12dccSNélio Laranjeiro 		} else {
93599c12dccSNélio Laranjeiro 			int ret;
93699c12dccSNélio Laranjeiro 			int8_t op_own;
93799c12dccSNélio Laranjeiro 
93897267b8eSNelio Laranjeiro 			ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
93988c07335SMatan Azrad 			if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
94088c07335SMatan Azrad 				if (unlikely(ret == MLX5_CQE_STATUS_ERR ||
94188c07335SMatan Azrad 					     rxq->err_state)) {
94288c07335SMatan Azrad 					ret = mlx5_rx_err_handle(rxq, 0);
94388c07335SMatan Azrad 					if (ret == MLX5_CQE_STATUS_HW_OWN ||
94488c07335SMatan Azrad 					    ret == -1)
94599c12dccSNélio Laranjeiro 						return 0;
94688c07335SMatan Azrad 				} else {
94788c07335SMatan Azrad 					return 0;
94888c07335SMatan Azrad 				}
94988c07335SMatan Azrad 			}
95099c12dccSNélio Laranjeiro 			++rxq->cq_ci;
95199c12dccSNélio Laranjeiro 			op_own = cqe->op_own;
95299c12dccSNélio Laranjeiro 			if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
95399c12dccSNélio Laranjeiro 				volatile struct mlx5_mini_cqe8 (*mc)[8] =
95499c12dccSNélio Laranjeiro 					(volatile struct mlx5_mini_cqe8 (*)[8])
95588c07335SMatan Azrad 					(uintptr_t)(&(*rxq->cqes)
95688c07335SMatan Azrad 						[rxq->cq_ci &
9574aff4bcbSYongseok Koh 						 cqe_cnt].pkt_info);
95899c12dccSNélio Laranjeiro 
95999c12dccSNélio Laranjeiro 				/* Fix endianness. */
9606b30a6a8SShachar Beiser 				zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
96199c12dccSNélio Laranjeiro 				/*
96288c07335SMatan Azrad 				 * Current mini array position is the one
96388c07335SMatan Azrad 				 * returned by check_cqe64().
96499c12dccSNélio Laranjeiro 				 *
96588c07335SMatan Azrad 				 * If completion comprises several mini arrays,
96688c07335SMatan Azrad 				 * as a special case the second one is located
96788c07335SMatan Azrad 				 * 7 CQEs after the initial CQE instead of 8
96888c07335SMatan Azrad 				 * for subsequent ones.
96999c12dccSNélio Laranjeiro 				 */
970d2e842d0SYongseok Koh 				zip->ca = rxq->cq_ci;
97199c12dccSNélio Laranjeiro 				zip->na = zip->ca + 7;
97299c12dccSNélio Laranjeiro 				/* Compute the next non compressed CQE. */
97399c12dccSNélio Laranjeiro 				--rxq->cq_ci;
97499c12dccSNélio Laranjeiro 				zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
97599c12dccSNélio Laranjeiro 				/* Get packet size to return. */
9766b30a6a8SShachar Beiser 				len = rte_be_to_cpu_32((*mc)[0].byte_cnt);
9772e633f1fSYongseok Koh 				*mcqe = &(*mc)[0];
97899c12dccSNélio Laranjeiro 				zip->ai = 1;
97988c07335SMatan Azrad 				/* Prefetch all to be invalidated */
980d2e842d0SYongseok Koh 				idx = zip->ca;
981d2e842d0SYongseok Koh 				end = zip->cq_ci;
982d2e842d0SYongseok Koh 				while (idx != end) {
98388c07335SMatan Azrad 					rte_prefetch0(&(*rxq->cqes)[(idx) &
98488c07335SMatan Azrad 								    cqe_cnt]);
985d2e842d0SYongseok Koh 					++idx;
986d2e842d0SYongseok Koh 				}
98799c12dccSNélio Laranjeiro 			} else {
9886b30a6a8SShachar Beiser 				len = rte_be_to_cpu_32(cqe->byte_cnt);
98999c12dccSNélio Laranjeiro 			}
99099c12dccSNélio Laranjeiro 		}
99188c07335SMatan Azrad 		if (unlikely(rxq->err_state)) {
99288c07335SMatan Azrad 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
99388c07335SMatan Azrad 			++rxq->stats.idropped;
99488c07335SMatan Azrad 		} else {
99599c12dccSNélio Laranjeiro 			return len;
99699c12dccSNélio Laranjeiro 		}
99788c07335SMatan Azrad 	} while (1);
99888c07335SMatan Azrad }
99999c12dccSNélio Laranjeiro 
100099c12dccSNélio Laranjeiro /**
100167fa62bcSAdrien Mazarguil  * Translate RX completion flags to offload flags.
100267fa62bcSAdrien Mazarguil  *
10036218063bSNélio Laranjeiro  * @param[in] cqe
10046218063bSNélio Laranjeiro  *   Pointer to CQE.
100567fa62bcSAdrien Mazarguil  *
100667fa62bcSAdrien Mazarguil  * @return
100767fa62bcSAdrien Mazarguil  *   Offload flags (ol_flags) for struct rte_mbuf.
100867fa62bcSAdrien Mazarguil  */
100967fa62bcSAdrien Mazarguil static inline uint32_t
10106ba07449SXueming Li rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
101167fa62bcSAdrien Mazarguil {
101267fa62bcSAdrien Mazarguil 	uint32_t ol_flags = 0;
10136b30a6a8SShachar Beiser 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
101467fa62bcSAdrien Mazarguil 
10150603df73SNélio Laranjeiro 	ol_flags =
10160603df73SNélio Laranjeiro 		TRANSPOSE(flags,
10170603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L3_HDR_VALID,
10180603df73SNélio Laranjeiro 			  PKT_RX_IP_CKSUM_GOOD) |
10190603df73SNélio Laranjeiro 		TRANSPOSE(flags,
10200603df73SNélio Laranjeiro 			  MLX5_CQE_RX_L4_HDR_VALID,
102183e9d9a3SNelio Laranjeiro 			  PKT_RX_L4_CKSUM_GOOD);
102267fa62bcSAdrien Mazarguil 	return ol_flags;
102367fa62bcSAdrien Mazarguil }
102467fa62bcSAdrien Mazarguil 
102567fa62bcSAdrien Mazarguil /**
10263e1f82a1SYongseok Koh  * Fill in mbuf fields from RX completion flags.
10273e1f82a1SYongseok Koh  * Note that pkt->ol_flags should be initialized outside of this function.
10283e1f82a1SYongseok Koh  *
10293e1f82a1SYongseok Koh  * @param rxq
10303e1f82a1SYongseok Koh  *   Pointer to RX queue.
10313e1f82a1SYongseok Koh  * @param pkt
10323e1f82a1SYongseok Koh  *   mbuf to fill.
10333e1f82a1SYongseok Koh  * @param cqe
10343e1f82a1SYongseok Koh  *   CQE to process.
10353e1f82a1SYongseok Koh  * @param rss_hash_res
10363e1f82a1SYongseok Koh  *   Packet RSS Hash result.
10373e1f82a1SYongseok Koh  */
10383e1f82a1SYongseok Koh static inline void
10393e1f82a1SYongseok Koh rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
10403e1f82a1SYongseok Koh 	       volatile struct mlx5_cqe *cqe, uint32_t rss_hash_res)
10413e1f82a1SYongseok Koh {
10423e1f82a1SYongseok Koh 	/* Update packet information. */
10433e1f82a1SYongseok Koh 	pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe);
10443e1f82a1SYongseok Koh 	if (rss_hash_res && rxq->rss_hash) {
10453e1f82a1SYongseok Koh 		pkt->hash.rss = rss_hash_res;
10463e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_RSS_HASH;
10473e1f82a1SYongseok Koh 	}
10483e1f82a1SYongseok Koh 	if (rxq->mark && MLX5_FLOW_MARK_IS_VALID(cqe->sop_drop_qpn)) {
10493e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_FDIR;
10503e1f82a1SYongseok Koh 		if (cqe->sop_drop_qpn !=
10513e1f82a1SYongseok Koh 		    rte_cpu_to_be_32(MLX5_FLOW_MARK_DEFAULT)) {
10523e1f82a1SYongseok Koh 			uint32_t mark = cqe->sop_drop_qpn;
10533e1f82a1SYongseok Koh 
10543e1f82a1SYongseok Koh 			pkt->ol_flags |= PKT_RX_FDIR_ID;
10553e1f82a1SYongseok Koh 			pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
10563e1f82a1SYongseok Koh 		}
10573e1f82a1SYongseok Koh 	}
10583e1f82a1SYongseok Koh 	if (rxq->csum)
10593e1f82a1SYongseok Koh 		pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
10603e1f82a1SYongseok Koh 	if (rxq->vlan_strip &&
10613e1f82a1SYongseok Koh 	    (cqe->hdr_type_etc & rte_cpu_to_be_16(MLX5_CQE_VLAN_STRIPPED))) {
10623e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
10633e1f82a1SYongseok Koh 		pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
10643e1f82a1SYongseok Koh 	}
10653e1f82a1SYongseok Koh 	if (rxq->hw_timestamp) {
10663e1f82a1SYongseok Koh 		pkt->timestamp = rte_be_to_cpu_64(cqe->timestamp);
10673e1f82a1SYongseok Koh 		pkt->ol_flags |= PKT_RX_TIMESTAMP;
10683e1f82a1SYongseok Koh 	}
10693e1f82a1SYongseok Koh }
10703e1f82a1SYongseok Koh 
10713e1f82a1SYongseok Koh /**
10722e22920bSAdrien Mazarguil  * DPDK callback for RX.
10732e22920bSAdrien Mazarguil  *
10742e22920bSAdrien Mazarguil  * @param dpdk_rxq
10752e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
10762e22920bSAdrien Mazarguil  * @param[out] pkts
10772e22920bSAdrien Mazarguil  *   Array to store received packets.
10782e22920bSAdrien Mazarguil  * @param pkts_n
10792e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
10802e22920bSAdrien Mazarguil  *
10812e22920bSAdrien Mazarguil  * @return
10822e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
10832e22920bSAdrien Mazarguil  */
10842e22920bSAdrien Mazarguil uint16_t
10852e22920bSAdrien Mazarguil mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
10862e22920bSAdrien Mazarguil {
108778142aacSNélio Laranjeiro 	struct mlx5_rxq_data *rxq = dpdk_rxq;
1088b4b12e55SNélio Laranjeiro 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
1089e2f116eeSNélio Laranjeiro 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
10909964b965SNélio Laranjeiro 	const unsigned int sges_n = rxq->sges_n;
10919964b965SNélio Laranjeiro 	struct rte_mbuf *pkt = NULL;
10929964b965SNélio Laranjeiro 	struct rte_mbuf *seg = NULL;
109397267b8eSNelio Laranjeiro 	volatile struct mlx5_cqe *cqe =
109497267b8eSNelio Laranjeiro 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
10959964b965SNélio Laranjeiro 	unsigned int i = 0;
10969964b965SNélio Laranjeiro 	unsigned int rq_ci = rxq->rq_ci << sges_n;
10974e66a6feSNelio Laranjeiro 	int len = 0; /* keep its value across iterations. */
10982e22920bSAdrien Mazarguil 
10999964b965SNélio Laranjeiro 	while (pkts_n) {
11009964b965SNélio Laranjeiro 		unsigned int idx = rq_ci & wqe_cnt;
11017d6bf6b8SYongseok Koh 		volatile struct mlx5_wqe_data_seg *wqe =
11027d6bf6b8SYongseok Koh 			&((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
11039964b965SNélio Laranjeiro 		struct rte_mbuf *rep = (*rxq->elts)[idx];
11042e633f1fSYongseok Koh 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
11052e633f1fSYongseok Koh 		uint32_t rss_hash_res;
11069964b965SNélio Laranjeiro 
11079964b965SNélio Laranjeiro 		if (pkt)
11089964b965SNélio Laranjeiro 			NEXT(seg) = rep;
11099964b965SNélio Laranjeiro 		seg = rep;
11109964b965SNélio Laranjeiro 		rte_prefetch0(seg);
11116218063bSNélio Laranjeiro 		rte_prefetch0(cqe);
11129964b965SNélio Laranjeiro 		rte_prefetch0(wqe);
1113fbfd9955SOlivier Matz 		rep = rte_mbuf_raw_alloc(rxq->mp);
11142e22920bSAdrien Mazarguil 		if (unlikely(rep == NULL)) {
111515a756b6SSagi Grimberg 			++rxq->stats.rx_nombuf;
111615a756b6SSagi Grimberg 			if (!pkt) {
111715a756b6SSagi Grimberg 				/*
111815a756b6SSagi Grimberg 				 * no buffers before we even started,
111915a756b6SSagi Grimberg 				 * bail out silently.
112015a756b6SSagi Grimberg 				 */
112115a756b6SSagi Grimberg 				break;
112215a756b6SSagi Grimberg 			}
1123a1bdb71aSNélio Laranjeiro 			while (pkt != seg) {
1124a1bdb71aSNélio Laranjeiro 				assert(pkt != (*rxq->elts)[idx]);
1125fe5fe382SNélio Laranjeiro 				rep = NEXT(pkt);
11268f094a9aSOlivier Matz 				NEXT(pkt) = NULL;
11278f094a9aSOlivier Matz 				NB_SEGS(pkt) = 1;
11281f88c0a2SOlivier Matz 				rte_mbuf_raw_free(pkt);
1129fe5fe382SNélio Laranjeiro 				pkt = rep;
11309964b965SNélio Laranjeiro 			}
11316218063bSNélio Laranjeiro 			break;
11322e22920bSAdrien Mazarguil 		}
11339964b965SNélio Laranjeiro 		if (!pkt) {
113497267b8eSNelio Laranjeiro 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
11352e633f1fSYongseok Koh 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe);
1136ecf60761SNélio Laranjeiro 			if (!len) {
11371f88c0a2SOlivier Matz 				rte_mbuf_raw_free(rep);
11386218063bSNélio Laranjeiro 				break;
11396218063bSNélio Laranjeiro 			}
11409964b965SNélio Laranjeiro 			pkt = seg;
11419964b965SNélio Laranjeiro 			assert(len >= (rxq->crc_present << 2));
11420ac64846SMaxime Leroy 			pkt->ol_flags = 0;
11432e633f1fSYongseok Koh 			/* If compressed, take hash result from mini-CQE. */
11442e633f1fSYongseok Koh 			rss_hash_res = rte_be_to_cpu_32(mcqe == NULL ?
11452e633f1fSYongseok Koh 							cqe->rx_hash_res :
11462e633f1fSYongseok Koh 							mcqe->rx_hash_result);
11473e1f82a1SYongseok Koh 			rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
11486218063bSNélio Laranjeiro 			if (rxq->crc_present)
114935b2d13fSOlivier Matz 				len -= RTE_ETHER_CRC_LEN;
11506218063bSNélio Laranjeiro 			PKT_LEN(pkt) = len;
11519964b965SNélio Laranjeiro 		}
11529964b965SNélio Laranjeiro 		DATA_LEN(rep) = DATA_LEN(seg);
11539964b965SNélio Laranjeiro 		PKT_LEN(rep) = PKT_LEN(seg);
11549964b965SNélio Laranjeiro 		SET_DATA_OFF(rep, DATA_OFF(seg));
11559964b965SNélio Laranjeiro 		PORT(rep) = PORT(seg);
11569964b965SNélio Laranjeiro 		(*rxq->elts)[idx] = rep;
11579964b965SNélio Laranjeiro 		/*
11589964b965SNélio Laranjeiro 		 * Fill NIC descriptor with the new buffer.  The lkey and size
11599964b965SNélio Laranjeiro 		 * of the buffers are already known, only the buffer address
11609964b965SNélio Laranjeiro 		 * changes.
11619964b965SNélio Laranjeiro 		 */
11626b30a6a8SShachar Beiser 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
1163974f1e7eSYongseok Koh 		/* If there's only one MR, no need to replace LKey in WQE. */
1164974f1e7eSYongseok Koh 		if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1165974f1e7eSYongseok Koh 			wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
11669964b965SNélio Laranjeiro 		if (len > DATA_LEN(seg)) {
11679964b965SNélio Laranjeiro 			len -= DATA_LEN(seg);
11689964b965SNélio Laranjeiro 			++NB_SEGS(pkt);
11699964b965SNélio Laranjeiro 			++rq_ci;
11709964b965SNélio Laranjeiro 			continue;
11719964b965SNélio Laranjeiro 		}
11729964b965SNélio Laranjeiro 		DATA_LEN(seg) = len;
117387011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
117487011737SAdrien Mazarguil 		/* Increment bytes counter. */
11759964b965SNélio Laranjeiro 		rxq->stats.ibytes += PKT_LEN(pkt);
117687011737SAdrien Mazarguil #endif
11776218063bSNélio Laranjeiro 		/* Return packet. */
11786218063bSNélio Laranjeiro 		*(pkts++) = pkt;
11799964b965SNélio Laranjeiro 		pkt = NULL;
11809964b965SNélio Laranjeiro 		--pkts_n;
11819964b965SNélio Laranjeiro 		++i;
11829964b965SNélio Laranjeiro 		/* Align consumer index to the next stride. */
11839964b965SNélio Laranjeiro 		rq_ci >>= sges_n;
11846218063bSNélio Laranjeiro 		++rq_ci;
11859964b965SNélio Laranjeiro 		rq_ci <<= sges_n;
11862e22920bSAdrien Mazarguil 	}
11879964b965SNélio Laranjeiro 	if (unlikely((i == 0) && ((rq_ci >> sges_n) == rxq->rq_ci)))
11882e22920bSAdrien Mazarguil 		return 0;
11896218063bSNélio Laranjeiro 	/* Update the consumer index. */
11909964b965SNélio Laranjeiro 	rxq->rq_ci = rq_ci >> sges_n;
11914fe7f662SYongseok Koh 	rte_cio_wmb();
11926b30a6a8SShachar Beiser 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
11934fe7f662SYongseok Koh 	rte_cio_wmb();
11946b30a6a8SShachar Beiser 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
119587011737SAdrien Mazarguil #ifdef MLX5_PMD_SOFT_COUNTERS
119687011737SAdrien Mazarguil 	/* Increment packets counter. */
11979964b965SNélio Laranjeiro 	rxq->stats.ipackets += i;
119887011737SAdrien Mazarguil #endif
11999964b965SNélio Laranjeiro 	return i;
12002e22920bSAdrien Mazarguil }
12012e22920bSAdrien Mazarguil 
12027d6bf6b8SYongseok Koh void
12037d6bf6b8SYongseok Koh mlx5_mprq_buf_free_cb(void *addr __rte_unused, void *opaque)
12047d6bf6b8SYongseok Koh {
12057d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *buf = opaque;
12067d6bf6b8SYongseok Koh 
12077d6bf6b8SYongseok Koh 	if (rte_atomic16_read(&buf->refcnt) == 1) {
12087d6bf6b8SYongseok Koh 		rte_mempool_put(buf->mp, buf);
12097d6bf6b8SYongseok Koh 	} else if (rte_atomic16_add_return(&buf->refcnt, -1) == 0) {
12107d6bf6b8SYongseok Koh 		rte_atomic16_set(&buf->refcnt, 1);
12117d6bf6b8SYongseok Koh 		rte_mempool_put(buf->mp, buf);
12127d6bf6b8SYongseok Koh 	}
12137d6bf6b8SYongseok Koh }
12147d6bf6b8SYongseok Koh 
12157d6bf6b8SYongseok Koh void
12167d6bf6b8SYongseok Koh mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
12177d6bf6b8SYongseok Koh {
12187d6bf6b8SYongseok Koh 	mlx5_mprq_buf_free_cb(NULL, buf);
12197d6bf6b8SYongseok Koh }
12207d6bf6b8SYongseok Koh 
12217d6bf6b8SYongseok Koh static inline void
12227d6bf6b8SYongseok Koh mprq_buf_replace(struct mlx5_rxq_data *rxq, uint16_t rq_idx)
12237d6bf6b8SYongseok Koh {
12247d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *rep = rxq->mprq_repl;
12257d6bf6b8SYongseok Koh 	volatile struct mlx5_wqe_data_seg *wqe =
12267d6bf6b8SYongseok Koh 		&((volatile struct mlx5_wqe_mprq *)rxq->wqes)[rq_idx].dseg;
12277d6bf6b8SYongseok Koh 	void *addr;
12287d6bf6b8SYongseok Koh 
12297d6bf6b8SYongseok Koh 	assert(rep != NULL);
12307d6bf6b8SYongseok Koh 	/* Replace MPRQ buf. */
12317d6bf6b8SYongseok Koh 	(*rxq->mprq_bufs)[rq_idx] = rep;
12327d6bf6b8SYongseok Koh 	/* Replace WQE. */
12337d6bf6b8SYongseok Koh 	addr = mlx5_mprq_buf_addr(rep);
12347d6bf6b8SYongseok Koh 	wqe->addr = rte_cpu_to_be_64((uintptr_t)addr);
12357d6bf6b8SYongseok Koh 	/* If there's only one MR, no need to replace LKey in WQE. */
12367d6bf6b8SYongseok Koh 	if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
12377d6bf6b8SYongseok Koh 		wqe->lkey = mlx5_rx_addr2mr(rxq, (uintptr_t)addr);
12387d6bf6b8SYongseok Koh 	/* Stash a mbuf for next replacement. */
12397d6bf6b8SYongseok Koh 	if (likely(!rte_mempool_get(rxq->mprq_mp, (void **)&rep)))
12407d6bf6b8SYongseok Koh 		rxq->mprq_repl = rep;
12417d6bf6b8SYongseok Koh 	else
12427d6bf6b8SYongseok Koh 		rxq->mprq_repl = NULL;
12437d6bf6b8SYongseok Koh }
12447d6bf6b8SYongseok Koh 
12457d6bf6b8SYongseok Koh /**
12467d6bf6b8SYongseok Koh  * DPDK callback for RX with Multi-Packet RQ support.
12477d6bf6b8SYongseok Koh  *
12487d6bf6b8SYongseok Koh  * @param dpdk_rxq
12497d6bf6b8SYongseok Koh  *   Generic pointer to RX queue structure.
12507d6bf6b8SYongseok Koh  * @param[out] pkts
12517d6bf6b8SYongseok Koh  *   Array to store received packets.
12527d6bf6b8SYongseok Koh  * @param pkts_n
12537d6bf6b8SYongseok Koh  *   Maximum number of packets in array.
12547d6bf6b8SYongseok Koh  *
12557d6bf6b8SYongseok Koh  * @return
12567d6bf6b8SYongseok Koh  *   Number of packets successfully received (<= pkts_n).
12577d6bf6b8SYongseok Koh  */
12587d6bf6b8SYongseok Koh uint16_t
12597d6bf6b8SYongseok Koh mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
12607d6bf6b8SYongseok Koh {
12617d6bf6b8SYongseok Koh 	struct mlx5_rxq_data *rxq = dpdk_rxq;
12627d6bf6b8SYongseok Koh 	const unsigned int strd_n = 1 << rxq->strd_num_n;
12637d6bf6b8SYongseok Koh 	const unsigned int strd_sz = 1 << rxq->strd_sz_n;
12647d6bf6b8SYongseok Koh 	const unsigned int strd_shift =
12657d6bf6b8SYongseok Koh 		MLX5_MPRQ_STRIDE_SHIFT_BYTE * rxq->strd_shift_en;
12667d6bf6b8SYongseok Koh 	const unsigned int cq_mask = (1 << rxq->cqe_n) - 1;
12677d6bf6b8SYongseok Koh 	const unsigned int wq_mask = (1 << rxq->elts_n) - 1;
12687d6bf6b8SYongseok Koh 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
12697d6bf6b8SYongseok Koh 	unsigned int i = 0;
12703afdf157SXueming Li 	uint32_t rq_ci = rxq->rq_ci;
12711787eb7bSYongseok Koh 	uint16_t consumed_strd = rxq->consumed_strd;
12727d6bf6b8SYongseok Koh 	struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
12737d6bf6b8SYongseok Koh 
12747d6bf6b8SYongseok Koh 	while (i < pkts_n) {
12757d6bf6b8SYongseok Koh 		struct rte_mbuf *pkt;
12767d6bf6b8SYongseok Koh 		void *addr;
12777d6bf6b8SYongseok Koh 		int ret;
12787d6bf6b8SYongseok Koh 		unsigned int len;
12791787eb7bSYongseok Koh 		uint16_t strd_cnt;
12801787eb7bSYongseok Koh 		uint16_t strd_idx;
12817d6bf6b8SYongseok Koh 		uint32_t offset;
12827d6bf6b8SYongseok Koh 		uint32_t byte_cnt;
12832e633f1fSYongseok Koh 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
12841787eb7bSYongseok Koh 		uint32_t rss_hash_res = 0;
12857d6bf6b8SYongseok Koh 
12861787eb7bSYongseok Koh 		if (consumed_strd == strd_n) {
12877d6bf6b8SYongseok Koh 			/* Replace WQE only if the buffer is still in use. */
12887d6bf6b8SYongseok Koh 			if (rte_atomic16_read(&buf->refcnt) > 1) {
12897d6bf6b8SYongseok Koh 				mprq_buf_replace(rxq, rq_ci & wq_mask);
12907d6bf6b8SYongseok Koh 				/* Release the old buffer. */
12917d6bf6b8SYongseok Koh 				mlx5_mprq_buf_free(buf);
12927d6bf6b8SYongseok Koh 			} else if (unlikely(rxq->mprq_repl == NULL)) {
12937d6bf6b8SYongseok Koh 				struct mlx5_mprq_buf *rep;
12947d6bf6b8SYongseok Koh 
12957d6bf6b8SYongseok Koh 				/*
12967d6bf6b8SYongseok Koh 				 * Currently, the MPRQ mempool is out of buffer
12977d6bf6b8SYongseok Koh 				 * and doing memcpy regardless of the size of Rx
12987d6bf6b8SYongseok Koh 				 * packet. Retry allocation to get back to
12997d6bf6b8SYongseok Koh 				 * normal.
13007d6bf6b8SYongseok Koh 				 */
13017d6bf6b8SYongseok Koh 				if (!rte_mempool_get(rxq->mprq_mp,
13027d6bf6b8SYongseok Koh 						     (void **)&rep))
13037d6bf6b8SYongseok Koh 					rxq->mprq_repl = rep;
13047d6bf6b8SYongseok Koh 			}
13057d6bf6b8SYongseok Koh 			/* Advance to the next WQE. */
13061787eb7bSYongseok Koh 			consumed_strd = 0;
13077d6bf6b8SYongseok Koh 			++rq_ci;
13087d6bf6b8SYongseok Koh 			buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
13097d6bf6b8SYongseok Koh 		}
13107d6bf6b8SYongseok Koh 		cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
13112e633f1fSYongseok Koh 		ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe);
13127d6bf6b8SYongseok Koh 		if (!ret)
13137d6bf6b8SYongseok Koh 			break;
13147d6bf6b8SYongseok Koh 		byte_cnt = ret;
13151787eb7bSYongseok Koh 		strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
13167d6bf6b8SYongseok Koh 			   MLX5_MPRQ_STRIDE_NUM_SHIFT;
13171787eb7bSYongseok Koh 		assert(strd_cnt);
13181787eb7bSYongseok Koh 		consumed_strd += strd_cnt;
13197d6bf6b8SYongseok Koh 		if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
13207d6bf6b8SYongseok Koh 			continue;
13211787eb7bSYongseok Koh 		if (mcqe == NULL) {
13221787eb7bSYongseok Koh 			rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
13231787eb7bSYongseok Koh 			strd_idx = rte_be_to_cpu_16(cqe->wqe_counter);
13241787eb7bSYongseok Koh 		} else {
13251787eb7bSYongseok Koh 			/* mini-CQE for MPRQ doesn't have hash result. */
13261787eb7bSYongseok Koh 			strd_idx = rte_be_to_cpu_16(mcqe->stride_idx);
13271787eb7bSYongseok Koh 		}
13281787eb7bSYongseok Koh 		assert(strd_idx < strd_n);
13291787eb7bSYongseok Koh 		assert(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & wq_mask));
13307d6bf6b8SYongseok Koh 		/*
13317d6bf6b8SYongseok Koh 		 * Currently configured to receive a packet per a stride. But if
13327d6bf6b8SYongseok Koh 		 * MTU is adjusted through kernel interface, device could
13337d6bf6b8SYongseok Koh 		 * consume multiple strides without raising an error. In this
13347d6bf6b8SYongseok Koh 		 * case, the packet should be dropped because it is bigger than
13357d6bf6b8SYongseok Koh 		 * the max_rx_pkt_len.
13367d6bf6b8SYongseok Koh 		 */
13371787eb7bSYongseok Koh 		if (unlikely(strd_cnt > 1)) {
13387d6bf6b8SYongseok Koh 			++rxq->stats.idropped;
13397d6bf6b8SYongseok Koh 			continue;
13407d6bf6b8SYongseok Koh 		}
13417d6bf6b8SYongseok Koh 		pkt = rte_pktmbuf_alloc(rxq->mp);
13427d6bf6b8SYongseok Koh 		if (unlikely(pkt == NULL)) {
13437d6bf6b8SYongseok Koh 			++rxq->stats.rx_nombuf;
13447d6bf6b8SYongseok Koh 			break;
13457d6bf6b8SYongseok Koh 		}
13467d6bf6b8SYongseok Koh 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
13477d6bf6b8SYongseok Koh 		assert((int)len >= (rxq->crc_present << 2));
13487d6bf6b8SYongseok Koh 		if (rxq->crc_present)
134935b2d13fSOlivier Matz 			len -= RTE_ETHER_CRC_LEN;
13501787eb7bSYongseok Koh 		offset = strd_idx * strd_sz + strd_shift;
13517d6bf6b8SYongseok Koh 		addr = RTE_PTR_ADD(mlx5_mprq_buf_addr(buf), offset);
13527d6bf6b8SYongseok Koh 		/* Initialize the offload flag. */
13537d6bf6b8SYongseok Koh 		pkt->ol_flags = 0;
13547d6bf6b8SYongseok Koh 		/*
13557d6bf6b8SYongseok Koh 		 * Memcpy packets to the target mbuf if:
13567d6bf6b8SYongseok Koh 		 * - The size of packet is smaller than mprq_max_memcpy_len.
13577d6bf6b8SYongseok Koh 		 * - Out of buffer in the Mempool for Multi-Packet RQ.
13587d6bf6b8SYongseok Koh 		 */
13597d6bf6b8SYongseok Koh 		if (len <= rxq->mprq_max_memcpy_len || rxq->mprq_repl == NULL) {
13607d6bf6b8SYongseok Koh 			/*
13617d6bf6b8SYongseok Koh 			 * When memcpy'ing packet due to out-of-buffer, the
13627d6bf6b8SYongseok Koh 			 * packet must be smaller than the target mbuf.
13637d6bf6b8SYongseok Koh 			 */
13647d6bf6b8SYongseok Koh 			if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
13657d6bf6b8SYongseok Koh 				rte_pktmbuf_free_seg(pkt);
13667d6bf6b8SYongseok Koh 				++rxq->stats.idropped;
13677d6bf6b8SYongseok Koh 				continue;
13687d6bf6b8SYongseok Koh 			}
13697d6bf6b8SYongseok Koh 			rte_memcpy(rte_pktmbuf_mtod(pkt, void *), addr, len);
13707d6bf6b8SYongseok Koh 		} else {
13717d6bf6b8SYongseok Koh 			rte_iova_t buf_iova;
13727d6bf6b8SYongseok Koh 			struct rte_mbuf_ext_shared_info *shinfo;
13731787eb7bSYongseok Koh 			uint16_t buf_len = strd_cnt * strd_sz;
13747d6bf6b8SYongseok Koh 
13757d6bf6b8SYongseok Koh 			/* Increment the refcnt of the whole chunk. */
13767d6bf6b8SYongseok Koh 			rte_atomic16_add_return(&buf->refcnt, 1);
13777d6bf6b8SYongseok Koh 			assert((uint16_t)rte_atomic16_read(&buf->refcnt) <=
13787d6bf6b8SYongseok Koh 			       strd_n + 1);
13797d6bf6b8SYongseok Koh 			addr = RTE_PTR_SUB(addr, RTE_PKTMBUF_HEADROOM);
13807d6bf6b8SYongseok Koh 			/*
13817d6bf6b8SYongseok Koh 			 * MLX5 device doesn't use iova but it is necessary in a
13827d6bf6b8SYongseok Koh 			 * case where the Rx packet is transmitted via a
13837d6bf6b8SYongseok Koh 			 * different PMD.
13847d6bf6b8SYongseok Koh 			 */
13857d6bf6b8SYongseok Koh 			buf_iova = rte_mempool_virt2iova(buf) +
13867d6bf6b8SYongseok Koh 				   RTE_PTR_DIFF(addr, buf);
13877d6bf6b8SYongseok Koh 			shinfo = rte_pktmbuf_ext_shinfo_init_helper(addr,
13887d6bf6b8SYongseok Koh 					&buf_len, mlx5_mprq_buf_free_cb, buf);
13897d6bf6b8SYongseok Koh 			/*
13907d6bf6b8SYongseok Koh 			 * EXT_ATTACHED_MBUF will be set to pkt->ol_flags when
13917d6bf6b8SYongseok Koh 			 * attaching the stride to mbuf and more offload flags
13927d6bf6b8SYongseok Koh 			 * will be added below by calling rxq_cq_to_mbuf().
13937d6bf6b8SYongseok Koh 			 * Other fields will be overwritten.
13947d6bf6b8SYongseok Koh 			 */
13957d6bf6b8SYongseok Koh 			rte_pktmbuf_attach_extbuf(pkt, addr, buf_iova, buf_len,
13967d6bf6b8SYongseok Koh 						  shinfo);
13977d6bf6b8SYongseok Koh 			rte_pktmbuf_reset_headroom(pkt);
13987d6bf6b8SYongseok Koh 			assert(pkt->ol_flags == EXT_ATTACHED_MBUF);
13997d6bf6b8SYongseok Koh 			/*
14007d6bf6b8SYongseok Koh 			 * Prevent potential overflow due to MTU change through
14017d6bf6b8SYongseok Koh 			 * kernel interface.
14027d6bf6b8SYongseok Koh 			 */
14037d6bf6b8SYongseok Koh 			if (unlikely(rte_pktmbuf_tailroom(pkt) < len)) {
14047d6bf6b8SYongseok Koh 				rte_pktmbuf_free_seg(pkt);
14057d6bf6b8SYongseok Koh 				++rxq->stats.idropped;
14067d6bf6b8SYongseok Koh 				continue;
14077d6bf6b8SYongseok Koh 			}
14087d6bf6b8SYongseok Koh 		}
14097d6bf6b8SYongseok Koh 		rxq_cq_to_mbuf(rxq, pkt, cqe, rss_hash_res);
14107d6bf6b8SYongseok Koh 		PKT_LEN(pkt) = len;
14117d6bf6b8SYongseok Koh 		DATA_LEN(pkt) = len;
14127d6bf6b8SYongseok Koh 		PORT(pkt) = rxq->port_id;
14137d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
14147d6bf6b8SYongseok Koh 		/* Increment bytes counter. */
14157d6bf6b8SYongseok Koh 		rxq->stats.ibytes += PKT_LEN(pkt);
14167d6bf6b8SYongseok Koh #endif
14177d6bf6b8SYongseok Koh 		/* Return packet. */
14187d6bf6b8SYongseok Koh 		*(pkts++) = pkt;
14197d6bf6b8SYongseok Koh 		++i;
14207d6bf6b8SYongseok Koh 	}
14217d6bf6b8SYongseok Koh 	/* Update the consumer indexes. */
14221787eb7bSYongseok Koh 	rxq->consumed_strd = consumed_strd;
14230cfdc180SYongseok Koh 	rte_cio_wmb();
14247d6bf6b8SYongseok Koh 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
14257d6bf6b8SYongseok Koh 	if (rq_ci != rxq->rq_ci) {
14267d6bf6b8SYongseok Koh 		rxq->rq_ci = rq_ci;
14270cfdc180SYongseok Koh 		rte_cio_wmb();
14287d6bf6b8SYongseok Koh 		*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
14297d6bf6b8SYongseok Koh 	}
14307d6bf6b8SYongseok Koh #ifdef MLX5_PMD_SOFT_COUNTERS
14317d6bf6b8SYongseok Koh 	/* Increment packets counter. */
14327d6bf6b8SYongseok Koh 	rxq->stats.ipackets += i;
14337d6bf6b8SYongseok Koh #endif
14347d6bf6b8SYongseok Koh 	return i;
14357d6bf6b8SYongseok Koh }
14367d6bf6b8SYongseok Koh 
14372e22920bSAdrien Mazarguil /**
14382e22920bSAdrien Mazarguil  * Dummy DPDK callback for TX.
14392e22920bSAdrien Mazarguil  *
14402e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14412e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14422e22920bSAdrien Mazarguil  *
14432e22920bSAdrien Mazarguil  * @param dpdk_txq
14442e22920bSAdrien Mazarguil  *   Generic pointer to TX queue structure.
14452e22920bSAdrien Mazarguil  * @param[in] pkts
14462e22920bSAdrien Mazarguil  *   Packets to transmit.
14472e22920bSAdrien Mazarguil  * @param pkts_n
14482e22920bSAdrien Mazarguil  *   Number of packets in array.
14492e22920bSAdrien Mazarguil  *
14502e22920bSAdrien Mazarguil  * @return
14512e22920bSAdrien Mazarguil  *   Number of packets successfully transmitted (<= pkts_n).
14522e22920bSAdrien Mazarguil  */
14532e22920bSAdrien Mazarguil uint16_t
145456f08e16SNélio Laranjeiro removed_tx_burst(void *dpdk_txq __rte_unused,
145556f08e16SNélio Laranjeiro 		 struct rte_mbuf **pkts __rte_unused,
145656f08e16SNélio Laranjeiro 		 uint16_t pkts_n __rte_unused)
14572e22920bSAdrien Mazarguil {
14582aac5b5dSYongseok Koh 	rte_mb();
14592e22920bSAdrien Mazarguil 	return 0;
14602e22920bSAdrien Mazarguil }
14612e22920bSAdrien Mazarguil 
14622e22920bSAdrien Mazarguil /**
14632e22920bSAdrien Mazarguil  * Dummy DPDK callback for RX.
14642e22920bSAdrien Mazarguil  *
14652e22920bSAdrien Mazarguil  * This function is used to temporarily replace the real callback during
14662e22920bSAdrien Mazarguil  * unsafe control operations on the queue, or in case of error.
14672e22920bSAdrien Mazarguil  *
14682e22920bSAdrien Mazarguil  * @param dpdk_rxq
14692e22920bSAdrien Mazarguil  *   Generic pointer to RX queue structure.
14702e22920bSAdrien Mazarguil  * @param[out] pkts
14712e22920bSAdrien Mazarguil  *   Array to store received packets.
14722e22920bSAdrien Mazarguil  * @param pkts_n
14732e22920bSAdrien Mazarguil  *   Maximum number of packets in array.
14742e22920bSAdrien Mazarguil  *
14752e22920bSAdrien Mazarguil  * @return
14762e22920bSAdrien Mazarguil  *   Number of packets successfully received (<= pkts_n).
14772e22920bSAdrien Mazarguil  */
14782e22920bSAdrien Mazarguil uint16_t
147956f08e16SNélio Laranjeiro removed_rx_burst(void *dpdk_txq __rte_unused,
148056f08e16SNélio Laranjeiro 		 struct rte_mbuf **pkts __rte_unused,
148156f08e16SNélio Laranjeiro 		 uint16_t pkts_n __rte_unused)
14822e22920bSAdrien Mazarguil {
14832aac5b5dSYongseok Koh 	rte_mb();
14842e22920bSAdrien Mazarguil 	return 0;
14852e22920bSAdrien Mazarguil }
14866cb559d6SYongseok Koh 
14876cb559d6SYongseok Koh /*
14886cb559d6SYongseok Koh  * Vectorized Rx/Tx routines are not compiled in when required vector
14896cb559d6SYongseok Koh  * instructions are not supported on a target architecture. The following null
14906cb559d6SYongseok Koh  * stubs are needed for linkage when those are not included outside of this file
14916cb559d6SYongseok Koh  * (e.g.  mlx5_rxtx_vec_sse.c for x86).
14926cb559d6SYongseok Koh  */
14936cb559d6SYongseok Koh 
149481bede55SKeith Wiles __rte_weak uint16_t
149556f08e16SNélio Laranjeiro mlx5_rx_burst_vec(void *dpdk_txq __rte_unused,
149656f08e16SNélio Laranjeiro 		  struct rte_mbuf **pkts __rte_unused,
149756f08e16SNélio Laranjeiro 		  uint16_t pkts_n __rte_unused)
14986cb559d6SYongseok Koh {
14996cb559d6SYongseok Koh 	return 0;
15006cb559d6SYongseok Koh }
15016cb559d6SYongseok Koh 
150281bede55SKeith Wiles __rte_weak int
1503af4f09f2SNélio Laranjeiro mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused)
15046cb559d6SYongseok Koh {
15056cb559d6SYongseok Koh 	return -ENOTSUP;
15066cb559d6SYongseok Koh }
15076cb559d6SYongseok Koh 
150881bede55SKeith Wiles __rte_weak int
1509af4f09f2SNélio Laranjeiro mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused)
15106cb559d6SYongseok Koh {
15116cb559d6SYongseok Koh 	return -ENOTSUP;
15126cb559d6SYongseok Koh }
1513a6bd4911SViacheslav Ovsiienko 
1514a6bd4911SViacheslav Ovsiienko /**
1515a6bd4911SViacheslav Ovsiienko  * DPDK callback to check the status of a tx descriptor.
1516a6bd4911SViacheslav Ovsiienko  *
1517a6bd4911SViacheslav Ovsiienko  * @param tx_queue
1518a6bd4911SViacheslav Ovsiienko  *   The tx queue.
1519a6bd4911SViacheslav Ovsiienko  * @param[in] offset
1520a6bd4911SViacheslav Ovsiienko  *   The index of the descriptor in the ring.
1521a6bd4911SViacheslav Ovsiienko  *
1522a6bd4911SViacheslav Ovsiienko  * @return
1523a6bd4911SViacheslav Ovsiienko  *   The status of the tx descriptor.
1524a6bd4911SViacheslav Ovsiienko  */
1525a6bd4911SViacheslav Ovsiienko int
1526a6bd4911SViacheslav Ovsiienko mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
1527a6bd4911SViacheslav Ovsiienko {
1528a6bd4911SViacheslav Ovsiienko 	(void)tx_queue;
1529a6bd4911SViacheslav Ovsiienko 	(void)offset;
1530a6bd4911SViacheslav Ovsiienko 	return RTE_ETH_TX_DESC_FULL;
1531a6bd4911SViacheslav Ovsiienko }
1532a6bd4911SViacheslav Ovsiienko 
1533a6bd4911SViacheslav Ovsiienko /**
1534a6bd4911SViacheslav Ovsiienko  * Configure the TX function to use.
1535a6bd4911SViacheslav Ovsiienko  *
1536a6bd4911SViacheslav Ovsiienko  * @param dev
1537a6bd4911SViacheslav Ovsiienko  *   Pointer to private data structure.
1538a6bd4911SViacheslav Ovsiienko  *
1539a6bd4911SViacheslav Ovsiienko  * @return
1540a6bd4911SViacheslav Ovsiienko  *   Pointer to selected Tx burst function.
1541a6bd4911SViacheslav Ovsiienko  */
1542a6bd4911SViacheslav Ovsiienko eth_tx_burst_t
1543a6bd4911SViacheslav Ovsiienko mlx5_select_tx_function(struct rte_eth_dev *dev)
1544a6bd4911SViacheslav Ovsiienko {
1545a6bd4911SViacheslav Ovsiienko 	(void)dev;
1546a6bd4911SViacheslav Ovsiienko 	return removed_tx_burst;
1547a6bd4911SViacheslav Ovsiienko }
1548a6bd4911SViacheslav Ovsiienko 
1549a6bd4911SViacheslav Ovsiienko 
1550