xref: /dpdk/drivers/net/mlx5/mlx5_rx.c (revision 3cddeba0ca38b00c7dc646277484d08a4cb2d862)
1a96102c8SMichael Baum /* SPDX-License-Identifier: BSD-3-Clause
2a96102c8SMichael Baum  * Copyright 2021 6WIND S.A.
3a96102c8SMichael Baum  * Copyright 2021 Mellanox Technologies, Ltd
4a96102c8SMichael Baum  */
5a96102c8SMichael Baum 
6a96102c8SMichael Baum #include <stdint.h>
7a96102c8SMichael Baum #include <string.h>
8a96102c8SMichael Baum #include <stdlib.h>
9a96102c8SMichael Baum 
10a96102c8SMichael Baum #include <rte_mbuf.h>
11a96102c8SMichael Baum #include <rte_mempool.h>
12a96102c8SMichael Baum #include <rte_prefetch.h>
13a96102c8SMichael Baum #include <rte_common.h>
14a96102c8SMichael Baum #include <rte_branch_prediction.h>
15a96102c8SMichael Baum #include <rte_ether.h>
16a96102c8SMichael Baum #include <rte_cycles.h>
17a96102c8SMichael Baum #include <rte_flow.h>
18a96102c8SMichael Baum 
19a96102c8SMichael Baum #include <mlx5_prm.h>
20a96102c8SMichael Baum #include <mlx5_common.h>
21fc59a1ecSMichael Baum #include <mlx5_common_mr.h>
222235fcdaSSpike Du #include <rte_pmd_mlx5.h>
23a96102c8SMichael Baum 
24a96102c8SMichael Baum #include "mlx5_autoconf.h"
25a96102c8SMichael Baum #include "mlx5_defs.h"
26a96102c8SMichael Baum #include "mlx5.h"
27a96102c8SMichael Baum #include "mlx5_utils.h"
28a96102c8SMichael Baum #include "mlx5_rxtx.h"
295c9f3294SSpike Du #include "mlx5_devx.h"
30a96102c8SMichael Baum #include "mlx5_rx.h"
312235fcdaSSpike Du #ifdef HAVE_MLX5_MSTFLINT
322235fcdaSSpike Du #include <mstflint/mtcr.h>
332235fcdaSSpike Du #endif
34a96102c8SMichael Baum 
35a96102c8SMichael Baum 
36a96102c8SMichael Baum static __rte_always_inline uint32_t
37a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
38a96102c8SMichael Baum 		   volatile struct mlx5_mini_cqe8 *mcqe);
39a96102c8SMichael Baum 
40a96102c8SMichael Baum static __rte_always_inline int
41a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
4202a6195cSAlexander Kozyrev 		 uint16_t cqe_n, uint16_t cqe_mask,
4302a6195cSAlexander Kozyrev 		 volatile struct mlx5_mini_cqe8 **mcqe,
44aa67ed30SAlexander Kozyrev 		 uint16_t *skip_cnt, bool mprq);
45a96102c8SMichael Baum 
46a96102c8SMichael Baum static __rte_always_inline uint32_t
47a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
48a96102c8SMichael Baum 
49a96102c8SMichael Baum static __rte_always_inline void
50a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
51a96102c8SMichael Baum 	       volatile struct mlx5_cqe *cqe,
52a96102c8SMichael Baum 	       volatile struct mlx5_mini_cqe8 *mcqe);
53a96102c8SMichael Baum 
54a96102c8SMichael Baum static inline void
55a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
56a96102c8SMichael Baum 			volatile struct mlx5_cqe *__rte_restrict cqe,
57a96102c8SMichael Baum 			uint32_t phcsum, uint8_t l4_type);
58a96102c8SMichael Baum 
59a96102c8SMichael Baum static inline void
60a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
61a96102c8SMichael Baum 		    volatile struct mlx5_cqe *__rte_restrict cqe,
62a96102c8SMichael Baum 		    volatile struct mlx5_mini_cqe8 *mcqe,
63a96102c8SMichael Baum 		    struct mlx5_rxq_data *rxq, uint32_t len);
64a96102c8SMichael Baum 
65a96102c8SMichael Baum 
66a96102c8SMichael Baum /**
67a96102c8SMichael Baum  * Internal function to compute the number of used descriptors in an RX queue.
68a96102c8SMichael Baum  *
69a96102c8SMichael Baum  * @param rxq
70a96102c8SMichael Baum  *   The Rx queue.
71a96102c8SMichael Baum  *
72a96102c8SMichael Baum  * @return
73a96102c8SMichael Baum  *   The number of used Rx descriptor.
74a96102c8SMichael Baum  */
75a96102c8SMichael Baum static uint32_t
76a96102c8SMichael Baum rx_queue_count(struct mlx5_rxq_data *rxq)
77a96102c8SMichael Baum {
78a96102c8SMichael Baum 	struct rxq_zip *zip = &rxq->zip;
79a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe;
80a96102c8SMichael Baum 	const unsigned int cqe_n = (1 << rxq->cqe_n);
81a96102c8SMichael Baum 	const unsigned int sges_n = (1 << rxq->sges_n);
82a96102c8SMichael Baum 	const unsigned int elts_n = (1 << rxq->elts_n);
830947ed38SMichael Baum 	const unsigned int strd_n = RTE_BIT32(rxq->log_strd_num);
84a96102c8SMichael Baum 	const unsigned int cqe_cnt = cqe_n - 1;
85a96102c8SMichael Baum 	unsigned int cq_ci, used;
86a96102c8SMichael Baum 
87a96102c8SMichael Baum 	/* if we are processing a compressed cqe */
88a96102c8SMichael Baum 	if (zip->ai) {
89a96102c8SMichael Baum 		used = zip->cqe_cnt - zip->ai;
90a96102c8SMichael Baum 		cq_ci = zip->cq_ci;
91a96102c8SMichael Baum 	} else {
92a96102c8SMichael Baum 		used = 0;
93a96102c8SMichael Baum 		cq_ci = rxq->cq_ci;
94a96102c8SMichael Baum 	}
95a96102c8SMichael Baum 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
96a96102c8SMichael Baum 	while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) {
97a96102c8SMichael Baum 		int8_t op_own;
98a96102c8SMichael Baum 		unsigned int n;
99a96102c8SMichael Baum 
100a96102c8SMichael Baum 		op_own = cqe->op_own;
101a96102c8SMichael Baum 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
102a96102c8SMichael Baum 			n = rte_be_to_cpu_32(cqe->byte_cnt);
103a96102c8SMichael Baum 		else
104a96102c8SMichael Baum 			n = 1;
105a96102c8SMichael Baum 		cq_ci += n;
106a96102c8SMichael Baum 		used += n;
107a96102c8SMichael Baum 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
108a96102c8SMichael Baum 	}
109a96102c8SMichael Baum 	used = RTE_MIN(used * sges_n, elts_n * strd_n);
110a96102c8SMichael Baum 	return used;
111a96102c8SMichael Baum }
112a96102c8SMichael Baum 
113a96102c8SMichael Baum /**
114a96102c8SMichael Baum  * DPDK callback to check the status of a Rx descriptor.
115a96102c8SMichael Baum  *
116a96102c8SMichael Baum  * @param rx_queue
117a96102c8SMichael Baum  *   The Rx queue.
118a96102c8SMichael Baum  * @param[in] offset
119a96102c8SMichael Baum  *   The index of the descriptor in the ring.
120a96102c8SMichael Baum  *
121a96102c8SMichael Baum  * @return
122a96102c8SMichael Baum  *   The status of the Rx descriptor.
123a96102c8SMichael Baum  */
124a96102c8SMichael Baum int
125a96102c8SMichael Baum mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
126a96102c8SMichael Baum {
127a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = rx_queue;
128a96102c8SMichael Baum 
129a96102c8SMichael Baum 	if (offset >= (1 << rxq->cqe_n)) {
130a96102c8SMichael Baum 		rte_errno = EINVAL;
131a96102c8SMichael Baum 		return -rte_errno;
132a96102c8SMichael Baum 	}
133a96102c8SMichael Baum 	if (offset < rx_queue_count(rxq))
134a96102c8SMichael Baum 		return RTE_ETH_RX_DESC_DONE;
135a96102c8SMichael Baum 	return RTE_ETH_RX_DESC_AVAIL;
136a96102c8SMichael Baum }
137a96102c8SMichael Baum 
1385c9f3294SSpike Du /* Get rxq lwm percentage according to lwm number. */
1395c9f3294SSpike Du static uint8_t
1405c9f3294SSpike Du mlx5_rxq_lwm_to_percentage(struct mlx5_rxq_priv *rxq)
1415c9f3294SSpike Du {
1425c9f3294SSpike Du 	struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq;
1435c9f3294SSpike Du 	uint32_t wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
1445c9f3294SSpike Du 
1455c9f3294SSpike Du 	return rxq->lwm * 100 / wqe_cnt;
1465c9f3294SSpike Du }
1475c9f3294SSpike Du 
148a96102c8SMichael Baum /**
149a96102c8SMichael Baum  * DPDK callback to get the RX queue information.
150a96102c8SMichael Baum  *
151a96102c8SMichael Baum  * @param dev
152a96102c8SMichael Baum  *   Pointer to the device structure.
153a96102c8SMichael Baum  *
154a96102c8SMichael Baum  * @param rx_queue_id
155a96102c8SMichael Baum  *   Rx queue identificator.
156a96102c8SMichael Baum  *
157a96102c8SMichael Baum  * @param qinfo
158a96102c8SMichael Baum  *   Pointer to the RX queue information structure.
159a96102c8SMichael Baum  *
160a96102c8SMichael Baum  * @return
161a96102c8SMichael Baum  *   None.
162a96102c8SMichael Baum  */
163a96102c8SMichael Baum 
164a96102c8SMichael Baum void
165a96102c8SMichael Baum mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
166a96102c8SMichael Baum 		  struct rte_eth_rxq_info *qinfo)
167a96102c8SMichael Baum {
1685cf0707fSXueming Li 	struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, rx_queue_id);
1695cf0707fSXueming Li 	struct mlx5_rxq_data *rxq = mlx5_rxq_data_get(dev, rx_queue_id);
1705c9f3294SSpike Du 	struct mlx5_rxq_priv *rxq_priv = mlx5_rxq_get(dev, rx_queue_id);
171a96102c8SMichael Baum 
172a96102c8SMichael Baum 	if (!rxq)
173a96102c8SMichael Baum 		return;
174a96102c8SMichael Baum 	qinfo->mp = mlx5_rxq_mprq_enabled(rxq) ?
175a96102c8SMichael Baum 					rxq->mprq_mp : rxq->mp;
176a96102c8SMichael Baum 	qinfo->conf.rx_thresh.pthresh = 0;
177a96102c8SMichael Baum 	qinfo->conf.rx_thresh.hthresh = 0;
178a96102c8SMichael Baum 	qinfo->conf.rx_thresh.wthresh = 0;
179a96102c8SMichael Baum 	qinfo->conf.rx_free_thresh = rxq->rq_repl_thresh;
180a96102c8SMichael Baum 	qinfo->conf.rx_drop_en = 1;
1815cf0707fSXueming Li 	if (rxq_ctrl == NULL || rxq_ctrl->obj == NULL)
1825cf0707fSXueming Li 		qinfo->conf.rx_deferred_start = 0;
1835cf0707fSXueming Li 	else
1845cf0707fSXueming Li 		qinfo->conf.rx_deferred_start = 1;
185a96102c8SMichael Baum 	qinfo->conf.offloads = dev->data->dev_conf.rxmode.offloads;
186a96102c8SMichael Baum 	qinfo->scattered_rx = dev->data->scattered_rx;
187a96102c8SMichael Baum 	qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ?
1880947ed38SMichael Baum 		RTE_BIT32(rxq->elts_n) * RTE_BIT32(rxq->log_strd_num) :
1890947ed38SMichael Baum 		RTE_BIT32(rxq->elts_n);
1905c9f3294SSpike Du 	qinfo->avail_thresh = rxq_priv ?
1915c9f3294SSpike Du 		mlx5_rxq_lwm_to_percentage(rxq_priv) : 0;
192a96102c8SMichael Baum }
193a96102c8SMichael Baum 
194a96102c8SMichael Baum /**
195a96102c8SMichael Baum  * DPDK callback to get the RX packet burst mode information.
196a96102c8SMichael Baum  *
197a96102c8SMichael Baum  * @param dev
198a96102c8SMichael Baum  *   Pointer to the device structure.
199a96102c8SMichael Baum  *
200a96102c8SMichael Baum  * @param rx_queue_id
2017be78d02SJosh Soref  *   Rx queue identification.
202a96102c8SMichael Baum  *
203a96102c8SMichael Baum  * @param mode
204a96102c8SMichael Baum  *   Pointer to the burts mode information.
205a96102c8SMichael Baum  *
206a96102c8SMichael Baum  * @return
207a96102c8SMichael Baum  *   0 as success, -EINVAL as failure.
208a96102c8SMichael Baum  */
209a96102c8SMichael Baum int
210a96102c8SMichael Baum mlx5_rx_burst_mode_get(struct rte_eth_dev *dev,
211a96102c8SMichael Baum 		       uint16_t rx_queue_id __rte_unused,
212a96102c8SMichael Baum 		       struct rte_eth_burst_mode *mode)
213a96102c8SMichael Baum {
214a96102c8SMichael Baum 	eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
2155cf0707fSXueming Li 	struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id);
216a96102c8SMichael Baum 
217a96102c8SMichael Baum 	if (!rxq) {
218a96102c8SMichael Baum 		rte_errno = EINVAL;
219a96102c8SMichael Baum 		return -rte_errno;
220a96102c8SMichael Baum 	}
221a96102c8SMichael Baum 	if (pkt_burst == mlx5_rx_burst) {
222a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Scalar");
223a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_mprq) {
224a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Multi-Packet RQ");
225a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_vec) {
226a96102c8SMichael Baum #if defined RTE_ARCH_X86_64
227a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector SSE");
228a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64
229a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector Neon");
230a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64
231a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector AltiVec");
232a96102c8SMichael Baum #else
233a96102c8SMichael Baum 		return -EINVAL;
234a96102c8SMichael Baum #endif
235a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_mprq_vec) {
236a96102c8SMichael Baum #if defined RTE_ARCH_X86_64
237a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector SSE");
238a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64
239a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector Neon");
240a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64
241a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector AltiVec");
242a96102c8SMichael Baum #else
243a96102c8SMichael Baum 		return -EINVAL;
244a96102c8SMichael Baum #endif
245a96102c8SMichael Baum 	} else {
246a96102c8SMichael Baum 		return -EINVAL;
247a96102c8SMichael Baum 	}
248a96102c8SMichael Baum 	return 0;
249a96102c8SMichael Baum }
250a96102c8SMichael Baum 
251a96102c8SMichael Baum /**
252a96102c8SMichael Baum  * DPDK callback to get the number of used descriptors in a RX queue.
253a96102c8SMichael Baum  *
2548d7d4fcdSKonstantin Ananyev  * @param rx_queue
2558d7d4fcdSKonstantin Ananyev  *   The Rx queue pointer.
256a96102c8SMichael Baum  *
257a96102c8SMichael Baum  * @return
258a96102c8SMichael Baum  *   The number of used rx descriptor.
259a96102c8SMichael Baum  *   -EINVAL if the queue is invalid
260a96102c8SMichael Baum  */
261a96102c8SMichael Baum uint32_t
2628d7d4fcdSKonstantin Ananyev mlx5_rx_queue_count(void *rx_queue)
263a96102c8SMichael Baum {
2648d7d4fcdSKonstantin Ananyev 	struct mlx5_rxq_data *rxq = rx_queue;
2658d7d4fcdSKonstantin Ananyev 	struct rte_eth_dev *dev;
2668d7d4fcdSKonstantin Ananyev 
2678d7d4fcdSKonstantin Ananyev 	if (!rxq) {
2688d7d4fcdSKonstantin Ananyev 		rte_errno = EINVAL;
2698d7d4fcdSKonstantin Ananyev 		return -rte_errno;
2708d7d4fcdSKonstantin Ananyev 	}
2718d7d4fcdSKonstantin Ananyev 
2728d7d4fcdSKonstantin Ananyev 	dev = &rte_eth_devices[rxq->port_id];
273a96102c8SMichael Baum 
274a96102c8SMichael Baum 	if (dev->rx_pkt_burst == NULL ||
275a41f593fSFerruh Yigit 	    dev->rx_pkt_burst == rte_eth_pkt_burst_dummy) {
276a96102c8SMichael Baum 		rte_errno = ENOTSUP;
277a96102c8SMichael Baum 		return -rte_errno;
278a96102c8SMichael Baum 	}
2798d7d4fcdSKonstantin Ananyev 
280a96102c8SMichael Baum 	return rx_queue_count(rxq);
281a96102c8SMichael Baum }
282a96102c8SMichael Baum 
2836afc4bafSAnatoly Burakov #define CLB_VAL_IDX 0
2846afc4bafSAnatoly Burakov #define CLB_MSK_IDX 1
2856afc4bafSAnatoly Burakov static int
2866afc4bafSAnatoly Burakov mlx5_monitor_callback(const uint64_t value,
2876afc4bafSAnatoly Burakov 		const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
2886afc4bafSAnatoly Burakov {
2896afc4bafSAnatoly Burakov 	const uint64_t m = opaque[CLB_MSK_IDX];
2906afc4bafSAnatoly Burakov 	const uint64_t v = opaque[CLB_VAL_IDX];
2916afc4bafSAnatoly Burakov 
2926afc4bafSAnatoly Burakov 	return (value & m) == v ? -1 : 0;
2936afc4bafSAnatoly Burakov }
2946afc4bafSAnatoly Burakov 
295a8f0df6bSAlexander Kozyrev int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
296a8f0df6bSAlexander Kozyrev {
297a8f0df6bSAlexander Kozyrev 	struct mlx5_rxq_data *rxq = rx_queue;
298a8f0df6bSAlexander Kozyrev 	const unsigned int cqe_num = 1 << rxq->cqe_n;
299a8f0df6bSAlexander Kozyrev 	const unsigned int cqe_mask = cqe_num - 1;
300a8f0df6bSAlexander Kozyrev 	const uint16_t idx = rxq->cq_ci & cqe_num;
30102a6195cSAlexander Kozyrev 	const uint8_t vic = rxq->cq_ci >> rxq->cqe_n;
302a8f0df6bSAlexander Kozyrev 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
303a8f0df6bSAlexander Kozyrev 
304a8f0df6bSAlexander Kozyrev 	if (unlikely(rxq->cqes == NULL)) {
305a8f0df6bSAlexander Kozyrev 		rte_errno = EINVAL;
306a8f0df6bSAlexander Kozyrev 		return -rte_errno;
307a8f0df6bSAlexander Kozyrev 	}
30802a6195cSAlexander Kozyrev 	if (rxq->cqe_comp_layout) {
30902a6195cSAlexander Kozyrev 		pmc->addr = &cqe->validity_iteration_count;
31002a6195cSAlexander Kozyrev 		pmc->opaque[CLB_VAL_IDX] = vic;
31102a6195cSAlexander Kozyrev 		pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_VIC_INIT;
31202a6195cSAlexander Kozyrev 	} else {
313a8f0df6bSAlexander Kozyrev 		pmc->addr = &cqe->op_own;
3146afc4bafSAnatoly Burakov 		pmc->opaque[CLB_VAL_IDX] = !!idx;
3156afc4bafSAnatoly Burakov 		pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_OWNER_MASK;
31602a6195cSAlexander Kozyrev 	}
3176afc4bafSAnatoly Burakov 	pmc->fn = mlx5_monitor_callback;
318a8f0df6bSAlexander Kozyrev 	pmc->size = sizeof(uint8_t);
319a8f0df6bSAlexander Kozyrev 	return 0;
320a8f0df6bSAlexander Kozyrev }
321a8f0df6bSAlexander Kozyrev 
322a96102c8SMichael Baum /**
323a96102c8SMichael Baum  * Translate RX completion flags to packet type.
324a96102c8SMichael Baum  *
325a96102c8SMichael Baum  * @param[in] rxq
326a96102c8SMichael Baum  *   Pointer to RX queue structure.
327a96102c8SMichael Baum  * @param[in] cqe
328a96102c8SMichael Baum  *   Pointer to CQE.
329a96102c8SMichael Baum  *
330a96102c8SMichael Baum  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
331a96102c8SMichael Baum  *
332a96102c8SMichael Baum  * @return
333a96102c8SMichael Baum  *   Packet type for struct rte_mbuf.
334a96102c8SMichael Baum  */
335a96102c8SMichael Baum static inline uint32_t
336a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
337a96102c8SMichael Baum 				   volatile struct mlx5_mini_cqe8 *mcqe)
338a96102c8SMichael Baum {
339a96102c8SMichael Baum 	uint8_t idx;
340a96102c8SMichael Baum 	uint8_t ptype;
341a96102c8SMichael Baum 	uint8_t pinfo = (cqe->pkt_info & 0x3) << 6;
342a96102c8SMichael Baum 
343a96102c8SMichael Baum 	/* Get l3/l4 header from mini-CQE in case L3/L4 format*/
344a96102c8SMichael Baum 	if (mcqe == NULL ||
345a96102c8SMichael Baum 	    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
346a96102c8SMichael Baum 		ptype = (cqe->hdr_type_etc & 0xfc00) >> 10;
347a96102c8SMichael Baum 	else
348a96102c8SMichael Baum 		ptype = mcqe->hdr_type >> 2;
349a96102c8SMichael Baum 	/*
350a96102c8SMichael Baum 	 * The index to the array should have:
351a96102c8SMichael Baum 	 * bit[1:0] = l3_hdr_type
352a96102c8SMichael Baum 	 * bit[4:2] = l4_hdr_type
353a96102c8SMichael Baum 	 * bit[5] = ip_frag
354a96102c8SMichael Baum 	 * bit[6] = tunneled
355a96102c8SMichael Baum 	 * bit[7] = outer_l3_type
356a96102c8SMichael Baum 	 */
357a96102c8SMichael Baum 	idx = pinfo | ptype;
358a96102c8SMichael Baum 	return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
359a96102c8SMichael Baum }
360a96102c8SMichael Baum 
361a96102c8SMichael Baum /**
362a96102c8SMichael Baum  * Initialize Rx WQ and indexes.
363a96102c8SMichael Baum  *
364a96102c8SMichael Baum  * @param[in] rxq
365a96102c8SMichael Baum  *   Pointer to RX queue structure.
366a96102c8SMichael Baum  */
367a96102c8SMichael Baum void
368a96102c8SMichael Baum mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
369a96102c8SMichael Baum {
370a96102c8SMichael Baum 	const unsigned int wqe_n = 1 << rxq->elts_n;
371a96102c8SMichael Baum 	unsigned int i;
372a96102c8SMichael Baum 
373a96102c8SMichael Baum 	for (i = 0; (i != wqe_n); ++i) {
374a96102c8SMichael Baum 		volatile struct mlx5_wqe_data_seg *scat;
375a96102c8SMichael Baum 		uintptr_t addr;
376a96102c8SMichael Baum 		uint32_t byte_count;
377077be91dSDmitry Kozlyuk 		uint32_t lkey;
378a96102c8SMichael Baum 
379a96102c8SMichael Baum 		if (mlx5_rxq_mprq_enabled(rxq)) {
380a96102c8SMichael Baum 			struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
381a96102c8SMichael Baum 
382a96102c8SMichael Baum 			scat = &((volatile struct mlx5_wqe_mprq *)
383a96102c8SMichael Baum 				rxq->wqes)[i].dseg;
3840947ed38SMichael Baum 			addr = (uintptr_t)mlx5_mprq_buf_addr
3850947ed38SMichael Baum 					(buf, RTE_BIT32(rxq->log_strd_num));
3860947ed38SMichael Baum 			byte_count = RTE_BIT32(rxq->log_strd_sz) *
3870947ed38SMichael Baum 				     RTE_BIT32(rxq->log_strd_num);
388077be91dSDmitry Kozlyuk 			lkey = mlx5_rx_addr2mr(rxq, addr);
389a96102c8SMichael Baum 		} else {
390a96102c8SMichael Baum 			struct rte_mbuf *buf = (*rxq->elts)[i];
391a96102c8SMichael Baum 
392a96102c8SMichael Baum 			scat = &((volatile struct mlx5_wqe_data_seg *)
393a96102c8SMichael Baum 					rxq->wqes)[i];
394a96102c8SMichael Baum 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
395a96102c8SMichael Baum 			byte_count = DATA_LEN(buf);
396077be91dSDmitry Kozlyuk 			lkey = mlx5_rx_mb2mr(rxq, buf);
397a96102c8SMichael Baum 		}
398a96102c8SMichael Baum 		/* scat->addr must be able to store a pointer. */
399a96102c8SMichael Baum 		MLX5_ASSERT(sizeof(scat->addr) >= sizeof(uintptr_t));
400a96102c8SMichael Baum 		*scat = (struct mlx5_wqe_data_seg){
401a96102c8SMichael Baum 			.addr = rte_cpu_to_be_64(addr),
402a96102c8SMichael Baum 			.byte_count = rte_cpu_to_be_32(byte_count),
403077be91dSDmitry Kozlyuk 			.lkey = lkey,
404a96102c8SMichael Baum 		};
405a96102c8SMichael Baum 	}
406a96102c8SMichael Baum 	rxq->consumed_strd = 0;
407a96102c8SMichael Baum 	rxq->decompressed = 0;
408a96102c8SMichael Baum 	rxq->rq_pi = 0;
409a96102c8SMichael Baum 	rxq->zip = (struct rxq_zip){
410a96102c8SMichael Baum 		.ai = 0,
411a96102c8SMichael Baum 	};
412a96102c8SMichael Baum 	rxq->elts_ci = mlx5_rxq_mprq_enabled(rxq) ?
4130947ed38SMichael Baum 		(wqe_n >> rxq->sges_n) * RTE_BIT32(rxq->log_strd_num) : 0;
414a96102c8SMichael Baum 	/* Update doorbell counter. */
415a96102c8SMichael Baum 	rxq->rq_ci = wqe_n >> rxq->sges_n;
416a96102c8SMichael Baum 	rte_io_wmb();
417a96102c8SMichael Baum 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
418a96102c8SMichael Baum }
419a96102c8SMichael Baum 
420aa67ed30SAlexander Kozyrev #define MLX5_ERROR_CQE_MASK 0x40000000
42160b254e3SMatan Azrad /* Must be negative. */
422aa67ed30SAlexander Kozyrev #define MLX5_REGULAR_ERROR_CQE_RET (-5)
423aa67ed30SAlexander Kozyrev #define MLX5_CRITICAL_ERROR_CQE_RET (-4)
42460b254e3SMatan Azrad /* Must not be negative. */
42560b254e3SMatan Azrad #define MLX5_RECOVERY_ERROR_RET 0
426aa67ed30SAlexander Kozyrev #define MLX5_RECOVERY_IGNORE_RET 1
427aa67ed30SAlexander Kozyrev #define MLX5_RECOVERY_COMPLETED_RET 2
42860b254e3SMatan Azrad 
429a96102c8SMichael Baum /**
430a96102c8SMichael Baum  * Handle a Rx error.
431a96102c8SMichael Baum  * The function inserts the RQ state to reset when the first error CQE is
432a96102c8SMichael Baum  * shown, then drains the CQ by the caller function loop. When the CQ is empty,
433a96102c8SMichael Baum  * it moves the RQ state to ready and initializes the RQ.
434a96102c8SMichael Baum  * Next CQE identification and error counting are in the caller responsibility.
435a96102c8SMichael Baum  *
436a96102c8SMichael Baum  * @param[in] rxq
437a96102c8SMichael Baum  *   Pointer to RX queue structure.
438a96102c8SMichael Baum  * @param[in] vec
439a96102c8SMichael Baum  *   1 when called from vectorized Rx burst, need to prepare mbufs for the RQ.
440a96102c8SMichael Baum  *   0 when called from non-vectorized Rx burst.
441633684e0SAlexander Kozyrev  * @param[in] err_n
442633684e0SAlexander Kozyrev  *   Number of CQEs to check for an error.
443a96102c8SMichael Baum  *
444a96102c8SMichael Baum  * @return
445aa67ed30SAlexander Kozyrev  *   MLX5_RECOVERY_ERROR_RET in case of recovery error,
446aa67ed30SAlexander Kozyrev  *   MLX5_RECOVERY_IGNORE_RET in case of non-critical error syndrome,
447aa67ed30SAlexander Kozyrev  *   MLX5_RECOVERY_COMPLETED_RET in case of recovery is completed,
448aa67ed30SAlexander Kozyrev  *   otherwise the CQE status after ignored error syndrome or queue reset.
449a96102c8SMichael Baum  */
450a96102c8SMichael Baum int
451aa67ed30SAlexander Kozyrev mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec,
452aa67ed30SAlexander Kozyrev 		   uint16_t err_n, uint16_t *skip_cnt)
453a96102c8SMichael Baum {
454a96102c8SMichael Baum 	const uint16_t cqe_n = 1 << rxq->cqe_n;
455a96102c8SMichael Baum 	const uint16_t cqe_mask = cqe_n - 1;
456a96102c8SMichael Baum 	const uint16_t wqe_n = 1 << rxq->elts_n;
4570947ed38SMichael Baum 	const uint16_t strd_n = RTE_BIT32(rxq->log_strd_num);
458a96102c8SMichael Baum 	struct mlx5_rxq_ctrl *rxq_ctrl =
459a96102c8SMichael Baum 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
460a96102c8SMichael Baum 	union {
461a96102c8SMichael Baum 		volatile struct mlx5_cqe *cqe;
462*3cddeba0SAlexander Kozyrev 		volatile struct mlx5_error_cqe *err_cqe;
463a96102c8SMichael Baum 	} u = {
464633684e0SAlexander Kozyrev 		.cqe = &(*rxq->cqes)[(rxq->cq_ci - vec) & cqe_mask],
465a96102c8SMichael Baum 	};
466a96102c8SMichael Baum 	struct mlx5_mp_arg_queue_state_modify sm;
467aa67ed30SAlexander Kozyrev 	bool critical_syndrome = false;
468633684e0SAlexander Kozyrev 	int ret, i;
469a96102c8SMichael Baum 
470a96102c8SMichael Baum 	switch (rxq->err_state) {
471aa67ed30SAlexander Kozyrev 	case MLX5_RXQ_ERR_STATE_IGNORE:
472aa67ed30SAlexander Kozyrev 		ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci - vec);
473aa67ed30SAlexander Kozyrev 		if (ret != MLX5_CQE_STATUS_ERR) {
474aa67ed30SAlexander Kozyrev 			rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
475aa67ed30SAlexander Kozyrev 			return ret;
476aa67ed30SAlexander Kozyrev 		}
477aa67ed30SAlexander Kozyrev 		/* Fall-through */
478a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NO_ERROR:
479633684e0SAlexander Kozyrev 		for (i = 0; i < (int)err_n; i++) {
480633684e0SAlexander Kozyrev 			u.cqe = &(*rxq->cqes)[(rxq->cq_ci - vec - i) & cqe_mask];
481aa67ed30SAlexander Kozyrev 			if (MLX5_CQE_OPCODE(u.cqe->op_own) == MLX5_CQE_RESP_ERR) {
482aa67ed30SAlexander Kozyrev 				if (u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
483aa67ed30SAlexander Kozyrev 				    u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_PROT_ERR ||
484aa67ed30SAlexander Kozyrev 				    u.err_cqe->syndrome == MLX5_CQE_SYNDROME_WR_FLUSH_ERR)
485aa67ed30SAlexander Kozyrev 					critical_syndrome = true;
486633684e0SAlexander Kozyrev 				break;
487633684e0SAlexander Kozyrev 			}
488aa67ed30SAlexander Kozyrev 		}
489aa67ed30SAlexander Kozyrev 		if (!critical_syndrome) {
490aa67ed30SAlexander Kozyrev 			if (rxq->err_state == MLX5_RXQ_ERR_STATE_NO_ERROR) {
491aa67ed30SAlexander Kozyrev 				*skip_cnt = 0;
492aa67ed30SAlexander Kozyrev 				if (i == err_n)
493aa67ed30SAlexander Kozyrev 					rxq->err_state = MLX5_RXQ_ERR_STATE_IGNORE;
494aa67ed30SAlexander Kozyrev 			}
495aa67ed30SAlexander Kozyrev 			return MLX5_RECOVERY_IGNORE_RET;
496aa67ed30SAlexander Kozyrev 		}
497a96102c8SMichael Baum 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET;
498a96102c8SMichael Baum 		/* Fall-through */
499a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NEED_RESET:
500a96102c8SMichael Baum 		sm.is_wq = 1;
501a96102c8SMichael Baum 		sm.queue_id = rxq->idx;
502a96102c8SMichael Baum 		sm.state = IBV_WQS_RESET;
5035db77fefSXueming Li 		if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm))
50460b254e3SMatan Azrad 			return MLX5_RECOVERY_ERROR_RET;
505a96102c8SMichael Baum 		if (rxq_ctrl->dump_file_n <
5065db77fefSXueming Li 		    RXQ_PORT(rxq_ctrl)->config.max_dump_files_num) {
507a96102c8SMichael Baum 			MKSTR(err_str, "Unexpected CQE error syndrome "
508a96102c8SMichael Baum 			      "0x%02x CQN = %u RQN = %u wqe_counter = %u"
509a96102c8SMichael Baum 			      " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome,
510a96102c8SMichael Baum 			      rxq->cqn, rxq_ctrl->wqn,
511a96102c8SMichael Baum 			      rte_be_to_cpu_16(u.err_cqe->wqe_counter),
512a96102c8SMichael Baum 			      rxq->rq_ci << rxq->sges_n, rxq->cq_ci);
513a96102c8SMichael Baum 			MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u",
514a96102c8SMichael Baum 			      rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc());
515a96102c8SMichael Baum 			mlx5_dump_debug_information(name, NULL, err_str, 0);
516a96102c8SMichael Baum 			mlx5_dump_debug_information(name, "MLX5 Error CQ:",
517a96102c8SMichael Baum 						    (const void *)((uintptr_t)
518a96102c8SMichael Baum 								    rxq->cqes),
519a96102c8SMichael Baum 						    sizeof(*u.cqe) * cqe_n);
520a96102c8SMichael Baum 			mlx5_dump_debug_information(name, "MLX5 Error RQ:",
521a96102c8SMichael Baum 						    (const void *)((uintptr_t)
522a96102c8SMichael Baum 								    rxq->wqes),
523a96102c8SMichael Baum 						    16 * wqe_n);
524a96102c8SMichael Baum 			rxq_ctrl->dump_file_n++;
525a96102c8SMichael Baum 		}
526a96102c8SMichael Baum 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY;
527a96102c8SMichael Baum 		/* Fall-through */
528a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NEED_READY:
529a96102c8SMichael Baum 		ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci);
530a96102c8SMichael Baum 		if (ret == MLX5_CQE_STATUS_HW_OWN) {
531a96102c8SMichael Baum 			rte_io_wmb();
532a96102c8SMichael Baum 			*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
533a96102c8SMichael Baum 			rte_io_wmb();
534a96102c8SMichael Baum 			/*
535a96102c8SMichael Baum 			 * The RQ consumer index must be zeroed while moving
536a96102c8SMichael Baum 			 * from RESET state to RDY state.
537a96102c8SMichael Baum 			 */
538a96102c8SMichael Baum 			*rxq->rq_db = rte_cpu_to_be_32(0);
539a96102c8SMichael Baum 			rte_io_wmb();
540a96102c8SMichael Baum 			sm.is_wq = 1;
541a96102c8SMichael Baum 			sm.queue_id = rxq->idx;
542a96102c8SMichael Baum 			sm.state = IBV_WQS_RDY;
5435db77fefSXueming Li 			if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm))
54460b254e3SMatan Azrad 				return MLX5_RECOVERY_ERROR_RET;
545a96102c8SMichael Baum 			if (vec) {
546a96102c8SMichael Baum 				const uint32_t elts_n =
547a96102c8SMichael Baum 					mlx5_rxq_mprq_enabled(rxq) ?
548a96102c8SMichael Baum 					wqe_n * strd_n : wqe_n;
549a96102c8SMichael Baum 				const uint32_t e_mask = elts_n - 1;
550a96102c8SMichael Baum 				uint32_t elts_ci =
551a96102c8SMichael Baum 					mlx5_rxq_mprq_enabled(rxq) ?
552a96102c8SMichael Baum 					rxq->elts_ci : rxq->rq_ci;
553a96102c8SMichael Baum 				uint32_t elt_idx;
554a96102c8SMichael Baum 				struct rte_mbuf **elt;
555a96102c8SMichael Baum 				unsigned int n = elts_n - (elts_ci -
556a96102c8SMichael Baum 							  rxq->rq_pi);
557a96102c8SMichael Baum 
558a96102c8SMichael Baum 				for (i = 0; i < (int)n; ++i) {
559a96102c8SMichael Baum 					elt_idx = (elts_ci + i) & e_mask;
560a96102c8SMichael Baum 					elt = &(*rxq->elts)[elt_idx];
561a96102c8SMichael Baum 					*elt = rte_mbuf_raw_alloc(rxq->mp);
562a96102c8SMichael Baum 					if (!*elt) {
563a96102c8SMichael Baum 						for (i--; i >= 0; --i) {
564a96102c8SMichael Baum 							elt_idx = (elts_ci +
565a96102c8SMichael Baum 								   i) & elts_n;
566a96102c8SMichael Baum 							elt = &(*rxq->elts)
567a96102c8SMichael Baum 								[elt_idx];
568a96102c8SMichael Baum 							rte_pktmbuf_free_seg
569a96102c8SMichael Baum 								(*elt);
570a96102c8SMichael Baum 						}
57160b254e3SMatan Azrad 						return MLX5_RECOVERY_ERROR_RET;
572a96102c8SMichael Baum 					}
573a96102c8SMichael Baum 				}
574a96102c8SMichael Baum 				for (i = 0; i < (int)elts_n; ++i) {
575a96102c8SMichael Baum 					elt = &(*rxq->elts)[i];
576a96102c8SMichael Baum 					DATA_LEN(*elt) =
577a96102c8SMichael Baum 						(uint16_t)((*elt)->buf_len -
578a96102c8SMichael Baum 						rte_pktmbuf_headroom(*elt));
579a96102c8SMichael Baum 				}
580a96102c8SMichael Baum 				/* Padding with a fake mbuf for vec Rx. */
581a96102c8SMichael Baum 				for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i)
582a96102c8SMichael Baum 					(*rxq->elts)[elts_n + i] =
583a96102c8SMichael Baum 								&rxq->fake_mbuf;
584a96102c8SMichael Baum 			}
585a96102c8SMichael Baum 			mlx5_rxq_initialize(rxq);
586a96102c8SMichael Baum 			rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
587aa67ed30SAlexander Kozyrev 			return MLX5_RECOVERY_COMPLETED_RET;
588a96102c8SMichael Baum 		}
589a96102c8SMichael Baum 		return ret;
590a96102c8SMichael Baum 	default:
59160b254e3SMatan Azrad 		return MLX5_RECOVERY_ERROR_RET;
592a96102c8SMichael Baum 	}
593a96102c8SMichael Baum }
594a96102c8SMichael Baum 
595a96102c8SMichael Baum /**
596a96102c8SMichael Baum  * Get size of the next packet for a given CQE. For compressed CQEs, the
597a96102c8SMichael Baum  * consumer index is updated only once all packets of the current one have
598a96102c8SMichael Baum  * been processed.
599a96102c8SMichael Baum  *
600a96102c8SMichael Baum  * @param rxq
601a96102c8SMichael Baum  *   Pointer to RX queue.
602a96102c8SMichael Baum  * @param cqe
603a96102c8SMichael Baum  *   CQE to process.
60402a6195cSAlexander Kozyrev  * @param cqe_n
60502a6195cSAlexander Kozyrev  *   Completion queue count.
60602a6195cSAlexander Kozyrev  * @param cqe_mask
60702a6195cSAlexander Kozyrev  *   Completion queue mask.
608a96102c8SMichael Baum  * @param[out] mcqe
609a96102c8SMichael Baum  *   Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
610a96102c8SMichael Baum  *   written.
611aa67ed30SAlexander Kozyrev  * @param[out] skip_cnt
612aa67ed30SAlexander Kozyrev  *   Number of packets skipped due to recoverable errors.
613aa67ed30SAlexander Kozyrev  * @param mprq
614aa67ed30SAlexander Kozyrev  *   Indication if it is called from MPRQ.
615a96102c8SMichael Baum  * @return
616ef296e8fSViacheslav Ovsiienko  *   0 in case of empty CQE,
617ef296e8fSViacheslav Ovsiienko  *   MLX5_REGULAR_ERROR_CQE_RET in case of error CQE,
618aa67ed30SAlexander Kozyrev  *   MLX5_CRITICAL_ERROR_CQE_RET in case of error CQE lead to Rx queue reset,
619aa67ed30SAlexander Kozyrev  *   otherwise the packet size in regular RxQ,
620aa67ed30SAlexander Kozyrev  *   and striding byte count format in mprq case.
621a96102c8SMichael Baum  */
622a96102c8SMichael Baum static inline int
623a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
62402a6195cSAlexander Kozyrev 		 uint16_t cqe_n, uint16_t cqe_mask,
62502a6195cSAlexander Kozyrev 		 volatile struct mlx5_mini_cqe8 **mcqe,
626aa67ed30SAlexander Kozyrev 		 uint16_t *skip_cnt, bool mprq)
627a96102c8SMichael Baum {
628a96102c8SMichael Baum 	struct rxq_zip *zip = &rxq->zip;
629aa67ed30SAlexander Kozyrev 	int len = 0, ret = 0;
63002a6195cSAlexander Kozyrev 	uint32_t idx, end;
631a96102c8SMichael Baum 
632a96102c8SMichael Baum 	do {
633a96102c8SMichael Baum 		len = 0;
634a96102c8SMichael Baum 		/* Process compressed data in the CQE and mini arrays. */
635a96102c8SMichael Baum 		if (zip->ai) {
636a96102c8SMichael Baum 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
637a96102c8SMichael Baum 				(volatile struct mlx5_mini_cqe8 (*)[8])
638a96102c8SMichael Baum 				(uintptr_t)(&(*rxq->cqes)[zip->ca &
63902a6195cSAlexander Kozyrev 							cqe_mask].pkt_info);
640a96102c8SMichael Baum 			len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt &
641a96102c8SMichael Baum 						rxq->byte_mask);
642a96102c8SMichael Baum 			*mcqe = &(*mc)[zip->ai & 7];
64302a6195cSAlexander Kozyrev 			if (rxq->cqe_comp_layout) {
64402a6195cSAlexander Kozyrev 				zip->ai++;
64502a6195cSAlexander Kozyrev 				if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
64602a6195cSAlexander Kozyrev 					rxq->cq_ci = zip->cq_ci;
64702a6195cSAlexander Kozyrev 					zip->ai = 0;
64802a6195cSAlexander Kozyrev 				}
64902a6195cSAlexander Kozyrev 			} else {
650a96102c8SMichael Baum 				if ((++zip->ai & 7) == 0) {
651a96102c8SMichael Baum 					/* Invalidate consumed CQEs */
652a96102c8SMichael Baum 					idx = zip->ca;
653a96102c8SMichael Baum 					end = zip->na;
654a96102c8SMichael Baum 					while (idx != end) {
65502a6195cSAlexander Kozyrev 						(*rxq->cqes)[idx & cqe_mask].op_own =
656a96102c8SMichael Baum 							MLX5_CQE_INVALIDATE;
657a96102c8SMichael Baum 						++idx;
658a96102c8SMichael Baum 					}
659a96102c8SMichael Baum 					/*
660a96102c8SMichael Baum 					 * Increment consumer index to skip the number
661a96102c8SMichael Baum 					 * of CQEs consumed. Hardware leaves holes in
662a96102c8SMichael Baum 					 * the CQ ring for software use.
663a96102c8SMichael Baum 					 */
664a96102c8SMichael Baum 					zip->ca = zip->na;
665a96102c8SMichael Baum 					zip->na += 8;
666a96102c8SMichael Baum 				}
667a96102c8SMichael Baum 				if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
668a96102c8SMichael Baum 					/* Invalidate the rest */
669a96102c8SMichael Baum 					idx = zip->ca;
670a96102c8SMichael Baum 					end = zip->cq_ci;
671a96102c8SMichael Baum 
672a96102c8SMichael Baum 					while (idx != end) {
67302a6195cSAlexander Kozyrev 						(*rxq->cqes)[idx & cqe_mask].op_own =
674a96102c8SMichael Baum 							MLX5_CQE_INVALIDATE;
675a96102c8SMichael Baum 						++idx;
676a96102c8SMichael Baum 					}
677a96102c8SMichael Baum 					rxq->cq_ci = zip->cq_ci;
678a96102c8SMichael Baum 					zip->ai = 0;
679a96102c8SMichael Baum 				}
68002a6195cSAlexander Kozyrev 			}
681a96102c8SMichael Baum 		/*
682a96102c8SMichael Baum 		 * No compressed data, get next CQE and verify if it is
683a96102c8SMichael Baum 		 * compressed.
684a96102c8SMichael Baum 		 */
685a96102c8SMichael Baum 		} else {
686a96102c8SMichael Baum 			int8_t op_own;
687a96102c8SMichael Baum 			uint32_t cq_ci;
688a96102c8SMichael Baum 
68902a6195cSAlexander Kozyrev 			ret = (rxq->cqe_comp_layout) ?
69002a6195cSAlexander Kozyrev 				check_cqe_iteration(cqe, rxq->cqe_n, rxq->cq_ci) :
69102a6195cSAlexander Kozyrev 				check_cqe(cqe, cqe_n, rxq->cq_ci);
692a96102c8SMichael Baum 			if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
693a96102c8SMichael Baum 				if (unlikely(ret == MLX5_CQE_STATUS_ERR ||
694a96102c8SMichael Baum 					     rxq->err_state)) {
695aa67ed30SAlexander Kozyrev 					ret = mlx5_rx_err_handle(rxq, 0, 1, skip_cnt);
696aa67ed30SAlexander Kozyrev 					if (ret == MLX5_CQE_STATUS_HW_OWN)
697aa67ed30SAlexander Kozyrev 						return MLX5_ERROR_CQE_MASK;
698aa67ed30SAlexander Kozyrev 					if (ret == MLX5_RECOVERY_ERROR_RET ||
699aa67ed30SAlexander Kozyrev 						ret == MLX5_RECOVERY_COMPLETED_RET)
700aa67ed30SAlexander Kozyrev 						return MLX5_CRITICAL_ERROR_CQE_RET;
701ef296e8fSViacheslav Ovsiienko 					if (!mprq && ret == MLX5_RECOVERY_IGNORE_RET) {
702ef296e8fSViacheslav Ovsiienko 						*skip_cnt = 1;
703ef296e8fSViacheslav Ovsiienko 						++rxq->cq_ci;
704ef296e8fSViacheslav Ovsiienko 						return MLX5_ERROR_CQE_MASK;
705ef296e8fSViacheslav Ovsiienko 					}
706a96102c8SMichael Baum 				} else {
707a96102c8SMichael Baum 					return 0;
708a96102c8SMichael Baum 				}
709a96102c8SMichael Baum 			}
710a96102c8SMichael Baum 			/*
711a96102c8SMichael Baum 			 * Introduce the local variable to have queue cq_ci
712a96102c8SMichael Baum 			 * index in queue structure always consistent with
713a96102c8SMichael Baum 			 * actual CQE boundary (not pointing to the middle
714a96102c8SMichael Baum 			 * of compressed CQE session).
715a96102c8SMichael Baum 			 */
71602a6195cSAlexander Kozyrev 			cq_ci = rxq->cq_ci + !rxq->cqe_comp_layout;
717a96102c8SMichael Baum 			op_own = cqe->op_own;
718a96102c8SMichael Baum 			if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
719a96102c8SMichael Baum 				volatile struct mlx5_mini_cqe8 (*mc)[8] =
720a96102c8SMichael Baum 					(volatile struct mlx5_mini_cqe8 (*)[8])
721a96102c8SMichael Baum 					(uintptr_t)(&(*rxq->cqes)
72202a6195cSAlexander Kozyrev 						[cq_ci & cqe_mask].pkt_info);
723a96102c8SMichael Baum 
724a96102c8SMichael Baum 				/* Fix endianness. */
72502a6195cSAlexander Kozyrev 				zip->cqe_cnt = rxq->cqe_comp_layout ?
72602a6195cSAlexander Kozyrev 					(MLX5_CQE_NUM_MINIS(op_own) + 1U) :
72702a6195cSAlexander Kozyrev 					rte_be_to_cpu_32(cqe->byte_cnt);
728a96102c8SMichael Baum 				/*
729a96102c8SMichael Baum 				 * Current mini array position is the one
730a96102c8SMichael Baum 				 * returned by check_cqe64().
731a96102c8SMichael Baum 				 *
732a96102c8SMichael Baum 				 * If completion comprises several mini arrays,
733a96102c8SMichael Baum 				 * as a special case the second one is located
734a96102c8SMichael Baum 				 * 7 CQEs after the initial CQE instead of 8
735a96102c8SMichael Baum 				 * for subsequent ones.
736a96102c8SMichael Baum 				*/
737a96102c8SMichael Baum 				zip->ca = cq_ci;
738a96102c8SMichael Baum 				zip->na = zip->ca + 7;
739a96102c8SMichael Baum 				/* Compute the next non compressed CQE. */
740a96102c8SMichael Baum 				zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
741a96102c8SMichael Baum 				/* Get packet size to return. */
742a96102c8SMichael Baum 				len = rte_be_to_cpu_32((*mc)[0].byte_cnt &
743a96102c8SMichael Baum 							rxq->byte_mask);
744a96102c8SMichael Baum 				*mcqe = &(*mc)[0];
74502a6195cSAlexander Kozyrev 				if (rxq->cqe_comp_layout) {
74602a6195cSAlexander Kozyrev 					if (MLX5_CQE_NUM_MINIS(op_own))
74702a6195cSAlexander Kozyrev 						zip->ai = 1;
74802a6195cSAlexander Kozyrev 					else
74902a6195cSAlexander Kozyrev 						rxq->cq_ci = zip->cq_ci;
75002a6195cSAlexander Kozyrev 				} else {
751a96102c8SMichael Baum 					zip->ai = 1;
752a96102c8SMichael Baum 					/* Prefetch all to be invalidated */
753a96102c8SMichael Baum 					idx = zip->ca;
754a96102c8SMichael Baum 					end = zip->cq_ci;
755a96102c8SMichael Baum 					while (idx != end) {
75602a6195cSAlexander Kozyrev 						rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_mask]);
757a96102c8SMichael Baum 						++idx;
758a96102c8SMichael Baum 					}
75902a6195cSAlexander Kozyrev 				}
760a96102c8SMichael Baum 			} else {
76102a6195cSAlexander Kozyrev 				++rxq->cq_ci;
762a96102c8SMichael Baum 				len = rte_be_to_cpu_32(cqe->byte_cnt);
76302a6195cSAlexander Kozyrev 				if (rxq->cqe_comp_layout) {
76402a6195cSAlexander Kozyrev 					volatile struct mlx5_cqe *next;
76502a6195cSAlexander Kozyrev 
76602a6195cSAlexander Kozyrev 					next = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
76702a6195cSAlexander Kozyrev 					ret = check_cqe_iteration(next, rxq->cqe_n, rxq->cq_ci);
76802a6195cSAlexander Kozyrev 					if (ret != MLX5_CQE_STATUS_SW_OWN ||
76902a6195cSAlexander Kozyrev 					    MLX5_CQE_FORMAT(next->op_own) == MLX5_COMPRESSED)
77002a6195cSAlexander Kozyrev 						rte_memcpy(&rxq->title_cqe,
77102a6195cSAlexander Kozyrev 							   (const void *)(uintptr_t)cqe,
77202a6195cSAlexander Kozyrev 							   sizeof(struct mlx5_cqe));
77302a6195cSAlexander Kozyrev 				}
774a96102c8SMichael Baum 			}
775a96102c8SMichael Baum 		}
776a96102c8SMichael Baum 		if (unlikely(rxq->err_state)) {
777aa67ed30SAlexander Kozyrev 			if (rxq->err_state == MLX5_RXQ_ERR_STATE_IGNORE &&
778aa67ed30SAlexander Kozyrev 			    ret == MLX5_CQE_STATUS_SW_OWN) {
779aa67ed30SAlexander Kozyrev 				rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
780aa67ed30SAlexander Kozyrev 				return len & MLX5_ERROR_CQE_MASK;
781aa67ed30SAlexander Kozyrev 			}
78202a6195cSAlexander Kozyrev 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
783a96102c8SMichael Baum 			++rxq->stats.idropped;
784aa67ed30SAlexander Kozyrev 			(*skip_cnt) += mprq ? (len & MLX5_MPRQ_STRIDE_NUM_MASK) >>
785aa67ed30SAlexander Kozyrev 				MLX5_MPRQ_STRIDE_NUM_SHIFT : 1;
786a96102c8SMichael Baum 		} else {
787a96102c8SMichael Baum 			return len;
788a96102c8SMichael Baum 		}
789a96102c8SMichael Baum 	} while (1);
790a96102c8SMichael Baum }
791a96102c8SMichael Baum 
792a96102c8SMichael Baum /**
793a96102c8SMichael Baum  * Translate RX completion flags to offload flags.
794a96102c8SMichael Baum  *
795a96102c8SMichael Baum  * @param[in] cqe
796a96102c8SMichael Baum  *   Pointer to CQE.
797a96102c8SMichael Baum  *
798a96102c8SMichael Baum  * @return
799a96102c8SMichael Baum  *   Offload flags (ol_flags) for struct rte_mbuf.
800a96102c8SMichael Baum  */
801a96102c8SMichael Baum static inline uint32_t
802a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
803a96102c8SMichael Baum {
804a96102c8SMichael Baum 	uint32_t ol_flags = 0;
805a96102c8SMichael Baum 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
806a96102c8SMichael Baum 
807a96102c8SMichael Baum 	ol_flags =
808a96102c8SMichael Baum 		TRANSPOSE(flags,
809a96102c8SMichael Baum 			  MLX5_CQE_RX_L3_HDR_VALID,
810daa02b5cSOlivier Matz 			  RTE_MBUF_F_RX_IP_CKSUM_GOOD) |
811a96102c8SMichael Baum 		TRANSPOSE(flags,
812a96102c8SMichael Baum 			  MLX5_CQE_RX_L4_HDR_VALID,
813daa02b5cSOlivier Matz 			  RTE_MBUF_F_RX_L4_CKSUM_GOOD);
814a96102c8SMichael Baum 	return ol_flags;
815a96102c8SMichael Baum }
816a96102c8SMichael Baum 
817a96102c8SMichael Baum /**
818a96102c8SMichael Baum  * Fill in mbuf fields from RX completion flags.
819a96102c8SMichael Baum  * Note that pkt->ol_flags should be initialized outside of this function.
820a96102c8SMichael Baum  *
821a96102c8SMichael Baum  * @param rxq
822a96102c8SMichael Baum  *   Pointer to RX queue.
823a96102c8SMichael Baum  * @param pkt
824a96102c8SMichael Baum  *   mbuf to fill.
825a96102c8SMichael Baum  * @param cqe
826a96102c8SMichael Baum  *   CQE to process.
827a96102c8SMichael Baum  * @param rss_hash_res
828a96102c8SMichael Baum  *   Packet RSS Hash result.
829a96102c8SMichael Baum  */
830a96102c8SMichael Baum static inline void
831a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
832a96102c8SMichael Baum 	       volatile struct mlx5_cqe *cqe,
833a96102c8SMichael Baum 	       volatile struct mlx5_mini_cqe8 *mcqe)
834a96102c8SMichael Baum {
835a96102c8SMichael Baum 	/* Update packet information. */
836a96102c8SMichael Baum 	pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe, mcqe);
83725ed2ebfSViacheslav Ovsiienko 	pkt->port = unlikely(rxq->shared) ? cqe->user_index_low : rxq->port_id;
838a96102c8SMichael Baum 
839a96102c8SMichael Baum 	if (rxq->rss_hash) {
840a96102c8SMichael Baum 		uint32_t rss_hash_res = 0;
841a96102c8SMichael Baum 
842a96102c8SMichael Baum 		/* If compressed, take hash result from mini-CQE. */
843a96102c8SMichael Baum 		if (mcqe == NULL ||
844a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_HASH)
845a96102c8SMichael Baum 			rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
846a96102c8SMichael Baum 		else
847a96102c8SMichael Baum 			rss_hash_res = rte_be_to_cpu_32(mcqe->rx_hash_result);
848a96102c8SMichael Baum 		if (rss_hash_res) {
849a96102c8SMichael Baum 			pkt->hash.rss = rss_hash_res;
850daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
851a96102c8SMichael Baum 		}
852a96102c8SMichael Baum 	}
853a96102c8SMichael Baum 	if (rxq->mark) {
854a96102c8SMichael Baum 		uint32_t mark = 0;
855a96102c8SMichael Baum 
856a96102c8SMichael Baum 		/* If compressed, take flow tag from mini-CQE. */
857a96102c8SMichael Baum 		if (mcqe == NULL ||
858a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
859a96102c8SMichael Baum 			mark = cqe->sop_drop_qpn;
860a96102c8SMichael Baum 		else
861a96102c8SMichael Baum 			mark = ((mcqe->byte_cnt_flow & 0xff) << 8) |
862a96102c8SMichael Baum 				(mcqe->flow_tag_high << 16);
863a96102c8SMichael Baum 		if (MLX5_FLOW_MARK_IS_VALID(mark)) {
864daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_FDIR;
865a96102c8SMichael Baum 			if (mark != RTE_BE32(MLX5_FLOW_MARK_DEFAULT)) {
866fca8cba4SDavid Marchand 				pkt->ol_flags |= rxq->mark_flag;
867a96102c8SMichael Baum 				pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
868a96102c8SMichael Baum 			}
869a96102c8SMichael Baum 		}
870a96102c8SMichael Baum 	}
871a96102c8SMichael Baum 	if (rxq->dynf_meta) {
8726d5735c1SAlexander Kozyrev 		uint32_t meta = rte_be_to_cpu_32(cqe->flow_table_metadata) &
873a96102c8SMichael Baum 			rxq->flow_meta_port_mask;
874a96102c8SMichael Baum 
875a96102c8SMichael Baum 		if (meta) {
876a96102c8SMichael Baum 			pkt->ol_flags |= rxq->flow_meta_mask;
877a96102c8SMichael Baum 			*RTE_MBUF_DYNFIELD(pkt, rxq->flow_meta_offset,
878a96102c8SMichael Baum 						uint32_t *) = meta;
879a96102c8SMichael Baum 		}
880a96102c8SMichael Baum 	}
881a96102c8SMichael Baum 	if (rxq->csum)
882a96102c8SMichael Baum 		pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
883a96102c8SMichael Baum 	if (rxq->vlan_strip) {
884a96102c8SMichael Baum 		bool vlan_strip;
885a96102c8SMichael Baum 
886a96102c8SMichael Baum 		if (mcqe == NULL ||
887a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
888a96102c8SMichael Baum 			vlan_strip = cqe->hdr_type_etc &
889a96102c8SMichael Baum 				     RTE_BE16(MLX5_CQE_VLAN_STRIPPED);
890a96102c8SMichael Baum 		else
891a96102c8SMichael Baum 			vlan_strip = mcqe->hdr_type &
892a96102c8SMichael Baum 				     RTE_BE16(MLX5_CQE_VLAN_STRIPPED);
893a96102c8SMichael Baum 		if (vlan_strip) {
894daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
895a96102c8SMichael Baum 			pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
896a96102c8SMichael Baum 		}
897a96102c8SMichael Baum 	}
898a96102c8SMichael Baum 	if (rxq->hw_timestamp) {
899a96102c8SMichael Baum 		uint64_t ts = rte_be_to_cpu_64(cqe->timestamp);
900a96102c8SMichael Baum 
901a96102c8SMichael Baum 		if (rxq->rt_timestamp)
902a96102c8SMichael Baum 			ts = mlx5_txpp_convert_rx_ts(rxq->sh, ts);
903a96102c8SMichael Baum 		mlx5_timestamp_set(pkt, rxq->timestamp_offset, ts);
904a96102c8SMichael Baum 		pkt->ol_flags |= rxq->timestamp_rx_flag;
905a96102c8SMichael Baum 	}
906a96102c8SMichael Baum }
907a96102c8SMichael Baum 
908a96102c8SMichael Baum /**
909a96102c8SMichael Baum  * DPDK callback for RX.
910a96102c8SMichael Baum  *
911a96102c8SMichael Baum  * @param dpdk_rxq
912a96102c8SMichael Baum  *   Generic pointer to RX queue structure.
913a96102c8SMichael Baum  * @param[out] pkts
914a96102c8SMichael Baum  *   Array to store received packets.
915a96102c8SMichael Baum  * @param pkts_n
916a96102c8SMichael Baum  *   Maximum number of packets in array.
917a96102c8SMichael Baum  *
918a96102c8SMichael Baum  * @return
919a96102c8SMichael Baum  *   Number of packets successfully received (<= pkts_n).
920a96102c8SMichael Baum  */
921a96102c8SMichael Baum uint16_t
922a96102c8SMichael Baum mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
923a96102c8SMichael Baum {
924a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = dpdk_rxq;
92502a6195cSAlexander Kozyrev 	const uint32_t wqe_n = 1 << rxq->elts_n;
92602a6195cSAlexander Kozyrev 	const uint32_t wqe_mask = wqe_n - 1;
92702a6195cSAlexander Kozyrev 	const uint32_t cqe_n = 1 << rxq->cqe_n;
92802a6195cSAlexander Kozyrev 	const uint32_t cqe_mask = cqe_n - 1;
929a96102c8SMichael Baum 	const unsigned int sges_n = rxq->sges_n;
930a96102c8SMichael Baum 	struct rte_mbuf *pkt = NULL;
931a96102c8SMichael Baum 	struct rte_mbuf *seg = NULL;
932a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe =
93302a6195cSAlexander Kozyrev 		&(*rxq->cqes)[rxq->cq_ci & cqe_mask];
934a96102c8SMichael Baum 	unsigned int i = 0;
935a96102c8SMichael Baum 	unsigned int rq_ci = rxq->rq_ci << sges_n;
936a96102c8SMichael Baum 	int len = 0; /* keep its value across iterations. */
937a96102c8SMichael Baum 
938a96102c8SMichael Baum 	while (pkts_n) {
939aa67ed30SAlexander Kozyrev 		uint16_t skip_cnt;
94002a6195cSAlexander Kozyrev 		unsigned int idx = rq_ci & wqe_mask;
941a96102c8SMichael Baum 		volatile struct mlx5_wqe_data_seg *wqe =
942a96102c8SMichael Baum 			&((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
943a96102c8SMichael Baum 		struct rte_mbuf *rep = (*rxq->elts)[idx];
944a96102c8SMichael Baum 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
945a96102c8SMichael Baum 
946a96102c8SMichael Baum 		if (pkt)
947a96102c8SMichael Baum 			NEXT(seg) = rep;
948a96102c8SMichael Baum 		seg = rep;
949a96102c8SMichael Baum 		rte_prefetch0(seg);
950a96102c8SMichael Baum 		rte_prefetch0(cqe);
951a96102c8SMichael Baum 		rte_prefetch0(wqe);
952a96102c8SMichael Baum 		/* Allocate the buf from the same pool. */
953a96102c8SMichael Baum 		rep = rte_mbuf_raw_alloc(seg->pool);
954a96102c8SMichael Baum 		if (unlikely(rep == NULL)) {
955a96102c8SMichael Baum 			++rxq->stats.rx_nombuf;
956a96102c8SMichael Baum 			if (!pkt) {
957a96102c8SMichael Baum 				/*
958a96102c8SMichael Baum 				 * no buffers before we even started,
959a96102c8SMichael Baum 				 * bail out silently.
960a96102c8SMichael Baum 				 */
961a96102c8SMichael Baum 				break;
962a96102c8SMichael Baum 			}
963a96102c8SMichael Baum 			while (pkt != seg) {
964a96102c8SMichael Baum 				MLX5_ASSERT(pkt != (*rxq->elts)[idx]);
965a96102c8SMichael Baum 				rep = NEXT(pkt);
966a96102c8SMichael Baum 				NEXT(pkt) = NULL;
967a96102c8SMichael Baum 				NB_SEGS(pkt) = 1;
968a96102c8SMichael Baum 				rte_mbuf_raw_free(pkt);
969a96102c8SMichael Baum 				pkt = rep;
970a96102c8SMichael Baum 			}
971a96102c8SMichael Baum 			rq_ci >>= sges_n;
972a96102c8SMichael Baum 			++rq_ci;
973a96102c8SMichael Baum 			rq_ci <<= sges_n;
974a96102c8SMichael Baum 			break;
975a96102c8SMichael Baum 		}
976a96102c8SMichael Baum 		if (!pkt) {
97702a6195cSAlexander Kozyrev 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
97802a6195cSAlexander Kozyrev 			len = mlx5_rx_poll_len(rxq, cqe, cqe_n, cqe_mask, &mcqe, &skip_cnt, false);
979aa67ed30SAlexander Kozyrev 			if (unlikely(len & MLX5_ERROR_CQE_MASK)) {
980ef296e8fSViacheslav Ovsiienko 				/* We drop packets with non-critical errors */
981a96102c8SMichael Baum 				rte_mbuf_raw_free(rep);
982ef296e8fSViacheslav Ovsiienko 				if (len == MLX5_CRITICAL_ERROR_CQE_RET) {
98360b254e3SMatan Azrad 					rq_ci = rxq->rq_ci << sges_n;
984a96102c8SMichael Baum 					break;
985a96102c8SMichael Baum 				}
986ef296e8fSViacheslav Ovsiienko 				/* Skip specified amount of error CQEs packets */
987aa67ed30SAlexander Kozyrev 				rq_ci >>= sges_n;
988aa67ed30SAlexander Kozyrev 				rq_ci += skip_cnt;
989aa67ed30SAlexander Kozyrev 				rq_ci <<= sges_n;
990ef296e8fSViacheslav Ovsiienko 				MLX5_ASSERT(!pkt);
991ef296e8fSViacheslav Ovsiienko 				continue;
992aa67ed30SAlexander Kozyrev 			}
993aa67ed30SAlexander Kozyrev 			if (len == 0) {
994aa67ed30SAlexander Kozyrev 				rte_mbuf_raw_free(rep);
995aa67ed30SAlexander Kozyrev 				break;
996aa67ed30SAlexander Kozyrev 			}
997a96102c8SMichael Baum 			pkt = seg;
998a96102c8SMichael Baum 			MLX5_ASSERT(len >= (rxq->crc_present << 2));
999daa02b5cSOlivier Matz 			pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
100002a6195cSAlexander Kozyrev 			if (rxq->cqe_comp_layout && mcqe)
100102a6195cSAlexander Kozyrev 				cqe = &rxq->title_cqe;
1002a96102c8SMichael Baum 			rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1003a96102c8SMichael Baum 			if (rxq->crc_present)
1004a96102c8SMichael Baum 				len -= RTE_ETHER_CRC_LEN;
1005a96102c8SMichael Baum 			PKT_LEN(pkt) = len;
1006a96102c8SMichael Baum 			if (cqe->lro_num_seg > 1) {
1007a96102c8SMichael Baum 				mlx5_lro_update_hdr
1008a96102c8SMichael Baum 					(rte_pktmbuf_mtod(pkt, uint8_t *), cqe,
1009a96102c8SMichael Baum 					 mcqe, rxq, len);
1010daa02b5cSOlivier Matz 				pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1011a96102c8SMichael Baum 				pkt->tso_segsz = len / cqe->lro_num_seg;
1012a96102c8SMichael Baum 			}
1013a96102c8SMichael Baum 		}
1014a96102c8SMichael Baum 		DATA_LEN(rep) = DATA_LEN(seg);
1015a96102c8SMichael Baum 		PKT_LEN(rep) = PKT_LEN(seg);
1016a96102c8SMichael Baum 		SET_DATA_OFF(rep, DATA_OFF(seg));
1017a96102c8SMichael Baum 		PORT(rep) = PORT(seg);
1018a96102c8SMichael Baum 		(*rxq->elts)[idx] = rep;
1019a96102c8SMichael Baum 		/*
1020a96102c8SMichael Baum 		 * Fill NIC descriptor with the new buffer. The lkey and size
1021a96102c8SMichael Baum 		 * of the buffers are already known, only the buffer address
1022a96102c8SMichael Baum 		 * changes.
1023a96102c8SMichael Baum 		 */
1024a96102c8SMichael Baum 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
1025a96102c8SMichael Baum 		/* If there's only one MR, no need to replace LKey in WQE. */
1026a96102c8SMichael Baum 		if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1027a96102c8SMichael Baum 			wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
1028a96102c8SMichael Baum 		if (len > DATA_LEN(seg)) {
1029a96102c8SMichael Baum 			len -= DATA_LEN(seg);
1030a96102c8SMichael Baum 			++NB_SEGS(pkt);
1031a96102c8SMichael Baum 			++rq_ci;
1032a96102c8SMichael Baum 			continue;
1033a96102c8SMichael Baum 		}
1034a96102c8SMichael Baum 		DATA_LEN(seg) = len;
1035a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1036a96102c8SMichael Baum 		/* Increment bytes counter. */
1037a96102c8SMichael Baum 		rxq->stats.ibytes += PKT_LEN(pkt);
1038a96102c8SMichael Baum #endif
1039a96102c8SMichael Baum 		/* Return packet. */
1040a96102c8SMichael Baum 		*(pkts++) = pkt;
1041a96102c8SMichael Baum 		pkt = NULL;
1042a96102c8SMichael Baum 		--pkts_n;
1043a96102c8SMichael Baum 		++i;
1044a96102c8SMichael Baum 		/* Align consumer index to the next stride. */
1045a96102c8SMichael Baum 		rq_ci >>= sges_n;
1046a96102c8SMichael Baum 		++rq_ci;
1047a96102c8SMichael Baum 		rq_ci <<= sges_n;
1048a96102c8SMichael Baum 	}
1049a96102c8SMichael Baum 	if (unlikely(i == 0 && ((rq_ci >> sges_n) == rxq->rq_ci)))
1050a96102c8SMichael Baum 		return 0;
1051a96102c8SMichael Baum 	/* Update the consumer index. */
1052a96102c8SMichael Baum 	rxq->rq_ci = rq_ci >> sges_n;
1053a96102c8SMichael Baum 	rte_io_wmb();
1054a96102c8SMichael Baum 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1055a96102c8SMichael Baum 	rte_io_wmb();
1056a96102c8SMichael Baum 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1057a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1058a96102c8SMichael Baum 	/* Increment packets counter. */
1059a96102c8SMichael Baum 	rxq->stats.ipackets += i;
1060a96102c8SMichael Baum #endif
1061a96102c8SMichael Baum 	return i;
1062a96102c8SMichael Baum }
1063a96102c8SMichael Baum 
1064a96102c8SMichael Baum /**
1065a96102c8SMichael Baum  * Update LRO packet TCP header.
1066a96102c8SMichael Baum  * The HW LRO feature doesn't update the TCP header after coalescing the
1067a96102c8SMichael Baum  * TCP segments but supplies information in CQE to fill it by SW.
1068a96102c8SMichael Baum  *
1069a96102c8SMichael Baum  * @param tcp
1070a96102c8SMichael Baum  *   Pointer to the TCP header.
1071a96102c8SMichael Baum  * @param cqe
1072a96102c8SMichael Baum  *   Pointer to the completion entry.
1073a96102c8SMichael Baum  * @param phcsum
1074a96102c8SMichael Baum  *   The L3 pseudo-header checksum.
1075a96102c8SMichael Baum  */
1076a96102c8SMichael Baum static inline void
1077a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
1078a96102c8SMichael Baum 			volatile struct mlx5_cqe *__rte_restrict cqe,
1079a96102c8SMichael Baum 			uint32_t phcsum, uint8_t l4_type)
1080a96102c8SMichael Baum {
1081a96102c8SMichael Baum 	/*
1082a96102c8SMichael Baum 	 * The HW calculates only the TCP payload checksum, need to complete
1083a96102c8SMichael Baum 	 * the TCP header checksum and the L3 pseudo-header checksum.
1084a96102c8SMichael Baum 	 */
1085a96102c8SMichael Baum 	uint32_t csum = phcsum + cqe->csum;
1086a96102c8SMichael Baum 
1087a96102c8SMichael Baum 	if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK ||
1088a96102c8SMichael Baum 	    l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) {
1089a96102c8SMichael Baum 		tcp->tcp_flags |= RTE_TCP_ACK_FLAG;
1090a96102c8SMichael Baum 		tcp->recv_ack = cqe->lro_ack_seq_num;
1091a96102c8SMichael Baum 		tcp->rx_win = cqe->lro_tcp_win;
1092a96102c8SMichael Baum 	}
1093a96102c8SMichael Baum 	if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK)
1094a96102c8SMichael Baum 		tcp->tcp_flags |= RTE_TCP_PSH_FLAG;
1095a96102c8SMichael Baum 	tcp->cksum = 0;
1096a96102c8SMichael Baum 	csum += rte_raw_cksum(tcp, (tcp->data_off >> 4) * 4);
1097a96102c8SMichael Baum 	csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
1098776209c4SHeng Jiang 	csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
1099a96102c8SMichael Baum 	csum = (~csum) & 0xffff;
1100a96102c8SMichael Baum 	if (csum == 0)
1101a96102c8SMichael Baum 		csum = 0xffff;
1102a96102c8SMichael Baum 	tcp->cksum = csum;
1103a96102c8SMichael Baum }
1104a96102c8SMichael Baum 
1105a96102c8SMichael Baum /**
1106a96102c8SMichael Baum  * Update LRO packet headers.
1107a96102c8SMichael Baum  * The HW LRO feature doesn't update the L3/TCP headers after coalescing the
1108a96102c8SMichael Baum  * TCP segments but supply information in CQE to fill it by SW.
1109a96102c8SMichael Baum  *
1110a96102c8SMichael Baum  * @param padd
1111a96102c8SMichael Baum  *   The packet address.
1112a96102c8SMichael Baum  * @param cqe
1113a96102c8SMichael Baum  *   Pointer to the completion entry.
1114a96102c8SMichael Baum  * @param len
1115a96102c8SMichael Baum  *   The packet length.
1116a96102c8SMichael Baum  */
1117a96102c8SMichael Baum static inline void
1118a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
1119a96102c8SMichael Baum 		    volatile struct mlx5_cqe *__rte_restrict cqe,
1120a96102c8SMichael Baum 		    volatile struct mlx5_mini_cqe8 *mcqe,
1121a96102c8SMichael Baum 		    struct mlx5_rxq_data *rxq, uint32_t len)
1122a96102c8SMichael Baum {
1123a96102c8SMichael Baum 	union {
1124a96102c8SMichael Baum 		struct rte_ether_hdr *eth;
1125a96102c8SMichael Baum 		struct rte_vlan_hdr *vlan;
1126a96102c8SMichael Baum 		struct rte_ipv4_hdr *ipv4;
1127a96102c8SMichael Baum 		struct rte_ipv6_hdr *ipv6;
1128a96102c8SMichael Baum 		struct rte_tcp_hdr *tcp;
1129a96102c8SMichael Baum 		uint8_t *hdr;
1130a96102c8SMichael Baum 	} h = {
1131a96102c8SMichael Baum 		.hdr = padd,
1132a96102c8SMichael Baum 	};
1133a96102c8SMichael Baum 	uint16_t proto = h.eth->ether_type;
1134a96102c8SMichael Baum 	uint32_t phcsum;
1135a96102c8SMichael Baum 	uint8_t l4_type;
1136a96102c8SMichael Baum 
1137a96102c8SMichael Baum 	h.eth++;
1138a96102c8SMichael Baum 	while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
1139a96102c8SMichael Baum 	       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
1140a96102c8SMichael Baum 		proto = h.vlan->eth_proto;
1141a96102c8SMichael Baum 		h.vlan++;
1142a96102c8SMichael Baum 	}
1143a96102c8SMichael Baum 	if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
1144a96102c8SMichael Baum 		h.ipv4->time_to_live = cqe->lro_min_ttl;
1145a96102c8SMichael Baum 		h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd));
1146a96102c8SMichael Baum 		h.ipv4->hdr_checksum = 0;
1147a96102c8SMichael Baum 		h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4);
1148a96102c8SMichael Baum 		phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0);
1149a96102c8SMichael Baum 		h.ipv4++;
1150a96102c8SMichael Baum 	} else {
1151a96102c8SMichael Baum 		h.ipv6->hop_limits = cqe->lro_min_ttl;
1152a96102c8SMichael Baum 		h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) -
1153a96102c8SMichael Baum 						       sizeof(*h.ipv6));
1154a96102c8SMichael Baum 		phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0);
1155a96102c8SMichael Baum 		h.ipv6++;
1156a96102c8SMichael Baum 	}
1157a96102c8SMichael Baum 	if (mcqe == NULL ||
1158a96102c8SMichael Baum 	    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
1159a96102c8SMichael Baum 		l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) &
1160a96102c8SMichael Baum 			   MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1161a96102c8SMichael Baum 	else
1162a96102c8SMichael Baum 		l4_type = (rte_be_to_cpu_16(mcqe->hdr_type) &
1163a96102c8SMichael Baum 			   MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1164a96102c8SMichael Baum 	mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum, l4_type);
1165a96102c8SMichael Baum }
1166a96102c8SMichael Baum 
1167a96102c8SMichael Baum void
1168a96102c8SMichael Baum mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
1169a96102c8SMichael Baum {
1170a96102c8SMichael Baum 	mlx5_mprq_buf_free_cb(NULL, buf);
1171a96102c8SMichael Baum }
1172a96102c8SMichael Baum 
1173a96102c8SMichael Baum /**
1174a96102c8SMichael Baum  * DPDK callback for RX with Multi-Packet RQ support.
1175a96102c8SMichael Baum  *
1176a96102c8SMichael Baum  * @param dpdk_rxq
1177a96102c8SMichael Baum  *   Generic pointer to RX queue structure.
1178a96102c8SMichael Baum  * @param[out] pkts
1179a96102c8SMichael Baum  *   Array to store received packets.
1180a96102c8SMichael Baum  * @param pkts_n
1181a96102c8SMichael Baum  *   Maximum number of packets in array.
1182a96102c8SMichael Baum  *
1183a96102c8SMichael Baum  * @return
1184a96102c8SMichael Baum  *   Number of packets successfully received (<= pkts_n).
1185a96102c8SMichael Baum  */
1186a96102c8SMichael Baum uint16_t
1187a96102c8SMichael Baum mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1188a96102c8SMichael Baum {
1189a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = dpdk_rxq;
11900947ed38SMichael Baum 	const uint32_t strd_n = RTE_BIT32(rxq->log_strd_num);
11910947ed38SMichael Baum 	const uint32_t strd_sz = RTE_BIT32(rxq->log_strd_sz);
119202a6195cSAlexander Kozyrev 	const uint32_t cqe_n = 1 << rxq->cqe_n;
119302a6195cSAlexander Kozyrev 	const uint32_t cq_mask = cqe_n - 1;
119402a6195cSAlexander Kozyrev 	const uint32_t wqe_n = 1 << rxq->elts_n;
119502a6195cSAlexander Kozyrev 	const uint32_t wq_mask = wqe_n - 1;
1196a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1197a96102c8SMichael Baum 	unsigned int i = 0;
1198a96102c8SMichael Baum 	uint32_t rq_ci = rxq->rq_ci;
1199a96102c8SMichael Baum 	uint16_t consumed_strd = rxq->consumed_strd;
1200a96102c8SMichael Baum 	struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1201a96102c8SMichael Baum 
1202a96102c8SMichael Baum 	while (i < pkts_n) {
1203a96102c8SMichael Baum 		struct rte_mbuf *pkt;
1204a96102c8SMichael Baum 		int ret;
1205a96102c8SMichael Baum 		uint32_t len;
1206a96102c8SMichael Baum 		uint16_t strd_cnt;
1207a96102c8SMichael Baum 		uint16_t strd_idx;
1208a96102c8SMichael Baum 		uint32_t byte_cnt;
1209aa67ed30SAlexander Kozyrev 		uint16_t skip_cnt;
1210a96102c8SMichael Baum 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1211a96102c8SMichael Baum 		enum mlx5_rqx_code rxq_code;
1212a96102c8SMichael Baum 
1213a96102c8SMichael Baum 		if (consumed_strd == strd_n) {
1214a96102c8SMichael Baum 			/* Replace WQE if the buffer is still in use. */
1215a96102c8SMichael Baum 			mprq_buf_replace(rxq, rq_ci & wq_mask);
1216a96102c8SMichael Baum 			/* Advance to the next WQE. */
1217a96102c8SMichael Baum 			consumed_strd = 0;
1218a96102c8SMichael Baum 			++rq_ci;
1219a96102c8SMichael Baum 			buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1220a96102c8SMichael Baum 		}
1221a96102c8SMichael Baum 		cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
122202a6195cSAlexander Kozyrev 		ret = mlx5_rx_poll_len(rxq, cqe, cqe_n, cq_mask, &mcqe, &skip_cnt, true);
1223aa67ed30SAlexander Kozyrev 		if (unlikely(ret & MLX5_ERROR_CQE_MASK)) {
1224aa67ed30SAlexander Kozyrev 			if (ret == MLX5_CRITICAL_ERROR_CQE_RET) {
122560b254e3SMatan Azrad 				rq_ci = rxq->rq_ci;
122660b254e3SMatan Azrad 				consumed_strd = rxq->consumed_strd;
122760b254e3SMatan Azrad 				break;
122860b254e3SMatan Azrad 			}
1229aa67ed30SAlexander Kozyrev 			consumed_strd += skip_cnt;
1230aa67ed30SAlexander Kozyrev 			while (consumed_strd >= strd_n) {
1231aa67ed30SAlexander Kozyrev 				/* Replace WQE if the buffer is still in use. */
1232aa67ed30SAlexander Kozyrev 				mprq_buf_replace(rxq, rq_ci & wq_mask);
1233aa67ed30SAlexander Kozyrev 				/* Advance to the next WQE. */
1234aa67ed30SAlexander Kozyrev 				consumed_strd -= strd_n;
1235aa67ed30SAlexander Kozyrev 				++rq_ci;
1236aa67ed30SAlexander Kozyrev 				buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1237aa67ed30SAlexander Kozyrev 			}
1238aa67ed30SAlexander Kozyrev 			cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1239aa67ed30SAlexander Kozyrev 		}
1240aa67ed30SAlexander Kozyrev 		if (ret == 0)
1241aa67ed30SAlexander Kozyrev 			break;
1242a96102c8SMichael Baum 		byte_cnt = ret;
1243a96102c8SMichael Baum 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1244a96102c8SMichael Baum 		MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1245a96102c8SMichael Baum 		if (rxq->crc_present)
1246a96102c8SMichael Baum 			len -= RTE_ETHER_CRC_LEN;
1247a96102c8SMichael Baum 		if (mcqe &&
1248a96102c8SMichael Baum 		    rxq->mcqe_format == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
1249a96102c8SMichael Baum 			strd_cnt = (len / strd_sz) + !!(len % strd_sz);
1250a96102c8SMichael Baum 		else
1251a96102c8SMichael Baum 			strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
1252a96102c8SMichael Baum 				   MLX5_MPRQ_STRIDE_NUM_SHIFT;
1253a96102c8SMichael Baum 		MLX5_ASSERT(strd_cnt);
1254a96102c8SMichael Baum 		consumed_strd += strd_cnt;
1255a96102c8SMichael Baum 		if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
1256a96102c8SMichael Baum 			continue;
125702a6195cSAlexander Kozyrev 		if (rxq->cqe_comp_layout && mcqe)
125802a6195cSAlexander Kozyrev 			cqe = &rxq->title_cqe;
1259a96102c8SMichael Baum 		strd_idx = rte_be_to_cpu_16(mcqe == NULL ?
1260a96102c8SMichael Baum 					cqe->wqe_counter :
1261a96102c8SMichael Baum 					mcqe->stride_idx);
1262a96102c8SMichael Baum 		MLX5_ASSERT(strd_idx < strd_n);
1263a96102c8SMichael Baum 		MLX5_ASSERT(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) &
1264a96102c8SMichael Baum 			    wq_mask));
1265a96102c8SMichael Baum 		pkt = rte_pktmbuf_alloc(rxq->mp);
1266a96102c8SMichael Baum 		if (unlikely(pkt == NULL)) {
1267a96102c8SMichael Baum 			++rxq->stats.rx_nombuf;
1268a96102c8SMichael Baum 			break;
1269a96102c8SMichael Baum 		}
1270a96102c8SMichael Baum 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1271a96102c8SMichael Baum 		MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1272a96102c8SMichael Baum 		if (rxq->crc_present)
1273a96102c8SMichael Baum 			len -= RTE_ETHER_CRC_LEN;
1274a96102c8SMichael Baum 		rxq_code = mprq_buf_to_pkt(rxq, pkt, len, buf,
1275a96102c8SMichael Baum 					   strd_idx, strd_cnt);
1276a96102c8SMichael Baum 		if (unlikely(rxq_code != MLX5_RXQ_CODE_EXIT)) {
1277a96102c8SMichael Baum 			rte_pktmbuf_free_seg(pkt);
1278a96102c8SMichael Baum 			if (rxq_code == MLX5_RXQ_CODE_DROPPED) {
1279a96102c8SMichael Baum 				++rxq->stats.idropped;
1280a96102c8SMichael Baum 				continue;
1281a96102c8SMichael Baum 			}
1282a96102c8SMichael Baum 			if (rxq_code == MLX5_RXQ_CODE_NOMBUF) {
1283a96102c8SMichael Baum 				++rxq->stats.rx_nombuf;
1284a96102c8SMichael Baum 				break;
1285a96102c8SMichael Baum 			}
1286a96102c8SMichael Baum 		}
1287a96102c8SMichael Baum 		rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1288a96102c8SMichael Baum 		if (cqe->lro_num_seg > 1) {
1289a96102c8SMichael Baum 			mlx5_lro_update_hdr(rte_pktmbuf_mtod(pkt, uint8_t *),
1290a96102c8SMichael Baum 					    cqe, mcqe, rxq, len);
1291daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1292a96102c8SMichael Baum 			pkt->tso_segsz = len / cqe->lro_num_seg;
1293a96102c8SMichael Baum 		}
1294a96102c8SMichael Baum 		PKT_LEN(pkt) = len;
1295a96102c8SMichael Baum 		PORT(pkt) = rxq->port_id;
1296a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1297a96102c8SMichael Baum 		/* Increment bytes counter. */
1298a96102c8SMichael Baum 		rxq->stats.ibytes += PKT_LEN(pkt);
1299a96102c8SMichael Baum #endif
1300a96102c8SMichael Baum 		/* Return packet. */
1301a96102c8SMichael Baum 		*(pkts++) = pkt;
1302a96102c8SMichael Baum 		++i;
1303a96102c8SMichael Baum 	}
1304a96102c8SMichael Baum 	/* Update the consumer indexes. */
1305a96102c8SMichael Baum 	rxq->consumed_strd = consumed_strd;
1306a96102c8SMichael Baum 	rte_io_wmb();
1307a96102c8SMichael Baum 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1308a96102c8SMichael Baum 	if (rq_ci != rxq->rq_ci) {
1309a96102c8SMichael Baum 		rxq->rq_ci = rq_ci;
1310a96102c8SMichael Baum 		rte_io_wmb();
1311a96102c8SMichael Baum 		*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1312a96102c8SMichael Baum 	}
1313a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1314a96102c8SMichael Baum 	/* Increment packets counter. */
1315a96102c8SMichael Baum 	rxq->stats.ipackets += i;
1316a96102c8SMichael Baum #endif
1317a96102c8SMichael Baum 	return i;
1318a96102c8SMichael Baum }
1319a96102c8SMichael Baum 
13205c9f3294SSpike Du int
13215c9f3294SSpike Du mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev,
13225c9f3294SSpike Du 			uint16_t *queue_id, uint8_t *lwm)
13235c9f3294SSpike Du {
13245c9f3294SSpike Du 	struct mlx5_priv *priv = dev->data->dev_private;
13255c9f3294SSpike Du 	unsigned int rxq_id, found = 0, n;
13265c9f3294SSpike Du 	struct mlx5_rxq_priv *rxq;
13275c9f3294SSpike Du 
13285c9f3294SSpike Du 	if (!queue_id)
13295c9f3294SSpike Du 		return -EINVAL;
13305c9f3294SSpike Du 	/* Query all the Rx queues of the port in a circular way. */
13315c9f3294SSpike Du 	for (rxq_id = *queue_id, n = 0; n < priv->rxqs_n; n++) {
13325c9f3294SSpike Du 		rxq = mlx5_rxq_get(dev, rxq_id);
13335c9f3294SSpike Du 		if (rxq && rxq->lwm_event_pending) {
13345c9f3294SSpike Du 			pthread_mutex_lock(&priv->sh->lwm_config_lock);
13355c9f3294SSpike Du 			rxq->lwm_event_pending = 0;
13365c9f3294SSpike Du 			pthread_mutex_unlock(&priv->sh->lwm_config_lock);
13375c9f3294SSpike Du 			*queue_id = rxq_id;
13385c9f3294SSpike Du 			found = 1;
13395c9f3294SSpike Du 			if (lwm)
13405c9f3294SSpike Du 				*lwm =  mlx5_rxq_lwm_to_percentage(rxq);
13415c9f3294SSpike Du 			break;
13425c9f3294SSpike Du 		}
13435c9f3294SSpike Du 		rxq_id = (rxq_id + 1) % priv->rxqs_n;
13445c9f3294SSpike Du 	}
13455c9f3294SSpike Du 	return found;
13465c9f3294SSpike Du }
13475c9f3294SSpike Du 
134825025da3SSpike Du /**
134925025da3SSpike Du  * Rte interrupt handler for LWM event.
135025025da3SSpike Du  * It first checks if the event arrives, if so process the callback for
135125025da3SSpike Du  * RTE_ETH_EVENT_RX_LWM.
135225025da3SSpike Du  *
135325025da3SSpike Du  * @param args
135425025da3SSpike Du  *   Generic pointer to mlx5_priv.
135525025da3SSpike Du  */
135625025da3SSpike Du void
135725025da3SSpike Du mlx5_dev_interrupt_handler_lwm(void *args)
135825025da3SSpike Du {
135925025da3SSpike Du 	struct mlx5_priv *priv = args;
136025025da3SSpike Du 	struct mlx5_rxq_priv *rxq;
136125025da3SSpike Du 	struct rte_eth_dev *dev;
136225025da3SSpike Du 	int ret, rxq_idx = 0, port_id = 0;
136325025da3SSpike Du 
136425025da3SSpike Du 	ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
136525025da3SSpike Du 	if (unlikely(ret < 0)) {
136625025da3SSpike Du 		DRV_LOG(WARNING, "Cannot get LWM event context.");
136725025da3SSpike Du 		return;
136825025da3SSpike Du 	}
136925025da3SSpike Du 	DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
137025025da3SSpike Du 		port_id, rxq_idx);
137125025da3SSpike Du 	dev = &rte_eth_devices[port_id];
137225025da3SSpike Du 	rxq = mlx5_rxq_get(dev, rxq_idx);
137325025da3SSpike Du 	if (rxq) {
137425025da3SSpike Du 		pthread_mutex_lock(&priv->sh->lwm_config_lock);
137525025da3SSpike Du 		rxq->lwm_event_pending = 1;
137625025da3SSpike Du 		pthread_mutex_unlock(&priv->sh->lwm_config_lock);
137725025da3SSpike Du 	}
137825025da3SSpike Du 	rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
137925025da3SSpike Du }
13805c9f3294SSpike Du 
13815c9f3294SSpike Du /**
13825c9f3294SSpike Du  * DPDK callback to arm an Rx queue LWM(limit watermark) event.
13835c9f3294SSpike Du  * While the Rx queue fullness reaches the LWM limit, the driver catches
13845c9f3294SSpike Du  * an HW event and invokes the user event callback.
13855c9f3294SSpike Du  * After the last event handling, the user needs to call this API again
13865c9f3294SSpike Du  * to arm an additional event.
13875c9f3294SSpike Du  *
13885c9f3294SSpike Du  * @param dev
13895c9f3294SSpike Du  *   Pointer to the device structure.
13905c9f3294SSpike Du  * @param[in] rx_queue_id
13915c9f3294SSpike Du  *   Rx queue identificator.
13925c9f3294SSpike Du  * @param[in] lwm
13935c9f3294SSpike Du  *   The LWM value, is defined by a percentage of the Rx queue size.
13945c9f3294SSpike Du  *   [1-99] to set a new LWM (update the old value).
13955c9f3294SSpike Du  *   0 to unarm the event.
13965c9f3294SSpike Du  *
13975c9f3294SSpike Du  * @return
13985c9f3294SSpike Du  *   0 : operation success.
13995c9f3294SSpike Du  *   Otherwise:
14005c9f3294SSpike Du  *   - ENOMEM - not enough memory to create LWM event channel.
14015c9f3294SSpike Du  *   - EINVAL - the input Rxq is not created by devx.
14025c9f3294SSpike Du  *   - E2BIG  - lwm is bigger than 99.
14035c9f3294SSpike Du  */
14045c9f3294SSpike Du int
14055c9f3294SSpike Du mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
14065c9f3294SSpike Du 		      uint8_t lwm)
14075c9f3294SSpike Du {
14085c9f3294SSpike Du 	struct mlx5_priv *priv = dev->data->dev_private;
14095c9f3294SSpike Du 	uint16_t port_id = PORT_ID(priv);
14105c9f3294SSpike Du 	struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id);
14115c9f3294SSpike Du 	uint16_t event_nums[1] = {MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED};
14125c9f3294SSpike Du 	struct mlx5_rxq_data *rxq_data;
14135c9f3294SSpike Du 	uint32_t wqe_cnt;
14145c9f3294SSpike Du 	uint64_t cookie;
14155c9f3294SSpike Du 	int ret = 0;
14165c9f3294SSpike Du 
14175c9f3294SSpike Du 	if (!rxq) {
14185c9f3294SSpike Du 		rte_errno = EINVAL;
14195c9f3294SSpike Du 		return -rte_errno;
14205c9f3294SSpike Du 	}
14215c9f3294SSpike Du 	rxq_data = &rxq->ctrl->rxq;
14225c9f3294SSpike Du 	/* Ensure the Rq is created by devx. */
14235c9f3294SSpike Du 	if (priv->obj_ops.rxq_obj_new != devx_obj_ops.rxq_obj_new) {
14245c9f3294SSpike Du 		rte_errno = EINVAL;
14255c9f3294SSpike Du 		return -rte_errno;
14265c9f3294SSpike Du 	}
14275c9f3294SSpike Du 	if (lwm > 99) {
14285c9f3294SSpike Du 		DRV_LOG(WARNING, "Too big LWM configuration.");
14295c9f3294SSpike Du 		rte_errno = E2BIG;
14305c9f3294SSpike Du 		return -rte_errno;
14315c9f3294SSpike Du 	}
14325c9f3294SSpike Du 	/* Start config LWM. */
14335c9f3294SSpike Du 	pthread_mutex_lock(&priv->sh->lwm_config_lock);
14345c9f3294SSpike Du 	if (rxq->lwm == 0 && lwm == 0) {
14355c9f3294SSpike Du 		/* Both old/new values are 0, do nothing. */
14365c9f3294SSpike Du 		ret = 0;
14375c9f3294SSpike Du 		goto end;
14385c9f3294SSpike Du 	}
14395c9f3294SSpike Du 	wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
14405c9f3294SSpike Du 	if (lwm) {
14415c9f3294SSpike Du 		if (!priv->sh->devx_channel_lwm) {
14425c9f3294SSpike Du 			ret = mlx5_lwm_setup(priv);
14435c9f3294SSpike Du 			if (ret) {
14445c9f3294SSpike Du 				DRV_LOG(WARNING,
14455c9f3294SSpike Du 					"Failed to create shared_lwm.");
14465c9f3294SSpike Du 				rte_errno = ENOMEM;
14475c9f3294SSpike Du 				ret = -rte_errno;
14485c9f3294SSpike Du 				goto end;
14495c9f3294SSpike Du 			}
14505c9f3294SSpike Du 		}
14515c9f3294SSpike Du 		if (!rxq->lwm_devx_subscribed) {
14525c9f3294SSpike Du 			cookie = ((uint32_t)
14535c9f3294SSpike Du 				  (port_id << LWM_COOKIE_PORTID_OFFSET)) |
14545c9f3294SSpike Du 				(rx_queue_id << LWM_COOKIE_RXQID_OFFSET);
14555c9f3294SSpike Du 			ret = mlx5_os_devx_subscribe_devx_event
14565c9f3294SSpike Du 				(priv->sh->devx_channel_lwm,
14575c9f3294SSpike Du 				 rxq->devx_rq.rq->obj,
14585c9f3294SSpike Du 				 sizeof(event_nums),
14595c9f3294SSpike Du 				 event_nums,
14605c9f3294SSpike Du 				 cookie);
14615c9f3294SSpike Du 			if (ret) {
14625c9f3294SSpike Du 				rte_errno = rte_errno ? rte_errno : EINVAL;
14635c9f3294SSpike Du 				ret = -rte_errno;
14645c9f3294SSpike Du 				goto end;
14655c9f3294SSpike Du 			}
14665c9f3294SSpike Du 			rxq->lwm_devx_subscribed = 1;
14675c9f3294SSpike Du 		}
14685c9f3294SSpike Du 	}
14695c9f3294SSpike Du 	/* Save LWM to rxq and send modify_rq devx command. */
14705c9f3294SSpike Du 	rxq->lwm = lwm * wqe_cnt / 100;
14715c9f3294SSpike Du 	/* Prevent integer division loss when switch lwm number to percentage. */
14725c9f3294SSpike Du 	if (lwm && (lwm * wqe_cnt % 100)) {
14735c9f3294SSpike Du 		rxq->lwm = ((uint32_t)(rxq->lwm + 1) >= wqe_cnt) ?
14745c9f3294SSpike Du 			rxq->lwm : (rxq->lwm + 1);
14755c9f3294SSpike Du 	}
14765c9f3294SSpike Du 	if (lwm && !rxq->lwm) {
14775c9f3294SSpike Du 		/* With mprq, wqe_cnt may be < 100. */
14785c9f3294SSpike Du 		DRV_LOG(WARNING, "Too small LWM configuration.");
14795c9f3294SSpike Du 		rte_errno = EINVAL;
14805c9f3294SSpike Du 		ret = -rte_errno;
14815c9f3294SSpike Du 		goto end;
14825c9f3294SSpike Du 	}
14835c9f3294SSpike Du 	ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RDY2RDY);
14845c9f3294SSpike Du end:
14855c9f3294SSpike Du 	pthread_mutex_unlock(&priv->sh->lwm_config_lock);
14865c9f3294SSpike Du 	return ret;
14875c9f3294SSpike Du }
14885c9f3294SSpike Du 
14892235fcdaSSpike Du /**
14902235fcdaSSpike Du  * Mlx5 access register function to configure host shaper.
14912235fcdaSSpike Du  * It calls API in libmtcr_ul to access QSHR(Qos Shaper Host Register)
14922235fcdaSSpike Du  * in firmware.
14932235fcdaSSpike Du  *
14942235fcdaSSpike Du  * @param dev
14952235fcdaSSpike Du  *   Pointer to rte_eth_dev.
14962235fcdaSSpike Du  * @param lwm_triggered
14972235fcdaSSpike Du  *   Flag to enable/disable lwm_triggered bit in QSHR.
14982235fcdaSSpike Du  * @param rate
14992235fcdaSSpike Du  *   Host shaper rate, unit is 100Mbps, set to 0 means disable the shaper.
15002235fcdaSSpike Du  * @return
15012235fcdaSSpike Du  *   0 : operation success.
15022235fcdaSSpike Du  *   Otherwise:
15032235fcdaSSpike Du  *   - ENOENT - no ibdev interface.
15042235fcdaSSpike Du  *   - EBUSY  - the register access unit is busy.
15052235fcdaSSpike Du  *   - EIO    - the register access command meets IO error.
15062235fcdaSSpike Du  */
15072235fcdaSSpike Du static int
15082235fcdaSSpike Du mlxreg_host_shaper_config(struct rte_eth_dev *dev,
15092235fcdaSSpike Du 			  bool lwm_triggered, uint8_t rate)
15102235fcdaSSpike Du {
15112235fcdaSSpike Du #ifdef HAVE_MLX5_MSTFLINT
15122235fcdaSSpike Du 	struct mlx5_priv *priv = dev->data->dev_private;
15132235fcdaSSpike Du 	uint32_t data[MLX5_ST_SZ_DW(register_qshr)] = {0};
15142235fcdaSSpike Du 	int rc, retry_count = 3;
15152235fcdaSSpike Du 	mfile *mf = NULL;
15162235fcdaSSpike Du 	int status;
15172235fcdaSSpike Du 	void *ptr;
15182235fcdaSSpike Du 
15192235fcdaSSpike Du 	mf = mopen(priv->sh->ibdev_name);
15202235fcdaSSpike Du 	if (!mf) {
15212235fcdaSSpike Du 		DRV_LOG(WARNING, "mopen failed\n");
15222235fcdaSSpike Du 		rte_errno = ENOENT;
15232235fcdaSSpike Du 		return -rte_errno;
15242235fcdaSSpike Du 	}
15252235fcdaSSpike Du 	MLX5_SET(register_qshr, data, connected_host, 1);
15262235fcdaSSpike Du 	MLX5_SET(register_qshr, data, fast_response, lwm_triggered ? 1 : 0);
15272235fcdaSSpike Du 	MLX5_SET(register_qshr, data, local_port, 1);
15282235fcdaSSpike Du 	ptr = MLX5_ADDR_OF(register_qshr, data, global_config);
15292235fcdaSSpike Du 	MLX5_SET(ets_global_config_register, ptr, rate_limit_update, 1);
15302235fcdaSSpike Du 	MLX5_SET(ets_global_config_register, ptr, max_bw_units,
15312235fcdaSSpike Du 		 rate ? ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS :
15322235fcdaSSpike Du 		 ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED);
15332235fcdaSSpike Du 	MLX5_SET(ets_global_config_register, ptr, max_bw_value, rate);
15342235fcdaSSpike Du 	do {
15352235fcdaSSpike Du 		rc = maccess_reg(mf,
15362235fcdaSSpike Du 				 MLX5_QSHR_REGISTER_ID,
15372235fcdaSSpike Du 				 MACCESS_REG_METHOD_SET,
15382235fcdaSSpike Du 				 (u_int32_t *)&data[0],
15392235fcdaSSpike Du 				 sizeof(data),
15402235fcdaSSpike Du 				 sizeof(data),
15412235fcdaSSpike Du 				 sizeof(data),
15422235fcdaSSpike Du 				 &status);
15432235fcdaSSpike Du 		if ((rc != ME_ICMD_STATUS_IFC_BUSY &&
15442235fcdaSSpike Du 		     status != ME_REG_ACCESS_BAD_PARAM) ||
15452235fcdaSSpike Du 		    !(mf->flags & MDEVS_REM)) {
15462235fcdaSSpike Du 			break;
15472235fcdaSSpike Du 		}
15482235fcdaSSpike Du 		DRV_LOG(WARNING, "%s retry.", __func__);
15492235fcdaSSpike Du 		usleep(10000);
15502235fcdaSSpike Du 	} while (retry_count-- > 0);
15512235fcdaSSpike Du 	mclose(mf);
15522235fcdaSSpike Du 	rte_errno = (rc == ME_REG_ACCESS_DEV_BUSY) ? EBUSY : EIO;
15532235fcdaSSpike Du 	return rc ? -rte_errno : 0;
15542235fcdaSSpike Du #else
15552235fcdaSSpike Du 	(void)dev;
15562235fcdaSSpike Du 	(void)lwm_triggered;
15572235fcdaSSpike Du 	(void)rate;
15582235fcdaSSpike Du 	return -1;
15592235fcdaSSpike Du #endif
15602235fcdaSSpike Du }
15612235fcdaSSpike Du 
15622235fcdaSSpike Du int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate,
15632235fcdaSSpike Du 				    uint32_t flags)
15642235fcdaSSpike Du {
15652235fcdaSSpike Du 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
15662235fcdaSSpike Du 	struct mlx5_priv *priv = dev->data->dev_private;
15672235fcdaSSpike Du 	bool lwm_triggered =
156886647d46SThomas Monjalon 	     !!(flags & RTE_BIT32(RTE_PMD_MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
15692235fcdaSSpike Du 
15702235fcdaSSpike Du 	if (!lwm_triggered) {
15712235fcdaSSpike Du 		priv->sh->host_shaper_rate = rate;
15722235fcdaSSpike Du 	} else {
15732235fcdaSSpike Du 		switch (rate) {
15742235fcdaSSpike Du 		case 0:
15752235fcdaSSpike Du 		/* Rate 0 means disable lwm_triggered. */
15762235fcdaSSpike Du 			priv->sh->lwm_triggered = 0;
15772235fcdaSSpike Du 			break;
15782235fcdaSSpike Du 		case 1:
15792235fcdaSSpike Du 		/* Rate 1 means enable lwm_triggered. */
15802235fcdaSSpike Du 			priv->sh->lwm_triggered = 1;
15812235fcdaSSpike Du 			break;
15822235fcdaSSpike Du 		default:
15832235fcdaSSpike Du 			return -ENOTSUP;
15842235fcdaSSpike Du 		}
15852235fcdaSSpike Du 	}
15862235fcdaSSpike Du 	return mlxreg_host_shaper_config(dev, priv->sh->lwm_triggered,
15872235fcdaSSpike Du 					 priv->sh->host_shaper_rate);
15882235fcdaSSpike Du }
15893dfa7877SKiran Vedere 
15903dfa7877SKiran Vedere /**
15913dfa7877SKiran Vedere  * Dump RQ/CQ Context to a file.
15923dfa7877SKiran Vedere  *
15933dfa7877SKiran Vedere  * @param[in] port_id
15943dfa7877SKiran Vedere  *   Port ID
15953dfa7877SKiran Vedere  * @param[in] queue_id
15963dfa7877SKiran Vedere  *   Queue ID
15973dfa7877SKiran Vedere  * @param[in] filename
15983dfa7877SKiran Vedere  *   Name of file to dump the Rx Queue Context
15993dfa7877SKiran Vedere  *
16003dfa7877SKiran Vedere  * @return
16013dfa7877SKiran Vedere  *   0 for Success, non-zero value depending on failure type
16023dfa7877SKiran Vedere  */
16033dfa7877SKiran Vedere int rte_pmd_mlx5_rxq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename)
16043dfa7877SKiran Vedere {
16053dfa7877SKiran Vedere 	struct rte_eth_dev *dev;
16063dfa7877SKiran Vedere 	struct mlx5_rxq_priv *rxq;
16073dfa7877SKiran Vedere 	struct mlx5_rxq_ctrl *rxq_ctrl;
16083dfa7877SKiran Vedere 	struct mlx5_rxq_obj *rxq_obj;
16093dfa7877SKiran Vedere 	struct mlx5_devx_rq *rq;
16103dfa7877SKiran Vedere 	struct mlx5_devx_cq *cq;
16113dfa7877SKiran Vedere 	struct mlx5_devx_obj *rq_devx_obj;
16123dfa7877SKiran Vedere 	struct mlx5_devx_obj *cq_devx_obj;
16133dfa7877SKiran Vedere 
16143dfa7877SKiran Vedere 	uint32_t rq_out[MLX5_ST_SZ_DW(query_rq_out)] = {0};
16153dfa7877SKiran Vedere 	uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0};
16163dfa7877SKiran Vedere 
16173dfa7877SKiran Vedere 	int ret;
16183dfa7877SKiran Vedere 	FILE *fd;
16193dfa7877SKiran Vedere 	MKSTR(path, "./%s", filename);
16203dfa7877SKiran Vedere 
16213dfa7877SKiran Vedere 	if (!rte_eth_dev_is_valid_port(port_id))
16223dfa7877SKiran Vedere 		return -ENODEV;
16233dfa7877SKiran Vedere 
16243dfa7877SKiran Vedere 	if (rte_eth_rx_queue_is_valid(port_id, queue_id))
16253dfa7877SKiran Vedere 		return -EINVAL;
16263dfa7877SKiran Vedere 
16273dfa7877SKiran Vedere 	fd = fopen(path, "w");
16283dfa7877SKiran Vedere 	if (!fd) {
16293dfa7877SKiran Vedere 		rte_errno = errno;
16303dfa7877SKiran Vedere 		return -EIO;
16313dfa7877SKiran Vedere 	}
16323dfa7877SKiran Vedere 
16333dfa7877SKiran Vedere 	dev = &rte_eth_devices[port_id];
16343dfa7877SKiran Vedere 	rxq = mlx5_rxq_ref(dev, queue_id);
16353dfa7877SKiran Vedere 	rxq_ctrl = rxq->ctrl;
16363dfa7877SKiran Vedere 	rxq_obj = rxq_ctrl->obj;
16373dfa7877SKiran Vedere 	rq = &rxq->devx_rq;
16383dfa7877SKiran Vedere 	cq = &rxq_obj->cq_obj;
16393dfa7877SKiran Vedere 	rq_devx_obj = rq->rq;
16403dfa7877SKiran Vedere 	cq_devx_obj = cq->cq;
16413dfa7877SKiran Vedere 
16423dfa7877SKiran Vedere 	do {
16433dfa7877SKiran Vedere 		ret = mlx5_devx_cmd_query_rq(rq_devx_obj, rq_out, sizeof(rq_out));
16443dfa7877SKiran Vedere 		if (ret)
16453dfa7877SKiran Vedere 			break;
16463dfa7877SKiran Vedere 
16473dfa7877SKiran Vedere 		/* Dump rq query output to file */
16483dfa7877SKiran Vedere 		MKSTR(rq_headline, "RQ DevX ID = %u Port = %u Queue index = %u ",
16493dfa7877SKiran Vedere 					rq_devx_obj->id, port_id, queue_id);
16503dfa7877SKiran Vedere 		mlx5_dump_to_file(fd, NULL, rq_headline, 0);
16513dfa7877SKiran Vedere 		mlx5_dump_to_file(fd, "Query RQ Dump:",
16523dfa7877SKiran Vedere 					(const void *)((uintptr_t)rq_out),
16533dfa7877SKiran Vedere 					sizeof(rq_out));
16543dfa7877SKiran Vedere 
16553dfa7877SKiran Vedere 		ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out));
16563dfa7877SKiran Vedere 		if (ret)
16573dfa7877SKiran Vedere 			break;
16583dfa7877SKiran Vedere 
16593dfa7877SKiran Vedere 		/* Dump cq query output to file */
16603dfa7877SKiran Vedere 		MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ",
16613dfa7877SKiran Vedere 					cq_devx_obj->id, port_id, queue_id);
16623dfa7877SKiran Vedere 		mlx5_dump_to_file(fd, NULL, cq_headline, 0);
16633dfa7877SKiran Vedere 		mlx5_dump_to_file(fd, "Query CQ Dump:",
16643dfa7877SKiran Vedere 					(const void *)((uintptr_t)cq_out),
16653dfa7877SKiran Vedere 					sizeof(cq_out));
16663dfa7877SKiran Vedere 	} while (false);
16673dfa7877SKiran Vedere 
16683dfa7877SKiran Vedere 	fclose(fd);
16693dfa7877SKiran Vedere 	return ret;
16703dfa7877SKiran Vedere }
1671