xref: /dpdk/drivers/net/mlx5/mlx5_rx.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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>
22a96102c8SMichael Baum 
23a96102c8SMichael Baum #include "mlx5_autoconf.h"
24a96102c8SMichael Baum #include "mlx5_defs.h"
25a96102c8SMichael Baum #include "mlx5.h"
26a96102c8SMichael Baum #include "mlx5_utils.h"
27a96102c8SMichael Baum #include "mlx5_rxtx.h"
28a96102c8SMichael Baum #include "mlx5_rx.h"
29a96102c8SMichael Baum 
30a96102c8SMichael Baum 
31a96102c8SMichael Baum static __rte_always_inline uint32_t
32a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
33a96102c8SMichael Baum 		   volatile struct mlx5_mini_cqe8 *mcqe);
34a96102c8SMichael Baum 
35a96102c8SMichael Baum static __rte_always_inline int
36a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
37a96102c8SMichael Baum 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe);
38a96102c8SMichael Baum 
39a96102c8SMichael Baum static __rte_always_inline uint32_t
40a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
41a96102c8SMichael Baum 
42a96102c8SMichael Baum static __rte_always_inline void
43a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
44a96102c8SMichael Baum 	       volatile struct mlx5_cqe *cqe,
45a96102c8SMichael Baum 	       volatile struct mlx5_mini_cqe8 *mcqe);
46a96102c8SMichael Baum 
47a96102c8SMichael Baum static inline void
48a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
49a96102c8SMichael Baum 			volatile struct mlx5_cqe *__rte_restrict cqe,
50a96102c8SMichael Baum 			uint32_t phcsum, uint8_t l4_type);
51a96102c8SMichael Baum 
52a96102c8SMichael Baum static inline void
53a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
54a96102c8SMichael Baum 		    volatile struct mlx5_cqe *__rte_restrict cqe,
55a96102c8SMichael Baum 		    volatile struct mlx5_mini_cqe8 *mcqe,
56a96102c8SMichael Baum 		    struct mlx5_rxq_data *rxq, uint32_t len);
57a96102c8SMichael Baum 
58a96102c8SMichael Baum 
59a96102c8SMichael Baum /**
60a96102c8SMichael Baum  * Internal function to compute the number of used descriptors in an RX queue.
61a96102c8SMichael Baum  *
62a96102c8SMichael Baum  * @param rxq
63a96102c8SMichael Baum  *   The Rx queue.
64a96102c8SMichael Baum  *
65a96102c8SMichael Baum  * @return
66a96102c8SMichael Baum  *   The number of used Rx descriptor.
67a96102c8SMichael Baum  */
68a96102c8SMichael Baum static uint32_t
69a96102c8SMichael Baum rx_queue_count(struct mlx5_rxq_data *rxq)
70a96102c8SMichael Baum {
71a96102c8SMichael Baum 	struct rxq_zip *zip = &rxq->zip;
72a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe;
73a96102c8SMichael Baum 	const unsigned int cqe_n = (1 << rxq->cqe_n);
74a96102c8SMichael Baum 	const unsigned int sges_n = (1 << rxq->sges_n);
75a96102c8SMichael Baum 	const unsigned int elts_n = (1 << rxq->elts_n);
76a96102c8SMichael Baum 	const unsigned int strd_n = (1 << rxq->strd_num_n);
77a96102c8SMichael Baum 	const unsigned int cqe_cnt = cqe_n - 1;
78a96102c8SMichael Baum 	unsigned int cq_ci, used;
79a96102c8SMichael Baum 
80a96102c8SMichael Baum 	/* if we are processing a compressed cqe */
81a96102c8SMichael Baum 	if (zip->ai) {
82a96102c8SMichael Baum 		used = zip->cqe_cnt - zip->ai;
83a96102c8SMichael Baum 		cq_ci = zip->cq_ci;
84a96102c8SMichael Baum 	} else {
85a96102c8SMichael Baum 		used = 0;
86a96102c8SMichael Baum 		cq_ci = rxq->cq_ci;
87a96102c8SMichael Baum 	}
88a96102c8SMichael Baum 	cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
89a96102c8SMichael Baum 	while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) {
90a96102c8SMichael Baum 		int8_t op_own;
91a96102c8SMichael Baum 		unsigned int n;
92a96102c8SMichael Baum 
93a96102c8SMichael Baum 		op_own = cqe->op_own;
94a96102c8SMichael Baum 		if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
95a96102c8SMichael Baum 			n = rte_be_to_cpu_32(cqe->byte_cnt);
96a96102c8SMichael Baum 		else
97a96102c8SMichael Baum 			n = 1;
98a96102c8SMichael Baum 		cq_ci += n;
99a96102c8SMichael Baum 		used += n;
100a96102c8SMichael Baum 		cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
101a96102c8SMichael Baum 	}
102a96102c8SMichael Baum 	used = RTE_MIN(used * sges_n, elts_n * strd_n);
103a96102c8SMichael Baum 	return used;
104a96102c8SMichael Baum }
105a96102c8SMichael Baum 
106a96102c8SMichael Baum /**
107a96102c8SMichael Baum  * DPDK callback to check the status of a Rx descriptor.
108a96102c8SMichael Baum  *
109a96102c8SMichael Baum  * @param rx_queue
110a96102c8SMichael Baum  *   The Rx queue.
111a96102c8SMichael Baum  * @param[in] offset
112a96102c8SMichael Baum  *   The index of the descriptor in the ring.
113a96102c8SMichael Baum  *
114a96102c8SMichael Baum  * @return
115a96102c8SMichael Baum  *   The status of the Rx descriptor.
116a96102c8SMichael Baum  */
117a96102c8SMichael Baum int
118a96102c8SMichael Baum mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
119a96102c8SMichael Baum {
120a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = rx_queue;
121a96102c8SMichael Baum 	struct mlx5_rxq_ctrl *rxq_ctrl =
122a96102c8SMichael Baum 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
123a96102c8SMichael Baum 	struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv);
124a96102c8SMichael Baum 
125a96102c8SMichael Baum 	if (dev->rx_pkt_burst == NULL ||
126a96102c8SMichael Baum 	    dev->rx_pkt_burst == removed_rx_burst) {
127a96102c8SMichael Baum 		rte_errno = ENOTSUP;
128a96102c8SMichael Baum 		return -rte_errno;
129a96102c8SMichael Baum 	}
130a96102c8SMichael Baum 	if (offset >= (1 << rxq->cqe_n)) {
131a96102c8SMichael Baum 		rte_errno = EINVAL;
132a96102c8SMichael Baum 		return -rte_errno;
133a96102c8SMichael Baum 	}
134a96102c8SMichael Baum 	if (offset < rx_queue_count(rxq))
135a96102c8SMichael Baum 		return RTE_ETH_RX_DESC_DONE;
136a96102c8SMichael Baum 	return RTE_ETH_RX_DESC_AVAIL;
137a96102c8SMichael Baum }
138a96102c8SMichael Baum 
139a96102c8SMichael Baum /**
140a96102c8SMichael Baum  * DPDK callback to get the RX queue information.
141a96102c8SMichael Baum  *
142a96102c8SMichael Baum  * @param dev
143a96102c8SMichael Baum  *   Pointer to the device structure.
144a96102c8SMichael Baum  *
145a96102c8SMichael Baum  * @param rx_queue_id
146a96102c8SMichael Baum  *   Rx queue identificator.
147a96102c8SMichael Baum  *
148a96102c8SMichael Baum  * @param qinfo
149a96102c8SMichael Baum  *   Pointer to the RX queue information structure.
150a96102c8SMichael Baum  *
151a96102c8SMichael Baum  * @return
152a96102c8SMichael Baum  *   None.
153a96102c8SMichael Baum  */
154a96102c8SMichael Baum 
155a96102c8SMichael Baum void
156a96102c8SMichael Baum mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
157a96102c8SMichael Baum 		  struct rte_eth_rxq_info *qinfo)
158a96102c8SMichael Baum {
159a96102c8SMichael Baum 	struct mlx5_priv *priv = dev->data->dev_private;
160a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = (*priv->rxqs)[rx_queue_id];
161a96102c8SMichael Baum 	struct mlx5_rxq_ctrl *rxq_ctrl =
162a96102c8SMichael Baum 		container_of(rxq, struct mlx5_rxq_ctrl, rxq);
163a96102c8SMichael Baum 
164a96102c8SMichael Baum 	if (!rxq)
165a96102c8SMichael Baum 		return;
166a96102c8SMichael Baum 	qinfo->mp = mlx5_rxq_mprq_enabled(rxq) ?
167a96102c8SMichael Baum 					rxq->mprq_mp : rxq->mp;
168a96102c8SMichael Baum 	qinfo->conf.rx_thresh.pthresh = 0;
169a96102c8SMichael Baum 	qinfo->conf.rx_thresh.hthresh = 0;
170a96102c8SMichael Baum 	qinfo->conf.rx_thresh.wthresh = 0;
171a96102c8SMichael Baum 	qinfo->conf.rx_free_thresh = rxq->rq_repl_thresh;
172a96102c8SMichael Baum 	qinfo->conf.rx_drop_en = 1;
173a96102c8SMichael Baum 	qinfo->conf.rx_deferred_start = rxq_ctrl ? 0 : 1;
174a96102c8SMichael Baum 	qinfo->conf.offloads = dev->data->dev_conf.rxmode.offloads;
175a96102c8SMichael Baum 	qinfo->scattered_rx = dev->data->scattered_rx;
176a96102c8SMichael Baum 	qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ?
177a96102c8SMichael Baum 		(1 << rxq->elts_n) * (1 << rxq->strd_num_n) :
178a96102c8SMichael Baum 		(1 << rxq->elts_n);
179a96102c8SMichael Baum }
180a96102c8SMichael Baum 
181a96102c8SMichael Baum /**
182a96102c8SMichael Baum  * DPDK callback to get the RX packet burst mode information.
183a96102c8SMichael Baum  *
184a96102c8SMichael Baum  * @param dev
185a96102c8SMichael Baum  *   Pointer to the device structure.
186a96102c8SMichael Baum  *
187a96102c8SMichael Baum  * @param rx_queue_id
188a96102c8SMichael Baum  *   Rx queue identificatior.
189a96102c8SMichael Baum  *
190a96102c8SMichael Baum  * @param mode
191a96102c8SMichael Baum  *   Pointer to the burts mode information.
192a96102c8SMichael Baum  *
193a96102c8SMichael Baum  * @return
194a96102c8SMichael Baum  *   0 as success, -EINVAL as failure.
195a96102c8SMichael Baum  */
196a96102c8SMichael Baum int
197a96102c8SMichael Baum mlx5_rx_burst_mode_get(struct rte_eth_dev *dev,
198a96102c8SMichael Baum 		       uint16_t rx_queue_id __rte_unused,
199a96102c8SMichael Baum 		       struct rte_eth_burst_mode *mode)
200a96102c8SMichael Baum {
201a96102c8SMichael Baum 	eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
202a96102c8SMichael Baum 	struct mlx5_priv *priv = dev->data->dev_private;
203a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq;
204a96102c8SMichael Baum 
205a96102c8SMichael Baum 	rxq = (*priv->rxqs)[rx_queue_id];
206a96102c8SMichael Baum 	if (!rxq) {
207a96102c8SMichael Baum 		rte_errno = EINVAL;
208a96102c8SMichael Baum 		return -rte_errno;
209a96102c8SMichael Baum 	}
210a96102c8SMichael Baum 	if (pkt_burst == mlx5_rx_burst) {
211a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Scalar");
212a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_mprq) {
213a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Multi-Packet RQ");
214a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_vec) {
215a96102c8SMichael Baum #if defined RTE_ARCH_X86_64
216a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector SSE");
217a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64
218a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector Neon");
219a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64
220a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "Vector AltiVec");
221a96102c8SMichael Baum #else
222a96102c8SMichael Baum 		return -EINVAL;
223a96102c8SMichael Baum #endif
224a96102c8SMichael Baum 	} else if (pkt_burst == mlx5_rx_burst_mprq_vec) {
225a96102c8SMichael Baum #if defined RTE_ARCH_X86_64
226a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector SSE");
227a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64
228a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector Neon");
229a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64
230a96102c8SMichael Baum 		snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector AltiVec");
231a96102c8SMichael Baum #else
232a96102c8SMichael Baum 		return -EINVAL;
233a96102c8SMichael Baum #endif
234a96102c8SMichael Baum 	} else {
235a96102c8SMichael Baum 		return -EINVAL;
236a96102c8SMichael Baum 	}
237a96102c8SMichael Baum 	return 0;
238a96102c8SMichael Baum }
239a96102c8SMichael Baum 
240a96102c8SMichael Baum /**
241a96102c8SMichael Baum  * DPDK callback to get the number of used descriptors in a RX queue.
242a96102c8SMichael Baum  *
2438d7d4fcdSKonstantin Ananyev  * @param rx_queue
2448d7d4fcdSKonstantin Ananyev  *   The Rx queue pointer.
245a96102c8SMichael Baum  *
246a96102c8SMichael Baum  * @return
247a96102c8SMichael Baum  *   The number of used rx descriptor.
248a96102c8SMichael Baum  *   -EINVAL if the queue is invalid
249a96102c8SMichael Baum  */
250a96102c8SMichael Baum uint32_t
2518d7d4fcdSKonstantin Ananyev mlx5_rx_queue_count(void *rx_queue)
252a96102c8SMichael Baum {
2538d7d4fcdSKonstantin Ananyev 	struct mlx5_rxq_data *rxq = rx_queue;
2548d7d4fcdSKonstantin Ananyev 	struct rte_eth_dev *dev;
2558d7d4fcdSKonstantin Ananyev 
2568d7d4fcdSKonstantin Ananyev 	if (!rxq) {
2578d7d4fcdSKonstantin Ananyev 		rte_errno = EINVAL;
2588d7d4fcdSKonstantin Ananyev 		return -rte_errno;
2598d7d4fcdSKonstantin Ananyev 	}
2608d7d4fcdSKonstantin Ananyev 
2618d7d4fcdSKonstantin Ananyev 	dev = &rte_eth_devices[rxq->port_id];
262a96102c8SMichael Baum 
263a96102c8SMichael Baum 	if (dev->rx_pkt_burst == NULL ||
264a96102c8SMichael Baum 	    dev->rx_pkt_burst == removed_rx_burst) {
265a96102c8SMichael Baum 		rte_errno = ENOTSUP;
266a96102c8SMichael Baum 		return -rte_errno;
267a96102c8SMichael Baum 	}
2688d7d4fcdSKonstantin Ananyev 
269a96102c8SMichael Baum 	return rx_queue_count(rxq);
270a96102c8SMichael Baum }
271a96102c8SMichael Baum 
2726afc4bafSAnatoly Burakov #define CLB_VAL_IDX 0
2736afc4bafSAnatoly Burakov #define CLB_MSK_IDX 1
2746afc4bafSAnatoly Burakov static int
2756afc4bafSAnatoly Burakov mlx5_monitor_callback(const uint64_t value,
2766afc4bafSAnatoly Burakov 		const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
2776afc4bafSAnatoly Burakov {
2786afc4bafSAnatoly Burakov 	const uint64_t m = opaque[CLB_MSK_IDX];
2796afc4bafSAnatoly Burakov 	const uint64_t v = opaque[CLB_VAL_IDX];
2806afc4bafSAnatoly Burakov 
2816afc4bafSAnatoly Burakov 	return (value & m) == v ? -1 : 0;
2826afc4bafSAnatoly Burakov }
2836afc4bafSAnatoly Burakov 
284a8f0df6bSAlexander Kozyrev int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
285a8f0df6bSAlexander Kozyrev {
286a8f0df6bSAlexander Kozyrev 	struct mlx5_rxq_data *rxq = rx_queue;
287a8f0df6bSAlexander Kozyrev 	const unsigned int cqe_num = 1 << rxq->cqe_n;
288a8f0df6bSAlexander Kozyrev 	const unsigned int cqe_mask = cqe_num - 1;
289a8f0df6bSAlexander Kozyrev 	const uint16_t idx = rxq->cq_ci & cqe_num;
290a8f0df6bSAlexander Kozyrev 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
291a8f0df6bSAlexander Kozyrev 
292a8f0df6bSAlexander Kozyrev 	if (unlikely(rxq->cqes == NULL)) {
293a8f0df6bSAlexander Kozyrev 		rte_errno = EINVAL;
294a8f0df6bSAlexander Kozyrev 		return -rte_errno;
295a8f0df6bSAlexander Kozyrev 	}
296a8f0df6bSAlexander Kozyrev 	pmc->addr = &cqe->op_own;
2976afc4bafSAnatoly Burakov 	pmc->opaque[CLB_VAL_IDX] = !!idx;
2986afc4bafSAnatoly Burakov 	pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_OWNER_MASK;
2996afc4bafSAnatoly Burakov 	pmc->fn = mlx5_monitor_callback;
300a8f0df6bSAlexander Kozyrev 	pmc->size = sizeof(uint8_t);
301a8f0df6bSAlexander Kozyrev 	return 0;
302a8f0df6bSAlexander Kozyrev }
303a8f0df6bSAlexander Kozyrev 
304a96102c8SMichael Baum /**
305a96102c8SMichael Baum  * Translate RX completion flags to packet type.
306a96102c8SMichael Baum  *
307a96102c8SMichael Baum  * @param[in] rxq
308a96102c8SMichael Baum  *   Pointer to RX queue structure.
309a96102c8SMichael Baum  * @param[in] cqe
310a96102c8SMichael Baum  *   Pointer to CQE.
311a96102c8SMichael Baum  *
312a96102c8SMichael Baum  * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
313a96102c8SMichael Baum  *
314a96102c8SMichael Baum  * @return
315a96102c8SMichael Baum  *   Packet type for struct rte_mbuf.
316a96102c8SMichael Baum  */
317a96102c8SMichael Baum static inline uint32_t
318a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
319a96102c8SMichael Baum 				   volatile struct mlx5_mini_cqe8 *mcqe)
320a96102c8SMichael Baum {
321a96102c8SMichael Baum 	uint8_t idx;
322a96102c8SMichael Baum 	uint8_t ptype;
323a96102c8SMichael Baum 	uint8_t pinfo = (cqe->pkt_info & 0x3) << 6;
324a96102c8SMichael Baum 
325a96102c8SMichael Baum 	/* Get l3/l4 header from mini-CQE in case L3/L4 format*/
326a96102c8SMichael Baum 	if (mcqe == NULL ||
327a96102c8SMichael Baum 	    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
328a96102c8SMichael Baum 		ptype = (cqe->hdr_type_etc & 0xfc00) >> 10;
329a96102c8SMichael Baum 	else
330a96102c8SMichael Baum 		ptype = mcqe->hdr_type >> 2;
331a96102c8SMichael Baum 	/*
332a96102c8SMichael Baum 	 * The index to the array should have:
333a96102c8SMichael Baum 	 * bit[1:0] = l3_hdr_type
334a96102c8SMichael Baum 	 * bit[4:2] = l4_hdr_type
335a96102c8SMichael Baum 	 * bit[5] = ip_frag
336a96102c8SMichael Baum 	 * bit[6] = tunneled
337a96102c8SMichael Baum 	 * bit[7] = outer_l3_type
338a96102c8SMichael Baum 	 */
339a96102c8SMichael Baum 	idx = pinfo | ptype;
340a96102c8SMichael Baum 	return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
341a96102c8SMichael Baum }
342a96102c8SMichael Baum 
343a96102c8SMichael Baum /**
344a96102c8SMichael Baum  * Initialize Rx WQ and indexes.
345a96102c8SMichael Baum  *
346a96102c8SMichael Baum  * @param[in] rxq
347a96102c8SMichael Baum  *   Pointer to RX queue structure.
348a96102c8SMichael Baum  */
349a96102c8SMichael Baum void
350a96102c8SMichael Baum mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
351a96102c8SMichael Baum {
352a96102c8SMichael Baum 	const unsigned int wqe_n = 1 << rxq->elts_n;
353a96102c8SMichael Baum 	unsigned int i;
354a96102c8SMichael Baum 
355a96102c8SMichael Baum 	for (i = 0; (i != wqe_n); ++i) {
356a96102c8SMichael Baum 		volatile struct mlx5_wqe_data_seg *scat;
357a96102c8SMichael Baum 		uintptr_t addr;
358a96102c8SMichael Baum 		uint32_t byte_count;
359a96102c8SMichael Baum 
360a96102c8SMichael Baum 		if (mlx5_rxq_mprq_enabled(rxq)) {
361a96102c8SMichael Baum 			struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
362a96102c8SMichael Baum 
363a96102c8SMichael Baum 			scat = &((volatile struct mlx5_wqe_mprq *)
364a96102c8SMichael Baum 				rxq->wqes)[i].dseg;
365a96102c8SMichael Baum 			addr = (uintptr_t)mlx5_mprq_buf_addr(buf,
366a96102c8SMichael Baum 							 1 << rxq->strd_num_n);
367a96102c8SMichael Baum 			byte_count = (1 << rxq->strd_sz_n) *
368a96102c8SMichael Baum 					(1 << rxq->strd_num_n);
369a96102c8SMichael Baum 		} else {
370a96102c8SMichael Baum 			struct rte_mbuf *buf = (*rxq->elts)[i];
371a96102c8SMichael Baum 
372a96102c8SMichael Baum 			scat = &((volatile struct mlx5_wqe_data_seg *)
373a96102c8SMichael Baum 					rxq->wqes)[i];
374a96102c8SMichael Baum 			addr = rte_pktmbuf_mtod(buf, uintptr_t);
375a96102c8SMichael Baum 			byte_count = DATA_LEN(buf);
376a96102c8SMichael Baum 		}
377a96102c8SMichael Baum 		/* scat->addr must be able to store a pointer. */
378a96102c8SMichael Baum 		MLX5_ASSERT(sizeof(scat->addr) >= sizeof(uintptr_t));
379a96102c8SMichael Baum 		*scat = (struct mlx5_wqe_data_seg){
380a96102c8SMichael Baum 			.addr = rte_cpu_to_be_64(addr),
381a96102c8SMichael Baum 			.byte_count = rte_cpu_to_be_32(byte_count),
382a96102c8SMichael Baum 			.lkey = mlx5_rx_addr2mr(rxq, addr),
383a96102c8SMichael Baum 		};
384a96102c8SMichael Baum 	}
385a96102c8SMichael Baum 	rxq->consumed_strd = 0;
386a96102c8SMichael Baum 	rxq->decompressed = 0;
387a96102c8SMichael Baum 	rxq->rq_pi = 0;
388a96102c8SMichael Baum 	rxq->zip = (struct rxq_zip){
389a96102c8SMichael Baum 		.ai = 0,
390a96102c8SMichael Baum 	};
391a96102c8SMichael Baum 	rxq->elts_ci = mlx5_rxq_mprq_enabled(rxq) ?
392a96102c8SMichael Baum 		(wqe_n >> rxq->sges_n) * (1 << rxq->strd_num_n) : 0;
393a96102c8SMichael Baum 	/* Update doorbell counter. */
394a96102c8SMichael Baum 	rxq->rq_ci = wqe_n >> rxq->sges_n;
395a96102c8SMichael Baum 	rte_io_wmb();
396a96102c8SMichael Baum 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
397a96102c8SMichael Baum }
398a96102c8SMichael Baum 
399a96102c8SMichael Baum /**
400a96102c8SMichael Baum  * Handle a Rx error.
401a96102c8SMichael Baum  * The function inserts the RQ state to reset when the first error CQE is
402a96102c8SMichael Baum  * shown, then drains the CQ by the caller function loop. When the CQ is empty,
403a96102c8SMichael Baum  * it moves the RQ state to ready and initializes the RQ.
404a96102c8SMichael Baum  * Next CQE identification and error counting are in the caller responsibility.
405a96102c8SMichael Baum  *
406a96102c8SMichael Baum  * @param[in] rxq
407a96102c8SMichael Baum  *   Pointer to RX queue structure.
408a96102c8SMichael Baum  * @param[in] vec
409a96102c8SMichael Baum  *   1 when called from vectorized Rx burst, need to prepare mbufs for the RQ.
410a96102c8SMichael Baum  *   0 when called from non-vectorized Rx burst.
411a96102c8SMichael Baum  *
412a96102c8SMichael Baum  * @return
413a96102c8SMichael Baum  *   -1 in case of recovery error, otherwise the CQE status.
414a96102c8SMichael Baum  */
415a96102c8SMichael Baum int
416a96102c8SMichael Baum mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec)
417a96102c8SMichael Baum {
418a96102c8SMichael Baum 	const uint16_t cqe_n = 1 << rxq->cqe_n;
419a96102c8SMichael Baum 	const uint16_t cqe_mask = cqe_n - 1;
420a96102c8SMichael Baum 	const uint16_t wqe_n = 1 << rxq->elts_n;
421a96102c8SMichael Baum 	const uint16_t strd_n = 1 << rxq->strd_num_n;
422a96102c8SMichael Baum 	struct mlx5_rxq_ctrl *rxq_ctrl =
423a96102c8SMichael Baum 			container_of(rxq, struct mlx5_rxq_ctrl, rxq);
424a96102c8SMichael Baum 	union {
425a96102c8SMichael Baum 		volatile struct mlx5_cqe *cqe;
426a96102c8SMichael Baum 		volatile struct mlx5_err_cqe *err_cqe;
427a96102c8SMichael Baum 	} u = {
428a96102c8SMichael Baum 		.cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask],
429a96102c8SMichael Baum 	};
430a96102c8SMichael Baum 	struct mlx5_mp_arg_queue_state_modify sm;
431a96102c8SMichael Baum 	int ret;
432a96102c8SMichael Baum 
433a96102c8SMichael Baum 	switch (rxq->err_state) {
434a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NO_ERROR:
435a96102c8SMichael Baum 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET;
436a96102c8SMichael Baum 		/* Fall-through */
437a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NEED_RESET:
438a96102c8SMichael Baum 		sm.is_wq = 1;
439a96102c8SMichael Baum 		sm.queue_id = rxq->idx;
440a96102c8SMichael Baum 		sm.state = IBV_WQS_RESET;
441a96102c8SMichael Baum 		if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv), &sm))
442a96102c8SMichael Baum 			return -1;
443a96102c8SMichael Baum 		if (rxq_ctrl->dump_file_n <
444a96102c8SMichael Baum 		    rxq_ctrl->priv->config.max_dump_files_num) {
445a96102c8SMichael Baum 			MKSTR(err_str, "Unexpected CQE error syndrome "
446a96102c8SMichael Baum 			      "0x%02x CQN = %u RQN = %u wqe_counter = %u"
447a96102c8SMichael Baum 			      " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome,
448a96102c8SMichael Baum 			      rxq->cqn, rxq_ctrl->wqn,
449a96102c8SMichael Baum 			      rte_be_to_cpu_16(u.err_cqe->wqe_counter),
450a96102c8SMichael Baum 			      rxq->rq_ci << rxq->sges_n, rxq->cq_ci);
451a96102c8SMichael Baum 			MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u",
452a96102c8SMichael Baum 			      rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc());
453a96102c8SMichael Baum 			mlx5_dump_debug_information(name, NULL, err_str, 0);
454a96102c8SMichael Baum 			mlx5_dump_debug_information(name, "MLX5 Error CQ:",
455a96102c8SMichael Baum 						    (const void *)((uintptr_t)
456a96102c8SMichael Baum 								    rxq->cqes),
457a96102c8SMichael Baum 						    sizeof(*u.cqe) * cqe_n);
458a96102c8SMichael Baum 			mlx5_dump_debug_information(name, "MLX5 Error RQ:",
459a96102c8SMichael Baum 						    (const void *)((uintptr_t)
460a96102c8SMichael Baum 								    rxq->wqes),
461a96102c8SMichael Baum 						    16 * wqe_n);
462a96102c8SMichael Baum 			rxq_ctrl->dump_file_n++;
463a96102c8SMichael Baum 		}
464a96102c8SMichael Baum 		rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY;
465a96102c8SMichael Baum 		/* Fall-through */
466a96102c8SMichael Baum 	case MLX5_RXQ_ERR_STATE_NEED_READY:
467a96102c8SMichael Baum 		ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci);
468a96102c8SMichael Baum 		if (ret == MLX5_CQE_STATUS_HW_OWN) {
469a96102c8SMichael Baum 			rte_io_wmb();
470a96102c8SMichael Baum 			*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
471a96102c8SMichael Baum 			rte_io_wmb();
472a96102c8SMichael Baum 			/*
473a96102c8SMichael Baum 			 * The RQ consumer index must be zeroed while moving
474a96102c8SMichael Baum 			 * from RESET state to RDY state.
475a96102c8SMichael Baum 			 */
476a96102c8SMichael Baum 			*rxq->rq_db = rte_cpu_to_be_32(0);
477a96102c8SMichael Baum 			rte_io_wmb();
478a96102c8SMichael Baum 			sm.is_wq = 1;
479a96102c8SMichael Baum 			sm.queue_id = rxq->idx;
480a96102c8SMichael Baum 			sm.state = IBV_WQS_RDY;
481a96102c8SMichael Baum 			if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv),
482a96102c8SMichael Baum 						    &sm))
483a96102c8SMichael Baum 				return -1;
484a96102c8SMichael Baum 			if (vec) {
485a96102c8SMichael Baum 				const uint32_t elts_n =
486a96102c8SMichael Baum 					mlx5_rxq_mprq_enabled(rxq) ?
487a96102c8SMichael Baum 					wqe_n * strd_n : wqe_n;
488a96102c8SMichael Baum 				const uint32_t e_mask = elts_n - 1;
489a96102c8SMichael Baum 				uint32_t elts_ci =
490a96102c8SMichael Baum 					mlx5_rxq_mprq_enabled(rxq) ?
491a96102c8SMichael Baum 					rxq->elts_ci : rxq->rq_ci;
492a96102c8SMichael Baum 				uint32_t elt_idx;
493a96102c8SMichael Baum 				struct rte_mbuf **elt;
494a96102c8SMichael Baum 				int i;
495a96102c8SMichael Baum 				unsigned int n = elts_n - (elts_ci -
496a96102c8SMichael Baum 							  rxq->rq_pi);
497a96102c8SMichael Baum 
498a96102c8SMichael Baum 				for (i = 0; i < (int)n; ++i) {
499a96102c8SMichael Baum 					elt_idx = (elts_ci + i) & e_mask;
500a96102c8SMichael Baum 					elt = &(*rxq->elts)[elt_idx];
501a96102c8SMichael Baum 					*elt = rte_mbuf_raw_alloc(rxq->mp);
502a96102c8SMichael Baum 					if (!*elt) {
503a96102c8SMichael Baum 						for (i--; i >= 0; --i) {
504a96102c8SMichael Baum 							elt_idx = (elts_ci +
505a96102c8SMichael Baum 								   i) & elts_n;
506a96102c8SMichael Baum 							elt = &(*rxq->elts)
507a96102c8SMichael Baum 								[elt_idx];
508a96102c8SMichael Baum 							rte_pktmbuf_free_seg
509a96102c8SMichael Baum 								(*elt);
510a96102c8SMichael Baum 						}
511a96102c8SMichael Baum 						return -1;
512a96102c8SMichael Baum 					}
513a96102c8SMichael Baum 				}
514a96102c8SMichael Baum 				for (i = 0; i < (int)elts_n; ++i) {
515a96102c8SMichael Baum 					elt = &(*rxq->elts)[i];
516a96102c8SMichael Baum 					DATA_LEN(*elt) =
517a96102c8SMichael Baum 						(uint16_t)((*elt)->buf_len -
518a96102c8SMichael Baum 						rte_pktmbuf_headroom(*elt));
519a96102c8SMichael Baum 				}
520a96102c8SMichael Baum 				/* Padding with a fake mbuf for vec Rx. */
521a96102c8SMichael Baum 				for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i)
522a96102c8SMichael Baum 					(*rxq->elts)[elts_n + i] =
523a96102c8SMichael Baum 								&rxq->fake_mbuf;
524a96102c8SMichael Baum 			}
525a96102c8SMichael Baum 			mlx5_rxq_initialize(rxq);
526a96102c8SMichael Baum 			rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
527a96102c8SMichael Baum 		}
528a96102c8SMichael Baum 		return ret;
529a96102c8SMichael Baum 	default:
530a96102c8SMichael Baum 		return -1;
531a96102c8SMichael Baum 	}
532a96102c8SMichael Baum }
533a96102c8SMichael Baum 
534a96102c8SMichael Baum /**
535a96102c8SMichael Baum  * Get size of the next packet for a given CQE. For compressed CQEs, the
536a96102c8SMichael Baum  * consumer index is updated only once all packets of the current one have
537a96102c8SMichael Baum  * been processed.
538a96102c8SMichael Baum  *
539a96102c8SMichael Baum  * @param rxq
540a96102c8SMichael Baum  *   Pointer to RX queue.
541a96102c8SMichael Baum  * @param cqe
542a96102c8SMichael Baum  *   CQE to process.
543a96102c8SMichael Baum  * @param[out] mcqe
544a96102c8SMichael Baum  *   Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
545a96102c8SMichael Baum  *   written.
546a96102c8SMichael Baum  *
547a96102c8SMichael Baum  * @return
548a96102c8SMichael Baum  *   0 in case of empty CQE, otherwise the packet size in bytes.
549a96102c8SMichael Baum  */
550a96102c8SMichael Baum static inline int
551a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
552a96102c8SMichael Baum 		 uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe)
553a96102c8SMichael Baum {
554a96102c8SMichael Baum 	struct rxq_zip *zip = &rxq->zip;
555a96102c8SMichael Baum 	uint16_t cqe_n = cqe_cnt + 1;
556a96102c8SMichael Baum 	int len;
557a96102c8SMichael Baum 	uint16_t idx, end;
558a96102c8SMichael Baum 
559a96102c8SMichael Baum 	do {
560a96102c8SMichael Baum 		len = 0;
561a96102c8SMichael Baum 		/* Process compressed data in the CQE and mini arrays. */
562a96102c8SMichael Baum 		if (zip->ai) {
563a96102c8SMichael Baum 			volatile struct mlx5_mini_cqe8 (*mc)[8] =
564a96102c8SMichael Baum 				(volatile struct mlx5_mini_cqe8 (*)[8])
565a96102c8SMichael Baum 				(uintptr_t)(&(*rxq->cqes)[zip->ca &
566a96102c8SMichael Baum 							  cqe_cnt].pkt_info);
567a96102c8SMichael Baum 			len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt &
568a96102c8SMichael Baum 					       rxq->byte_mask);
569a96102c8SMichael Baum 			*mcqe = &(*mc)[zip->ai & 7];
570a96102c8SMichael Baum 			if ((++zip->ai & 7) == 0) {
571a96102c8SMichael Baum 				/* Invalidate consumed CQEs */
572a96102c8SMichael Baum 				idx = zip->ca;
573a96102c8SMichael Baum 				end = zip->na;
574a96102c8SMichael Baum 				while (idx != end) {
575a96102c8SMichael Baum 					(*rxq->cqes)[idx & cqe_cnt].op_own =
576a96102c8SMichael Baum 						MLX5_CQE_INVALIDATE;
577a96102c8SMichael Baum 					++idx;
578a96102c8SMichael Baum 				}
579a96102c8SMichael Baum 				/*
580a96102c8SMichael Baum 				 * Increment consumer index to skip the number
581a96102c8SMichael Baum 				 * of CQEs consumed. Hardware leaves holes in
582a96102c8SMichael Baum 				 * the CQ ring for software use.
583a96102c8SMichael Baum 				 */
584a96102c8SMichael Baum 				zip->ca = zip->na;
585a96102c8SMichael Baum 				zip->na += 8;
586a96102c8SMichael Baum 			}
587a96102c8SMichael Baum 			if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
588a96102c8SMichael Baum 				/* Invalidate the rest */
589a96102c8SMichael Baum 				idx = zip->ca;
590a96102c8SMichael Baum 				end = zip->cq_ci;
591a96102c8SMichael Baum 
592a96102c8SMichael Baum 				while (idx != end) {
593a96102c8SMichael Baum 					(*rxq->cqes)[idx & cqe_cnt].op_own =
594a96102c8SMichael Baum 						MLX5_CQE_INVALIDATE;
595a96102c8SMichael Baum 					++idx;
596a96102c8SMichael Baum 				}
597a96102c8SMichael Baum 				rxq->cq_ci = zip->cq_ci;
598a96102c8SMichael Baum 				zip->ai = 0;
599a96102c8SMichael Baum 			}
600a96102c8SMichael Baum 		/*
601a96102c8SMichael Baum 		 * No compressed data, get next CQE and verify if it is
602a96102c8SMichael Baum 		 * compressed.
603a96102c8SMichael Baum 		 */
604a96102c8SMichael Baum 		} else {
605a96102c8SMichael Baum 			int ret;
606a96102c8SMichael Baum 			int8_t op_own;
607a96102c8SMichael Baum 			uint32_t cq_ci;
608a96102c8SMichael Baum 
609a96102c8SMichael Baum 			ret = check_cqe(cqe, cqe_n, rxq->cq_ci);
610a96102c8SMichael Baum 			if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
611a96102c8SMichael Baum 				if (unlikely(ret == MLX5_CQE_STATUS_ERR ||
612a96102c8SMichael Baum 					     rxq->err_state)) {
613a96102c8SMichael Baum 					ret = mlx5_rx_err_handle(rxq, 0);
614a96102c8SMichael Baum 					if (ret == MLX5_CQE_STATUS_HW_OWN ||
615a96102c8SMichael Baum 					    ret == -1)
616a96102c8SMichael Baum 						return 0;
617a96102c8SMichael Baum 				} else {
618a96102c8SMichael Baum 					return 0;
619a96102c8SMichael Baum 				}
620a96102c8SMichael Baum 			}
621a96102c8SMichael Baum 			/*
622a96102c8SMichael Baum 			 * Introduce the local variable to have queue cq_ci
623a96102c8SMichael Baum 			 * index in queue structure always consistent with
624a96102c8SMichael Baum 			 * actual CQE boundary (not pointing to the middle
625a96102c8SMichael Baum 			 * of compressed CQE session).
626a96102c8SMichael Baum 			 */
627a96102c8SMichael Baum 			cq_ci = rxq->cq_ci + 1;
628a96102c8SMichael Baum 			op_own = cqe->op_own;
629a96102c8SMichael Baum 			if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
630a96102c8SMichael Baum 				volatile struct mlx5_mini_cqe8 (*mc)[8] =
631a96102c8SMichael Baum 					(volatile struct mlx5_mini_cqe8 (*)[8])
632a96102c8SMichael Baum 					(uintptr_t)(&(*rxq->cqes)
633a96102c8SMichael Baum 						[cq_ci & cqe_cnt].pkt_info);
634a96102c8SMichael Baum 
635a96102c8SMichael Baum 				/* Fix endianness. */
636a96102c8SMichael Baum 				zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt);
637a96102c8SMichael Baum 				/*
638a96102c8SMichael Baum 				 * Current mini array position is the one
639a96102c8SMichael Baum 				 * returned by check_cqe64().
640a96102c8SMichael Baum 				 *
641a96102c8SMichael Baum 				 * If completion comprises several mini arrays,
642a96102c8SMichael Baum 				 * as a special case the second one is located
643a96102c8SMichael Baum 				 * 7 CQEs after the initial CQE instead of 8
644a96102c8SMichael Baum 				 * for subsequent ones.
645a96102c8SMichael Baum 				 */
646a96102c8SMichael Baum 				zip->ca = cq_ci;
647a96102c8SMichael Baum 				zip->na = zip->ca + 7;
648a96102c8SMichael Baum 				/* Compute the next non compressed CQE. */
649a96102c8SMichael Baum 				zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
650a96102c8SMichael Baum 				/* Get packet size to return. */
651a96102c8SMichael Baum 				len = rte_be_to_cpu_32((*mc)[0].byte_cnt &
652a96102c8SMichael Baum 						       rxq->byte_mask);
653a96102c8SMichael Baum 				*mcqe = &(*mc)[0];
654a96102c8SMichael Baum 				zip->ai = 1;
655a96102c8SMichael Baum 				/* Prefetch all to be invalidated */
656a96102c8SMichael Baum 				idx = zip->ca;
657a96102c8SMichael Baum 				end = zip->cq_ci;
658a96102c8SMichael Baum 				while (idx != end) {
659a96102c8SMichael Baum 					rte_prefetch0(&(*rxq->cqes)[(idx) &
660a96102c8SMichael Baum 								    cqe_cnt]);
661a96102c8SMichael Baum 					++idx;
662a96102c8SMichael Baum 				}
663a96102c8SMichael Baum 			} else {
664a96102c8SMichael Baum 				rxq->cq_ci = cq_ci;
665a96102c8SMichael Baum 				len = rte_be_to_cpu_32(cqe->byte_cnt);
666a96102c8SMichael Baum 			}
667a96102c8SMichael Baum 		}
668a96102c8SMichael Baum 		if (unlikely(rxq->err_state)) {
669a96102c8SMichael Baum 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
670a96102c8SMichael Baum 			++rxq->stats.idropped;
671a96102c8SMichael Baum 		} else {
672a96102c8SMichael Baum 			return len;
673a96102c8SMichael Baum 		}
674a96102c8SMichael Baum 	} while (1);
675a96102c8SMichael Baum }
676a96102c8SMichael Baum 
677a96102c8SMichael Baum /**
678a96102c8SMichael Baum  * Translate RX completion flags to offload flags.
679a96102c8SMichael Baum  *
680a96102c8SMichael Baum  * @param[in] cqe
681a96102c8SMichael Baum  *   Pointer to CQE.
682a96102c8SMichael Baum  *
683a96102c8SMichael Baum  * @return
684a96102c8SMichael Baum  *   Offload flags (ol_flags) for struct rte_mbuf.
685a96102c8SMichael Baum  */
686a96102c8SMichael Baum static inline uint32_t
687a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
688a96102c8SMichael Baum {
689a96102c8SMichael Baum 	uint32_t ol_flags = 0;
690a96102c8SMichael Baum 	uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
691a96102c8SMichael Baum 
692a96102c8SMichael Baum 	ol_flags =
693a96102c8SMichael Baum 		TRANSPOSE(flags,
694a96102c8SMichael Baum 			  MLX5_CQE_RX_L3_HDR_VALID,
695*daa02b5cSOlivier Matz 			  RTE_MBUF_F_RX_IP_CKSUM_GOOD) |
696a96102c8SMichael Baum 		TRANSPOSE(flags,
697a96102c8SMichael Baum 			  MLX5_CQE_RX_L4_HDR_VALID,
698*daa02b5cSOlivier Matz 			  RTE_MBUF_F_RX_L4_CKSUM_GOOD);
699a96102c8SMichael Baum 	return ol_flags;
700a96102c8SMichael Baum }
701a96102c8SMichael Baum 
702a96102c8SMichael Baum /**
703a96102c8SMichael Baum  * Fill in mbuf fields from RX completion flags.
704a96102c8SMichael Baum  * Note that pkt->ol_flags should be initialized outside of this function.
705a96102c8SMichael Baum  *
706a96102c8SMichael Baum  * @param rxq
707a96102c8SMichael Baum  *   Pointer to RX queue.
708a96102c8SMichael Baum  * @param pkt
709a96102c8SMichael Baum  *   mbuf to fill.
710a96102c8SMichael Baum  * @param cqe
711a96102c8SMichael Baum  *   CQE to process.
712a96102c8SMichael Baum  * @param rss_hash_res
713a96102c8SMichael Baum  *   Packet RSS Hash result.
714a96102c8SMichael Baum  */
715a96102c8SMichael Baum static inline void
716a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
717a96102c8SMichael Baum 	       volatile struct mlx5_cqe *cqe,
718a96102c8SMichael Baum 	       volatile struct mlx5_mini_cqe8 *mcqe)
719a96102c8SMichael Baum {
720a96102c8SMichael Baum 	/* Update packet information. */
721a96102c8SMichael Baum 	pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe, mcqe);
722a96102c8SMichael Baum 
723a96102c8SMichael Baum 	if (rxq->rss_hash) {
724a96102c8SMichael Baum 		uint32_t rss_hash_res = 0;
725a96102c8SMichael Baum 
726a96102c8SMichael Baum 		/* If compressed, take hash result from mini-CQE. */
727a96102c8SMichael Baum 		if (mcqe == NULL ||
728a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_HASH)
729a96102c8SMichael Baum 			rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
730a96102c8SMichael Baum 		else
731a96102c8SMichael Baum 			rss_hash_res = rte_be_to_cpu_32(mcqe->rx_hash_result);
732a96102c8SMichael Baum 		if (rss_hash_res) {
733a96102c8SMichael Baum 			pkt->hash.rss = rss_hash_res;
734*daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
735a96102c8SMichael Baum 		}
736a96102c8SMichael Baum 	}
737a96102c8SMichael Baum 	if (rxq->mark) {
738a96102c8SMichael Baum 		uint32_t mark = 0;
739a96102c8SMichael Baum 
740a96102c8SMichael Baum 		/* If compressed, take flow tag from mini-CQE. */
741a96102c8SMichael Baum 		if (mcqe == NULL ||
742a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
743a96102c8SMichael Baum 			mark = cqe->sop_drop_qpn;
744a96102c8SMichael Baum 		else
745a96102c8SMichael Baum 			mark = ((mcqe->byte_cnt_flow & 0xff) << 8) |
746a96102c8SMichael Baum 				(mcqe->flow_tag_high << 16);
747a96102c8SMichael Baum 		if (MLX5_FLOW_MARK_IS_VALID(mark)) {
748*daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_FDIR;
749a96102c8SMichael Baum 			if (mark != RTE_BE32(MLX5_FLOW_MARK_DEFAULT)) {
750*daa02b5cSOlivier Matz 				pkt->ol_flags |= RTE_MBUF_F_RX_FDIR_ID;
751a96102c8SMichael Baum 				pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
752a96102c8SMichael Baum 			}
753a96102c8SMichael Baum 		}
754a96102c8SMichael Baum 	}
755a96102c8SMichael Baum 	if (rxq->dynf_meta) {
7566d5735c1SAlexander Kozyrev 		uint32_t meta = rte_be_to_cpu_32(cqe->flow_table_metadata) &
757a96102c8SMichael Baum 			rxq->flow_meta_port_mask;
758a96102c8SMichael Baum 
759a96102c8SMichael Baum 		if (meta) {
760a96102c8SMichael Baum 			pkt->ol_flags |= rxq->flow_meta_mask;
761a96102c8SMichael Baum 			*RTE_MBUF_DYNFIELD(pkt, rxq->flow_meta_offset,
762a96102c8SMichael Baum 						uint32_t *) = meta;
763a96102c8SMichael Baum 		}
764a96102c8SMichael Baum 	}
765a96102c8SMichael Baum 	if (rxq->csum)
766a96102c8SMichael Baum 		pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
767a96102c8SMichael Baum 	if (rxq->vlan_strip) {
768a96102c8SMichael Baum 		bool vlan_strip;
769a96102c8SMichael Baum 
770a96102c8SMichael Baum 		if (mcqe == NULL ||
771a96102c8SMichael Baum 		    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
772a96102c8SMichael Baum 			vlan_strip = cqe->hdr_type_etc &
773a96102c8SMichael Baum 				     RTE_BE16(MLX5_CQE_VLAN_STRIPPED);
774a96102c8SMichael Baum 		else
775a96102c8SMichael Baum 			vlan_strip = mcqe->hdr_type &
776a96102c8SMichael Baum 				     RTE_BE16(MLX5_CQE_VLAN_STRIPPED);
777a96102c8SMichael Baum 		if (vlan_strip) {
778*daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
779a96102c8SMichael Baum 			pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
780a96102c8SMichael Baum 		}
781a96102c8SMichael Baum 	}
782a96102c8SMichael Baum 	if (rxq->hw_timestamp) {
783a96102c8SMichael Baum 		uint64_t ts = rte_be_to_cpu_64(cqe->timestamp);
784a96102c8SMichael Baum 
785a96102c8SMichael Baum 		if (rxq->rt_timestamp)
786a96102c8SMichael Baum 			ts = mlx5_txpp_convert_rx_ts(rxq->sh, ts);
787a96102c8SMichael Baum 		mlx5_timestamp_set(pkt, rxq->timestamp_offset, ts);
788a96102c8SMichael Baum 		pkt->ol_flags |= rxq->timestamp_rx_flag;
789a96102c8SMichael Baum 	}
790a96102c8SMichael Baum }
791a96102c8SMichael Baum 
792a96102c8SMichael Baum /**
793a96102c8SMichael Baum  * DPDK callback for RX.
794a96102c8SMichael Baum  *
795a96102c8SMichael Baum  * @param dpdk_rxq
796a96102c8SMichael Baum  *   Generic pointer to RX queue structure.
797a96102c8SMichael Baum  * @param[out] pkts
798a96102c8SMichael Baum  *   Array to store received packets.
799a96102c8SMichael Baum  * @param pkts_n
800a96102c8SMichael Baum  *   Maximum number of packets in array.
801a96102c8SMichael Baum  *
802a96102c8SMichael Baum  * @return
803a96102c8SMichael Baum  *   Number of packets successfully received (<= pkts_n).
804a96102c8SMichael Baum  */
805a96102c8SMichael Baum uint16_t
806a96102c8SMichael Baum mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
807a96102c8SMichael Baum {
808a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = dpdk_rxq;
809a96102c8SMichael Baum 	const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1;
810a96102c8SMichael Baum 	const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1;
811a96102c8SMichael Baum 	const unsigned int sges_n = rxq->sges_n;
812a96102c8SMichael Baum 	struct rte_mbuf *pkt = NULL;
813a96102c8SMichael Baum 	struct rte_mbuf *seg = NULL;
814a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe =
815a96102c8SMichael Baum 		&(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
816a96102c8SMichael Baum 	unsigned int i = 0;
817a96102c8SMichael Baum 	unsigned int rq_ci = rxq->rq_ci << sges_n;
818a96102c8SMichael Baum 	int len = 0; /* keep its value across iterations. */
819a96102c8SMichael Baum 
820a96102c8SMichael Baum 	while (pkts_n) {
821a96102c8SMichael Baum 		unsigned int idx = rq_ci & wqe_cnt;
822a96102c8SMichael Baum 		volatile struct mlx5_wqe_data_seg *wqe =
823a96102c8SMichael Baum 			&((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
824a96102c8SMichael Baum 		struct rte_mbuf *rep = (*rxq->elts)[idx];
825a96102c8SMichael Baum 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
826a96102c8SMichael Baum 
827a96102c8SMichael Baum 		if (pkt)
828a96102c8SMichael Baum 			NEXT(seg) = rep;
829a96102c8SMichael Baum 		seg = rep;
830a96102c8SMichael Baum 		rte_prefetch0(seg);
831a96102c8SMichael Baum 		rte_prefetch0(cqe);
832a96102c8SMichael Baum 		rte_prefetch0(wqe);
833a96102c8SMichael Baum 		/* Allocate the buf from the same pool. */
834a96102c8SMichael Baum 		rep = rte_mbuf_raw_alloc(seg->pool);
835a96102c8SMichael Baum 		if (unlikely(rep == NULL)) {
836a96102c8SMichael Baum 			++rxq->stats.rx_nombuf;
837a96102c8SMichael Baum 			if (!pkt) {
838a96102c8SMichael Baum 				/*
839a96102c8SMichael Baum 				 * no buffers before we even started,
840a96102c8SMichael Baum 				 * bail out silently.
841a96102c8SMichael Baum 				 */
842a96102c8SMichael Baum 				break;
843a96102c8SMichael Baum 			}
844a96102c8SMichael Baum 			while (pkt != seg) {
845a96102c8SMichael Baum 				MLX5_ASSERT(pkt != (*rxq->elts)[idx]);
846a96102c8SMichael Baum 				rep = NEXT(pkt);
847a96102c8SMichael Baum 				NEXT(pkt) = NULL;
848a96102c8SMichael Baum 				NB_SEGS(pkt) = 1;
849a96102c8SMichael Baum 				rte_mbuf_raw_free(pkt);
850a96102c8SMichael Baum 				pkt = rep;
851a96102c8SMichael Baum 			}
852a96102c8SMichael Baum 			rq_ci >>= sges_n;
853a96102c8SMichael Baum 			++rq_ci;
854a96102c8SMichael Baum 			rq_ci <<= sges_n;
855a96102c8SMichael Baum 			break;
856a96102c8SMichael Baum 		}
857a96102c8SMichael Baum 		if (!pkt) {
858a96102c8SMichael Baum 			cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt];
859a96102c8SMichael Baum 			len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe);
860a96102c8SMichael Baum 			if (!len) {
861a96102c8SMichael Baum 				rte_mbuf_raw_free(rep);
862a96102c8SMichael Baum 				break;
863a96102c8SMichael Baum 			}
864a96102c8SMichael Baum 			pkt = seg;
865a96102c8SMichael Baum 			MLX5_ASSERT(len >= (rxq->crc_present << 2));
866*daa02b5cSOlivier Matz 			pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
867a96102c8SMichael Baum 			rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
868a96102c8SMichael Baum 			if (rxq->crc_present)
869a96102c8SMichael Baum 				len -= RTE_ETHER_CRC_LEN;
870a96102c8SMichael Baum 			PKT_LEN(pkt) = len;
871a96102c8SMichael Baum 			if (cqe->lro_num_seg > 1) {
872a96102c8SMichael Baum 				mlx5_lro_update_hdr
873a96102c8SMichael Baum 					(rte_pktmbuf_mtod(pkt, uint8_t *), cqe,
874a96102c8SMichael Baum 					 mcqe, rxq, len);
875*daa02b5cSOlivier Matz 				pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
876a96102c8SMichael Baum 				pkt->tso_segsz = len / cqe->lro_num_seg;
877a96102c8SMichael Baum 			}
878a96102c8SMichael Baum 		}
879a96102c8SMichael Baum 		DATA_LEN(rep) = DATA_LEN(seg);
880a96102c8SMichael Baum 		PKT_LEN(rep) = PKT_LEN(seg);
881a96102c8SMichael Baum 		SET_DATA_OFF(rep, DATA_OFF(seg));
882a96102c8SMichael Baum 		PORT(rep) = PORT(seg);
883a96102c8SMichael Baum 		(*rxq->elts)[idx] = rep;
884a96102c8SMichael Baum 		/*
885a96102c8SMichael Baum 		 * Fill NIC descriptor with the new buffer. The lkey and size
886a96102c8SMichael Baum 		 * of the buffers are already known, only the buffer address
887a96102c8SMichael Baum 		 * changes.
888a96102c8SMichael Baum 		 */
889a96102c8SMichael Baum 		wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
890a96102c8SMichael Baum 		/* If there's only one MR, no need to replace LKey in WQE. */
891a96102c8SMichael Baum 		if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
892a96102c8SMichael Baum 			wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
893a96102c8SMichael Baum 		if (len > DATA_LEN(seg)) {
894a96102c8SMichael Baum 			len -= DATA_LEN(seg);
895a96102c8SMichael Baum 			++NB_SEGS(pkt);
896a96102c8SMichael Baum 			++rq_ci;
897a96102c8SMichael Baum 			continue;
898a96102c8SMichael Baum 		}
899a96102c8SMichael Baum 		DATA_LEN(seg) = len;
900a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
901a96102c8SMichael Baum 		/* Increment bytes counter. */
902a96102c8SMichael Baum 		rxq->stats.ibytes += PKT_LEN(pkt);
903a96102c8SMichael Baum #endif
904a96102c8SMichael Baum 		/* Return packet. */
905a96102c8SMichael Baum 		*(pkts++) = pkt;
906a96102c8SMichael Baum 		pkt = NULL;
907a96102c8SMichael Baum 		--pkts_n;
908a96102c8SMichael Baum 		++i;
909a96102c8SMichael Baum 		/* Align consumer index to the next stride. */
910a96102c8SMichael Baum 		rq_ci >>= sges_n;
911a96102c8SMichael Baum 		++rq_ci;
912a96102c8SMichael Baum 		rq_ci <<= sges_n;
913a96102c8SMichael Baum 	}
914a96102c8SMichael Baum 	if (unlikely(i == 0 && ((rq_ci >> sges_n) == rxq->rq_ci)))
915a96102c8SMichael Baum 		return 0;
916a96102c8SMichael Baum 	/* Update the consumer index. */
917a96102c8SMichael Baum 	rxq->rq_ci = rq_ci >> sges_n;
918a96102c8SMichael Baum 	rte_io_wmb();
919a96102c8SMichael Baum 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
920a96102c8SMichael Baum 	rte_io_wmb();
921a96102c8SMichael Baum 	*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
922a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
923a96102c8SMichael Baum 	/* Increment packets counter. */
924a96102c8SMichael Baum 	rxq->stats.ipackets += i;
925a96102c8SMichael Baum #endif
926a96102c8SMichael Baum 	return i;
927a96102c8SMichael Baum }
928a96102c8SMichael Baum 
929a96102c8SMichael Baum /**
930a96102c8SMichael Baum  * Update LRO packet TCP header.
931a96102c8SMichael Baum  * The HW LRO feature doesn't update the TCP header after coalescing the
932a96102c8SMichael Baum  * TCP segments but supplies information in CQE to fill it by SW.
933a96102c8SMichael Baum  *
934a96102c8SMichael Baum  * @param tcp
935a96102c8SMichael Baum  *   Pointer to the TCP header.
936a96102c8SMichael Baum  * @param cqe
937a96102c8SMichael Baum  *   Pointer to the completion entry.
938a96102c8SMichael Baum  * @param phcsum
939a96102c8SMichael Baum  *   The L3 pseudo-header checksum.
940a96102c8SMichael Baum  */
941a96102c8SMichael Baum static inline void
942a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
943a96102c8SMichael Baum 			volatile struct mlx5_cqe *__rte_restrict cqe,
944a96102c8SMichael Baum 			uint32_t phcsum, uint8_t l4_type)
945a96102c8SMichael Baum {
946a96102c8SMichael Baum 	/*
947a96102c8SMichael Baum 	 * The HW calculates only the TCP payload checksum, need to complete
948a96102c8SMichael Baum 	 * the TCP header checksum and the L3 pseudo-header checksum.
949a96102c8SMichael Baum 	 */
950a96102c8SMichael Baum 	uint32_t csum = phcsum + cqe->csum;
951a96102c8SMichael Baum 
952a96102c8SMichael Baum 	if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK ||
953a96102c8SMichael Baum 	    l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) {
954a96102c8SMichael Baum 		tcp->tcp_flags |= RTE_TCP_ACK_FLAG;
955a96102c8SMichael Baum 		tcp->recv_ack = cqe->lro_ack_seq_num;
956a96102c8SMichael Baum 		tcp->rx_win = cqe->lro_tcp_win;
957a96102c8SMichael Baum 	}
958a96102c8SMichael Baum 	if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK)
959a96102c8SMichael Baum 		tcp->tcp_flags |= RTE_TCP_PSH_FLAG;
960a96102c8SMichael Baum 	tcp->cksum = 0;
961a96102c8SMichael Baum 	csum += rte_raw_cksum(tcp, (tcp->data_off >> 4) * 4);
962a96102c8SMichael Baum 	csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
963a96102c8SMichael Baum 	csum = (~csum) & 0xffff;
964a96102c8SMichael Baum 	if (csum == 0)
965a96102c8SMichael Baum 		csum = 0xffff;
966a96102c8SMichael Baum 	tcp->cksum = csum;
967a96102c8SMichael Baum }
968a96102c8SMichael Baum 
969a96102c8SMichael Baum /**
970a96102c8SMichael Baum  * Update LRO packet headers.
971a96102c8SMichael Baum  * The HW LRO feature doesn't update the L3/TCP headers after coalescing the
972a96102c8SMichael Baum  * TCP segments but supply information in CQE to fill it by SW.
973a96102c8SMichael Baum  *
974a96102c8SMichael Baum  * @param padd
975a96102c8SMichael Baum  *   The packet address.
976a96102c8SMichael Baum  * @param cqe
977a96102c8SMichael Baum  *   Pointer to the completion entry.
978a96102c8SMichael Baum  * @param len
979a96102c8SMichael Baum  *   The packet length.
980a96102c8SMichael Baum  */
981a96102c8SMichael Baum static inline void
982a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
983a96102c8SMichael Baum 		    volatile struct mlx5_cqe *__rte_restrict cqe,
984a96102c8SMichael Baum 		    volatile struct mlx5_mini_cqe8 *mcqe,
985a96102c8SMichael Baum 		    struct mlx5_rxq_data *rxq, uint32_t len)
986a96102c8SMichael Baum {
987a96102c8SMichael Baum 	union {
988a96102c8SMichael Baum 		struct rte_ether_hdr *eth;
989a96102c8SMichael Baum 		struct rte_vlan_hdr *vlan;
990a96102c8SMichael Baum 		struct rte_ipv4_hdr *ipv4;
991a96102c8SMichael Baum 		struct rte_ipv6_hdr *ipv6;
992a96102c8SMichael Baum 		struct rte_tcp_hdr *tcp;
993a96102c8SMichael Baum 		uint8_t *hdr;
994a96102c8SMichael Baum 	} h = {
995a96102c8SMichael Baum 		.hdr = padd,
996a96102c8SMichael Baum 	};
997a96102c8SMichael Baum 	uint16_t proto = h.eth->ether_type;
998a96102c8SMichael Baum 	uint32_t phcsum;
999a96102c8SMichael Baum 	uint8_t l4_type;
1000a96102c8SMichael Baum 
1001a96102c8SMichael Baum 	h.eth++;
1002a96102c8SMichael Baum 	while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
1003a96102c8SMichael Baum 	       proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
1004a96102c8SMichael Baum 		proto = h.vlan->eth_proto;
1005a96102c8SMichael Baum 		h.vlan++;
1006a96102c8SMichael Baum 	}
1007a96102c8SMichael Baum 	if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
1008a96102c8SMichael Baum 		h.ipv4->time_to_live = cqe->lro_min_ttl;
1009a96102c8SMichael Baum 		h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd));
1010a96102c8SMichael Baum 		h.ipv4->hdr_checksum = 0;
1011a96102c8SMichael Baum 		h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4);
1012a96102c8SMichael Baum 		phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0);
1013a96102c8SMichael Baum 		h.ipv4++;
1014a96102c8SMichael Baum 	} else {
1015a96102c8SMichael Baum 		h.ipv6->hop_limits = cqe->lro_min_ttl;
1016a96102c8SMichael Baum 		h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) -
1017a96102c8SMichael Baum 						       sizeof(*h.ipv6));
1018a96102c8SMichael Baum 		phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0);
1019a96102c8SMichael Baum 		h.ipv6++;
1020a96102c8SMichael Baum 	}
1021a96102c8SMichael Baum 	if (mcqe == NULL ||
1022a96102c8SMichael Baum 	    rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
1023a96102c8SMichael Baum 		l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) &
1024a96102c8SMichael Baum 			   MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1025a96102c8SMichael Baum 	else
1026a96102c8SMichael Baum 		l4_type = (rte_be_to_cpu_16(mcqe->hdr_type) &
1027a96102c8SMichael Baum 			   MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1028a96102c8SMichael Baum 	mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum, l4_type);
1029a96102c8SMichael Baum }
1030a96102c8SMichael Baum 
1031a96102c8SMichael Baum void
1032a96102c8SMichael Baum mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
1033a96102c8SMichael Baum {
1034a96102c8SMichael Baum 	mlx5_mprq_buf_free_cb(NULL, buf);
1035a96102c8SMichael Baum }
1036a96102c8SMichael Baum 
1037a96102c8SMichael Baum /**
1038a96102c8SMichael Baum  * DPDK callback for RX with Multi-Packet RQ support.
1039a96102c8SMichael Baum  *
1040a96102c8SMichael Baum  * @param dpdk_rxq
1041a96102c8SMichael Baum  *   Generic pointer to RX queue structure.
1042a96102c8SMichael Baum  * @param[out] pkts
1043a96102c8SMichael Baum  *   Array to store received packets.
1044a96102c8SMichael Baum  * @param pkts_n
1045a96102c8SMichael Baum  *   Maximum number of packets in array.
1046a96102c8SMichael Baum  *
1047a96102c8SMichael Baum  * @return
1048a96102c8SMichael Baum  *   Number of packets successfully received (<= pkts_n).
1049a96102c8SMichael Baum  */
1050a96102c8SMichael Baum uint16_t
1051a96102c8SMichael Baum mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1052a96102c8SMichael Baum {
1053a96102c8SMichael Baum 	struct mlx5_rxq_data *rxq = dpdk_rxq;
1054a96102c8SMichael Baum 	const uint32_t strd_n = 1 << rxq->strd_num_n;
1055a96102c8SMichael Baum 	const uint32_t strd_sz = 1 << rxq->strd_sz_n;
1056a96102c8SMichael Baum 	const uint32_t cq_mask = (1 << rxq->cqe_n) - 1;
1057a96102c8SMichael Baum 	const uint32_t wq_mask = (1 << rxq->elts_n) - 1;
1058a96102c8SMichael Baum 	volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1059a96102c8SMichael Baum 	unsigned int i = 0;
1060a96102c8SMichael Baum 	uint32_t rq_ci = rxq->rq_ci;
1061a96102c8SMichael Baum 	uint16_t consumed_strd = rxq->consumed_strd;
1062a96102c8SMichael Baum 	struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1063a96102c8SMichael Baum 
1064a96102c8SMichael Baum 	while (i < pkts_n) {
1065a96102c8SMichael Baum 		struct rte_mbuf *pkt;
1066a96102c8SMichael Baum 		int ret;
1067a96102c8SMichael Baum 		uint32_t len;
1068a96102c8SMichael Baum 		uint16_t strd_cnt;
1069a96102c8SMichael Baum 		uint16_t strd_idx;
1070a96102c8SMichael Baum 		uint32_t byte_cnt;
1071a96102c8SMichael Baum 		volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1072a96102c8SMichael Baum 		enum mlx5_rqx_code rxq_code;
1073a96102c8SMichael Baum 
1074a96102c8SMichael Baum 		if (consumed_strd == strd_n) {
1075a96102c8SMichael Baum 			/* Replace WQE if the buffer is still in use. */
1076a96102c8SMichael Baum 			mprq_buf_replace(rxq, rq_ci & wq_mask);
1077a96102c8SMichael Baum 			/* Advance to the next WQE. */
1078a96102c8SMichael Baum 			consumed_strd = 0;
1079a96102c8SMichael Baum 			++rq_ci;
1080a96102c8SMichael Baum 			buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1081a96102c8SMichael Baum 		}
1082a96102c8SMichael Baum 		cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1083a96102c8SMichael Baum 		ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe);
1084a96102c8SMichael Baum 		if (!ret)
1085a96102c8SMichael Baum 			break;
1086a96102c8SMichael Baum 		byte_cnt = ret;
1087a96102c8SMichael Baum 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1088a96102c8SMichael Baum 		MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1089a96102c8SMichael Baum 		if (rxq->crc_present)
1090a96102c8SMichael Baum 			len -= RTE_ETHER_CRC_LEN;
1091a96102c8SMichael Baum 		if (mcqe &&
1092a96102c8SMichael Baum 		    rxq->mcqe_format == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
1093a96102c8SMichael Baum 			strd_cnt = (len / strd_sz) + !!(len % strd_sz);
1094a96102c8SMichael Baum 		else
1095a96102c8SMichael Baum 			strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
1096a96102c8SMichael Baum 				   MLX5_MPRQ_STRIDE_NUM_SHIFT;
1097a96102c8SMichael Baum 		MLX5_ASSERT(strd_cnt);
1098a96102c8SMichael Baum 		consumed_strd += strd_cnt;
1099a96102c8SMichael Baum 		if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
1100a96102c8SMichael Baum 			continue;
1101a96102c8SMichael Baum 		strd_idx = rte_be_to_cpu_16(mcqe == NULL ?
1102a96102c8SMichael Baum 					cqe->wqe_counter :
1103a96102c8SMichael Baum 					mcqe->stride_idx);
1104a96102c8SMichael Baum 		MLX5_ASSERT(strd_idx < strd_n);
1105a96102c8SMichael Baum 		MLX5_ASSERT(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) &
1106a96102c8SMichael Baum 			    wq_mask));
1107a96102c8SMichael Baum 		pkt = rte_pktmbuf_alloc(rxq->mp);
1108a96102c8SMichael Baum 		if (unlikely(pkt == NULL)) {
1109a96102c8SMichael Baum 			++rxq->stats.rx_nombuf;
1110a96102c8SMichael Baum 			break;
1111a96102c8SMichael Baum 		}
1112a96102c8SMichael Baum 		len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1113a96102c8SMichael Baum 		MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1114a96102c8SMichael Baum 		if (rxq->crc_present)
1115a96102c8SMichael Baum 			len -= RTE_ETHER_CRC_LEN;
1116a96102c8SMichael Baum 		rxq_code = mprq_buf_to_pkt(rxq, pkt, len, buf,
1117a96102c8SMichael Baum 					   strd_idx, strd_cnt);
1118a96102c8SMichael Baum 		if (unlikely(rxq_code != MLX5_RXQ_CODE_EXIT)) {
1119a96102c8SMichael Baum 			rte_pktmbuf_free_seg(pkt);
1120a96102c8SMichael Baum 			if (rxq_code == MLX5_RXQ_CODE_DROPPED) {
1121a96102c8SMichael Baum 				++rxq->stats.idropped;
1122a96102c8SMichael Baum 				continue;
1123a96102c8SMichael Baum 			}
1124a96102c8SMichael Baum 			if (rxq_code == MLX5_RXQ_CODE_NOMBUF) {
1125a96102c8SMichael Baum 				++rxq->stats.rx_nombuf;
1126a96102c8SMichael Baum 				break;
1127a96102c8SMichael Baum 			}
1128a96102c8SMichael Baum 		}
1129a96102c8SMichael Baum 		rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1130a96102c8SMichael Baum 		if (cqe->lro_num_seg > 1) {
1131a96102c8SMichael Baum 			mlx5_lro_update_hdr(rte_pktmbuf_mtod(pkt, uint8_t *),
1132a96102c8SMichael Baum 					    cqe, mcqe, rxq, len);
1133*daa02b5cSOlivier Matz 			pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1134a96102c8SMichael Baum 			pkt->tso_segsz = len / cqe->lro_num_seg;
1135a96102c8SMichael Baum 		}
1136a96102c8SMichael Baum 		PKT_LEN(pkt) = len;
1137a96102c8SMichael Baum 		PORT(pkt) = rxq->port_id;
1138a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1139a96102c8SMichael Baum 		/* Increment bytes counter. */
1140a96102c8SMichael Baum 		rxq->stats.ibytes += PKT_LEN(pkt);
1141a96102c8SMichael Baum #endif
1142a96102c8SMichael Baum 		/* Return packet. */
1143a96102c8SMichael Baum 		*(pkts++) = pkt;
1144a96102c8SMichael Baum 		++i;
1145a96102c8SMichael Baum 	}
1146a96102c8SMichael Baum 	/* Update the consumer indexes. */
1147a96102c8SMichael Baum 	rxq->consumed_strd = consumed_strd;
1148a96102c8SMichael Baum 	rte_io_wmb();
1149a96102c8SMichael Baum 	*rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1150a96102c8SMichael Baum 	if (rq_ci != rxq->rq_ci) {
1151a96102c8SMichael Baum 		rxq->rq_ci = rq_ci;
1152a96102c8SMichael Baum 		rte_io_wmb();
1153a96102c8SMichael Baum 		*rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1154a96102c8SMichael Baum 	}
1155a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS
1156a96102c8SMichael Baum 	/* Increment packets counter. */
1157a96102c8SMichael Baum 	rxq->stats.ipackets += i;
1158a96102c8SMichael Baum #endif
1159a96102c8SMichael Baum 	return i;
1160a96102c8SMichael Baum }
1161a96102c8SMichael Baum 
1162a96102c8SMichael Baum /**
1163a96102c8SMichael Baum  * Dummy DPDK callback for RX.
1164a96102c8SMichael Baum  *
1165a96102c8SMichael Baum  * This function is used to temporarily replace the real callback during
1166a96102c8SMichael Baum  * unsafe control operations on the queue, or in case of error.
1167a96102c8SMichael Baum  *
1168a96102c8SMichael Baum  * @param dpdk_rxq
1169a96102c8SMichael Baum  *   Generic pointer to RX queue structure.
1170a96102c8SMichael Baum  * @param[out] pkts
1171a96102c8SMichael Baum  *   Array to store received packets.
1172a96102c8SMichael Baum  * @param pkts_n
1173a96102c8SMichael Baum  *   Maximum number of packets in array.
1174a96102c8SMichael Baum  *
1175a96102c8SMichael Baum  * @return
1176a96102c8SMichael Baum  *   Number of packets successfully received (<= pkts_n).
1177a96102c8SMichael Baum  */
1178a96102c8SMichael Baum uint16_t
1179a96102c8SMichael Baum removed_rx_burst(void *dpdk_rxq __rte_unused,
1180a96102c8SMichael Baum 		 struct rte_mbuf **pkts __rte_unused,
1181a96102c8SMichael Baum 		 uint16_t pkts_n __rte_unused)
1182a96102c8SMichael Baum {
1183a96102c8SMichael Baum 	rte_mb();
1184a96102c8SMichael Baum 	return 0;
1185a96102c8SMichael Baum }
1186a96102c8SMichael Baum 
1187a96102c8SMichael Baum /*
1188a96102c8SMichael Baum  * Vectorized Rx routines are not compiled in when required vector instructions
1189a96102c8SMichael Baum  * are not supported on a target architecture.
1190a96102c8SMichael Baum  * The following null stubs are needed for linkage when those are not included
1191a96102c8SMichael Baum  * outside of this file (e.g. mlx5_rxtx_vec_sse.c for x86).
1192a96102c8SMichael Baum  */
1193a96102c8SMichael Baum 
1194a96102c8SMichael Baum __rte_weak uint16_t
1195a96102c8SMichael Baum mlx5_rx_burst_vec(void *dpdk_rxq __rte_unused,
1196a96102c8SMichael Baum 		  struct rte_mbuf **pkts __rte_unused,
1197a96102c8SMichael Baum 		  uint16_t pkts_n __rte_unused)
1198a96102c8SMichael Baum {
1199a96102c8SMichael Baum 	return 0;
1200a96102c8SMichael Baum }
1201a96102c8SMichael Baum 
1202a96102c8SMichael Baum __rte_weak uint16_t
1203a96102c8SMichael Baum mlx5_rx_burst_mprq_vec(void *dpdk_rxq __rte_unused,
1204a96102c8SMichael Baum 		       struct rte_mbuf **pkts __rte_unused,
1205a96102c8SMichael Baum 		       uint16_t pkts_n __rte_unused)
1206a96102c8SMichael Baum {
1207a96102c8SMichael Baum 	return 0;
1208a96102c8SMichael Baum }
1209a96102c8SMichael Baum 
1210a96102c8SMichael Baum __rte_weak int
1211a96102c8SMichael Baum mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused)
1212a96102c8SMichael Baum {
1213a96102c8SMichael Baum 	return -ENOTSUP;
1214a96102c8SMichael Baum }
1215a96102c8SMichael Baum 
1216a96102c8SMichael Baum __rte_weak int
1217a96102c8SMichael Baum mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused)
1218a96102c8SMichael Baum {
1219a96102c8SMichael Baum 	return -ENOTSUP;
1220a96102c8SMichael Baum }
1221a96102c8SMichael Baum 
1222