Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2021 6WIND S.A.
3 : : * Copyright 2021 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #include <stdint.h>
7 : : #include <string.h>
8 : : #include <stdlib.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_mbuf.h>
12 : : #include <rte_mempool.h>
13 : : #include <rte_prefetch.h>
14 : : #include <rte_common.h>
15 : : #include <rte_branch_prediction.h>
16 : : #include <rte_ether.h>
17 : : #include <rte_cycles.h>
18 : : #include <rte_flow.h>
19 : :
20 : : #include <mlx5_prm.h>
21 : : #include <mlx5_common.h>
22 : : #include <mlx5_common_mr.h>
23 : : #include <rte_pmd_mlx5.h>
24 : :
25 : : #include "mlx5_autoconf.h"
26 : : #include "mlx5_defs.h"
27 : : #include "mlx5.h"
28 : : #include "mlx5_utils.h"
29 : : #include "mlx5_rxtx.h"
30 : : #include "mlx5_devx.h"
31 : : #include "mlx5_rx.h"
32 : : #ifdef HAVE_MLX5_MSTFLINT
33 : : #include <mstflint/mtcr.h>
34 : : #endif
35 : :
36 : :
37 : : static __rte_always_inline uint32_t
38 : : rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
39 : : volatile struct mlx5_mini_cqe8 *mcqe);
40 : :
41 : : static __rte_always_inline int
42 : : mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
43 : : uint16_t cqe_n, uint16_t cqe_mask,
44 : : volatile struct mlx5_mini_cqe8 **mcqe,
45 : : uint16_t *skip_cnt, bool mprq, uint32_t *widx);
46 : :
47 : : static __rte_always_inline uint32_t
48 : : rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe);
49 : :
50 : : static __rte_always_inline void
51 : : rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
52 : : volatile struct mlx5_cqe *cqe,
53 : : volatile struct mlx5_mini_cqe8 *mcqe);
54 : :
55 : : static inline void
56 : : mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
57 : : volatile struct mlx5_cqe *__rte_restrict cqe,
58 : : uint32_t phcsum, uint8_t l4_type);
59 : :
60 : : static inline void
61 : : mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
62 : : volatile struct mlx5_cqe *__rte_restrict cqe,
63 : : volatile struct mlx5_mini_cqe8 *mcqe,
64 : : struct mlx5_rxq_data *rxq, uint32_t len);
65 : :
66 : :
67 : : /**
68 : : * Internal function to compute the number of used descriptors in an RX queue.
69 : : *
70 : : * @param rxq
71 : : * The Rx queue.
72 : : *
73 : : * @return
74 : : * The number of used Rx descriptor.
75 : : */
76 : : static int
77 : 0 : rx_queue_count(struct mlx5_rxq_data *rxq)
78 : : {
79 : : struct rxq_zip *zip = &rxq->zip;
80 : : volatile struct mlx5_cqe *cqe;
81 : 0 : const unsigned int cqe_n = (1 << rxq->cqe_n);
82 : 0 : const unsigned int sges_n = (1 << rxq->sges_n);
83 : 0 : const unsigned int elts_n = (1 << rxq->elts_n);
84 : 0 : const unsigned int strd_n = RTE_BIT32(rxq->log_strd_num);
85 : 0 : const unsigned int cqe_cnt = cqe_n - 1;
86 : : unsigned int cq_ci, used;
87 : :
88 : : /* if we are processing a compressed cqe */
89 [ # # ]: 0 : if (zip->ai) {
90 : 0 : used = zip->cqe_cnt - zip->ai;
91 : 0 : cq_ci = zip->cq_ci;
92 : : } else {
93 : : used = 0;
94 : 0 : cq_ci = rxq->cq_ci;
95 : : }
96 : 0 : cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
97 [ # # ]: 0 : while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) {
98 : : int8_t op_own;
99 : : unsigned int n;
100 : :
101 : 0 : op_own = cqe->op_own;
102 [ # # ]: 0 : if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED)
103 : 0 : n = rte_be_to_cpu_32(cqe->byte_cnt);
104 : : else
105 : : n = 1;
106 : 0 : cq_ci += n;
107 : 0 : used += n;
108 : 0 : cqe = &(*rxq->cqes)[cq_ci & cqe_cnt];
109 : : }
110 : 0 : used = RTE_MIN(used * sges_n, elts_n * strd_n);
111 : 0 : return used;
112 : : }
113 : :
114 : : /**
115 : : * DPDK callback to check the status of a Rx descriptor.
116 : : *
117 : : * @param rx_queue
118 : : * The Rx queue.
119 : : * @param[in] offset
120 : : * The index of the descriptor in the ring.
121 : : *
122 : : * @return
123 : : * The status of the Rx descriptor.
124 : : */
125 : : int
126 : 0 : mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset)
127 : : {
128 : : struct mlx5_rxq_data *rxq = rx_queue;
129 : :
130 [ # # ]: 0 : if (offset >= (1 << rxq->cqe_n)) {
131 : 0 : rte_errno = EINVAL;
132 : 0 : return -rte_errno;
133 : : }
134 [ # # ]: 0 : if (offset < rx_queue_count(rxq))
135 : 0 : return RTE_ETH_RX_DESC_DONE;
136 : : return RTE_ETH_RX_DESC_AVAIL;
137 : : }
138 : :
139 : : /* Get rxq lwm percentage according to lwm number. */
140 : : static uint8_t
141 : : mlx5_rxq_lwm_to_percentage(struct mlx5_rxq_priv *rxq)
142 : : {
143 : 0 : struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq;
144 : 0 : uint32_t wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
145 : :
146 : 0 : return rxq->lwm * 100 / wqe_cnt;
147 : : }
148 : :
149 : : /**
150 : : * DPDK callback to get the RX queue information.
151 : : *
152 : : * @param dev
153 : : * Pointer to the device structure.
154 : : *
155 : : * @param rx_queue_id
156 : : * Rx queue identificator.
157 : : *
158 : : * @param qinfo
159 : : * Pointer to the RX queue information structure.
160 : : *
161 : : * @return
162 : : * None.
163 : : */
164 : :
165 : : void
166 : 0 : mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id,
167 : : struct rte_eth_rxq_info *qinfo)
168 : : {
169 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, rx_queue_id);
170 : 0 : struct mlx5_rxq_data *rxq = mlx5_rxq_data_get(dev, rx_queue_id);
171 : 0 : struct mlx5_rxq_priv *rxq_priv = mlx5_rxq_get(dev, rx_queue_id);
172 : :
173 [ # # ]: 0 : if (!rxq)
174 : : return;
175 : 0 : qinfo->mp = mlx5_rxq_mprq_enabled(rxq) ?
176 [ # # ]: 0 : rxq->mprq_mp : rxq->mp;
177 : 0 : qinfo->conf.rx_thresh.pthresh = 0;
178 : 0 : qinfo->conf.rx_thresh.hthresh = 0;
179 : 0 : qinfo->conf.rx_thresh.wthresh = 0;
180 : 0 : qinfo->conf.rx_free_thresh = rxq->rq_repl_thresh;
181 : 0 : qinfo->conf.rx_drop_en = 1;
182 [ # # # # ]: 0 : if (rxq_ctrl == NULL || rxq_ctrl->obj == NULL)
183 : 0 : qinfo->conf.rx_deferred_start = 0;
184 : : else
185 : 0 : qinfo->conf.rx_deferred_start = 1;
186 : 0 : qinfo->conf.offloads = dev->data->dev_conf.rxmode.offloads;
187 : 0 : qinfo->scattered_rx = dev->data->scattered_rx;
188 [ # # ]: 0 : qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ?
189 : 0 : RTE_BIT32(rxq->elts_n) * RTE_BIT32(rxq->log_strd_num) :
190 : 0 : RTE_BIT32(rxq->elts_n);
191 [ # # ]: 0 : qinfo->avail_thresh = rxq_priv ?
192 : : mlx5_rxq_lwm_to_percentage(rxq_priv) : 0;
193 [ # # ]: 0 : if (rxq_ctrl != NULL) {
194 : 0 : qinfo->conf.share_group = rxq_ctrl->share_group;
195 : 0 : qinfo->conf.share_qid = rxq_ctrl->share_qid;
196 : : }
197 : : }
198 : :
199 : : /**
200 : : * DPDK callback to get the RX packet burst mode information.
201 : : *
202 : : * @param dev
203 : : * Pointer to the device structure.
204 : : *
205 : : * @param rx_queue_id
206 : : * Rx queue identification.
207 : : *
208 : : * @param mode
209 : : * Pointer to the burts mode information.
210 : : *
211 : : * @return
212 : : * 0 as success, -EINVAL as failure.
213 : : */
214 : : int
215 : 0 : mlx5_rx_burst_mode_get(struct rte_eth_dev *dev,
216 : : uint16_t rx_queue_id __rte_unused,
217 : : struct rte_eth_burst_mode *mode)
218 : : {
219 : 0 : eth_rx_burst_t pkt_burst = dev->rx_pkt_burst;
220 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id);
221 : :
222 [ # # ]: 0 : if (!rxq) {
223 : 0 : rte_errno = EINVAL;
224 : 0 : return -rte_errno;
225 : : }
226 [ # # ]: 0 : if (pkt_burst == mlx5_rx_burst) {
227 : 0 : snprintf(mode->info, sizeof(mode->info), "%s", "Scalar");
228 [ # # ]: 0 : } else if (pkt_burst == mlx5_rx_burst_out_of_order) {
229 : 0 : snprintf(mode->info, sizeof(mode->info), "%s", "Scalar Out-of-Order");
230 [ # # ]: 0 : } else if (pkt_burst == mlx5_rx_burst_mprq) {
231 : 0 : snprintf(mode->info, sizeof(mode->info), "%s", "Multi-Packet RQ");
232 [ # # ]: 0 : } else if (pkt_burst == mlx5_rx_burst_vec) {
233 : : #if defined RTE_ARCH_X86_64
234 : 0 : snprintf(mode->info, sizeof(mode->info), "%s", "Vector SSE");
235 : : #elif defined RTE_ARCH_ARM64
236 : : snprintf(mode->info, sizeof(mode->info), "%s", "Vector Neon");
237 : : #elif defined RTE_ARCH_PPC_64
238 : : snprintf(mode->info, sizeof(mode->info), "%s", "Vector AltiVec");
239 : : #else
240 : : return -EINVAL;
241 : : #endif
242 [ # # ]: 0 : } else if (pkt_burst == mlx5_rx_burst_mprq_vec) {
243 : : #if defined RTE_ARCH_X86_64
244 : 0 : snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector SSE");
245 : : #elif defined RTE_ARCH_ARM64
246 : : snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector Neon");
247 : : #elif defined RTE_ARCH_PPC_64
248 : : snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector AltiVec");
249 : : #else
250 : : return -EINVAL;
251 : : #endif
252 : : } else {
253 : : return -EINVAL;
254 : : }
255 : : return 0;
256 : : }
257 : :
258 : : /**
259 : : * DPDK callback to get the number of used descriptors in a RX queue.
260 : : *
261 : : * @param rx_queue
262 : : * The Rx queue pointer.
263 : : *
264 : : * @return
265 : : * The number of used rx descriptor.
266 : : * -EINVAL if the queue is invalid
267 : : */
268 : : int
269 : 0 : mlx5_rx_queue_count(void *rx_queue)
270 : : {
271 : : struct mlx5_rxq_data *rxq = rx_queue;
272 : : struct rte_eth_dev *dev;
273 : :
274 [ # # ]: 0 : if (!rxq) {
275 : 0 : rte_errno = EINVAL;
276 : 0 : return -rte_errno;
277 : : }
278 : :
279 : 0 : dev = &rte_eth_devices[rxq->port_id];
280 : :
281 [ # # # # ]: 0 : if (dev->rx_pkt_burst == NULL ||
282 : : dev->rx_pkt_burst == rte_eth_pkt_burst_dummy) {
283 : 0 : rte_errno = ENOTSUP;
284 : 0 : return -rte_errno;
285 : : }
286 : :
287 : 0 : return rx_queue_count(rxq);
288 : : }
289 : :
290 : : #define CLB_VAL_IDX 0
291 : : #define CLB_MSK_IDX 1
292 : : static int
293 : 0 : mlx5_monitor_callback(const uint64_t value,
294 : : const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
295 : : {
296 : 0 : const uint64_t m = opaque[CLB_MSK_IDX];
297 : 0 : const uint64_t v = opaque[CLB_VAL_IDX];
298 : :
299 [ # # ]: 0 : return (value & m) == v ? -1 : 0;
300 : : }
301 : :
302 : : static int
303 : 0 : mlx5_monitor_cqe_own_callback(const uint64_t value,
304 : : const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
305 : : {
306 : 0 : const uint64_t m = opaque[CLB_MSK_IDX];
307 : 0 : const uint64_t v = opaque[CLB_VAL_IDX];
308 : 0 : const uint64_t sw_owned = ((value & m) == v);
309 : 0 : const uint64_t opcode = MLX5_CQE_OPCODE(value);
310 : 0 : const uint64_t valid_op = (opcode != MLX5_CQE_INVALID);
311 : :
312 : : /* ownership bit is not valid for invalid opcode; CQE is HW owned */
313 : 0 : return -(valid_op & sw_owned);
314 : : }
315 : :
316 : 0 : int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
317 : : {
318 : : struct mlx5_rxq_data *rxq = rx_queue;
319 : 0 : const unsigned int cqe_num = 1 << rxq->cqe_n;
320 : 0 : const unsigned int cqe_mask = cqe_num - 1;
321 : 0 : const uint16_t idx = rxq->cq_ci & cqe_num;
322 : 0 : const uint8_t vic = rxq->cq_ci >> rxq->cqe_n;
323 : 0 : volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
324 : :
325 [ # # ]: 0 : if (unlikely(rxq->cqes == NULL)) {
326 : 0 : rte_errno = EINVAL;
327 : 0 : return -rte_errno;
328 : : }
329 [ # # ]: 0 : if (rxq->cqe_comp_layout) {
330 : 0 : pmc->addr = &cqe->validity_iteration_count;
331 : 0 : pmc->opaque[CLB_VAL_IDX] = vic;
332 : 0 : pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_VIC_INIT;
333 : 0 : pmc->fn = mlx5_monitor_callback;
334 : : } else {
335 : 0 : pmc->addr = &cqe->op_own;
336 : 0 : pmc->opaque[CLB_VAL_IDX] = !!idx;
337 : 0 : pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_OWNER_MASK;
338 : 0 : pmc->fn = mlx5_monitor_cqe_own_callback;
339 : : }
340 : 0 : pmc->size = sizeof(uint8_t);
341 : 0 : return 0;
342 : : }
343 : :
344 : : /**
345 : : * Translate RX completion flags to packet type.
346 : : *
347 : : * @param[in] rxq
348 : : * Pointer to RX queue structure.
349 : : * @param[in] cqe
350 : : * Pointer to CQE.
351 : : *
352 : : * @note: fix mlx5_dev_supported_ptypes_get() if any change here.
353 : : *
354 : : * @return
355 : : * Packet type for struct rte_mbuf.
356 : : */
357 : : static inline uint32_t
358 : : rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
359 : : volatile struct mlx5_mini_cqe8 *mcqe)
360 : : {
361 : : uint8_t idx;
362 : : uint8_t ptype;
363 : 0 : uint8_t pinfo = (cqe->pkt_info & 0x3) << 6;
364 : :
365 : : /* Get l3/l4 header from mini-CQE in case L3/L4 format*/
366 [ # # # # : 0 : if (mcqe == NULL ||
# # ]
367 [ # # # # : 0 : rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
# # ]
368 : 0 : ptype = (cqe->hdr_type_etc & 0xfc00) >> 10;
369 : : else
370 : 0 : ptype = mcqe->hdr_type >> 2;
371 : : /*
372 : : * The index to the array should have:
373 : : * bit[1:0] = l3_hdr_type
374 : : * bit[4:2] = l4_hdr_type
375 : : * bit[5] = ip_frag
376 : : * bit[6] = tunneled
377 : : * bit[7] = outer_l3_type
378 : : */
379 : 0 : idx = pinfo | ptype;
380 : 0 : return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6));
381 : : }
382 : :
383 : 0 : static inline void mlx5_rq_win_reset(struct mlx5_rxq_data *rxq)
384 : : {
385 : : static_assert(MLX5_WINOOO_BITS == (sizeof(*rxq->rq_win_data) * CHAR_BIT),
386 : : "Invalid out-of-order window bitwidth");
387 : 0 : rxq->rq_win_idx = 0;
388 : 0 : rxq->rq_win_cnt = 0;
389 [ # # # # ]: 0 : if (rxq->rq_win_data != NULL && rxq->rq_win_idx_mask != 0)
390 : 0 : memset(rxq->rq_win_data, 0, (rxq->rq_win_idx_mask + 1) * sizeof(*rxq->rq_win_data));
391 : 0 : }
392 : :
393 : 0 : static inline int mlx5_rq_win_init(struct mlx5_rxq_data *rxq)
394 : : {
395 : : struct mlx5_rxq_ctrl *ctrl = container_of(rxq, struct mlx5_rxq_ctrl, rxq);
396 : : uint32_t win_size, win_mask;
397 : :
398 : : /* Set queue size as window size */
399 : 0 : win_size = 1u << rxq->elts_n;
400 : 0 : win_size = RTE_MAX(win_size, MLX5_WINOOO_BITS);
401 : 0 : win_size = win_size / MLX5_WINOOO_BITS;
402 : 0 : win_mask = win_size - 1;
403 [ # # # # ]: 0 : if (win_mask != rxq->rq_win_idx_mask || rxq->rq_win_data == NULL) {
404 : 0 : mlx5_free(rxq->rq_win_data);
405 : 0 : rxq->rq_win_idx_mask = 0;
406 : 0 : rxq->rq_win_data = mlx5_malloc(MLX5_MEM_RTE,
407 : : win_size * sizeof(*rxq->rq_win_data),
408 : 0 : RTE_CACHE_LINE_SIZE, ctrl->socket);
409 [ # # ]: 0 : if (rxq->rq_win_data == NULL)
410 : : return -ENOMEM;
411 : 0 : rxq->rq_win_idx_mask = (uint16_t)win_mask;
412 : : }
413 : 0 : mlx5_rq_win_reset(rxq);
414 : 0 : return 0;
415 : : }
416 : :
417 : : static inline bool mlx5_rq_win_test(struct mlx5_rxq_data *rxq)
418 : : {
419 : 0 : return !!rxq->rq_win_cnt;
420 : : }
421 : :
422 : : static inline void mlx5_rq_win_update(struct mlx5_rxq_data *rxq, uint32_t delta)
423 : : {
424 : : uint32_t idx;
425 : :
426 : 0 : idx = (delta / MLX5_WINOOO_BITS) + rxq->rq_win_idx;
427 : 0 : idx &= rxq->rq_win_idx_mask;
428 : 0 : rxq->rq_win_cnt = 1;
429 : 0 : rxq->rq_win_data[idx] |= 1u << (delta % MLX5_WINOOO_BITS);
430 : 0 : }
431 : :
432 : 0 : static inline uint32_t mlx5_rq_win_advance(struct mlx5_rxq_data *rxq, uint32_t delta)
433 : : {
434 : : uint32_t idx;
435 : :
436 : 0 : idx = (delta / MLX5_WINOOO_BITS) + rxq->rq_win_idx;
437 : 0 : idx &= rxq->rq_win_idx_mask;
438 : 0 : rxq->rq_win_data[idx] |= 1u << (delta % MLX5_WINOOO_BITS);
439 : 0 : ++rxq->rq_win_cnt;
440 [ # # ]: 0 : if (delta >= MLX5_WINOOO_BITS)
441 : : return 0;
442 : : delta = 0;
443 [ # # ]: 0 : while (~rxq->rq_win_data[idx] == 0) {
444 : 0 : rxq->rq_win_data[idx] = 0;
445 : : MLX5_ASSERT(rxq->rq_win_cnt >= MLX5_WINOOO_BITS);
446 : 0 : rxq->rq_win_cnt -= MLX5_WINOOO_BITS;
447 : 0 : idx = (idx + 1) & rxq->rq_win_idx_mask;
448 : 0 : rxq->rq_win_idx = idx;
449 : 0 : delta += MLX5_WINOOO_BITS;
450 : : }
451 : : return delta;
452 : : }
453 : :
454 : : /**
455 : : * Initialize Rx WQ and indexes.
456 : : *
457 : : * @param[in] rxq
458 : : * Pointer to RX queue structure.
459 : : */
460 : : int
461 : 0 : mlx5_rxq_initialize(struct mlx5_rxq_data *rxq)
462 : : {
463 : 0 : const unsigned int wqe_n = 1 << rxq->elts_n;
464 : : unsigned int i;
465 : :
466 [ # # ]: 0 : for (i = 0; (i != wqe_n); ++i) {
467 : : volatile struct mlx5_wqe_data_seg *scat;
468 : : uintptr_t addr;
469 : : uint32_t byte_count;
470 : : uint32_t lkey;
471 : :
472 [ # # ]: 0 : if (mlx5_rxq_mprq_enabled(rxq)) {
473 : 0 : struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i];
474 : :
475 : 0 : scat = &((volatile struct mlx5_wqe_mprq *)
476 : 0 : rxq->wqes)[i].dseg;
477 : 0 : addr = (uintptr_t)mlx5_mprq_buf_addr
478 : : (buf, (uintptr_t)RTE_BIT32(rxq->log_strd_num));
479 [ # # ]: 0 : byte_count = RTE_BIT32(rxq->log_strd_sz) *
480 : : RTE_BIT32(rxq->log_strd_num);
481 : : lkey = mlx5_rx_addr2mr(rxq, addr);
482 : : } else {
483 : 0 : struct rte_mbuf *buf = (*rxq->elts)[i];
484 : :
485 : 0 : scat = &((volatile struct mlx5_wqe_data_seg *)
486 : 0 : rxq->wqes)[i];
487 : 0 : addr = rte_pktmbuf_mtod(buf, uintptr_t);
488 : 0 : byte_count = DATA_LEN(buf);
489 [ # # ]: 0 : lkey = buf->pool ? mlx5_rx_mb2mr(rxq, buf) : rxq->sh->null_mr->lkey;
490 : : }
491 : : /* scat->addr must be able to store a pointer. */
492 : : MLX5_ASSERT(sizeof(scat->addr) >= sizeof(uintptr_t));
493 : 0 : *scat = (struct mlx5_wqe_data_seg){
494 [ # # ]: 0 : .addr = rte_cpu_to_be_64(addr),
495 [ # # ]: 0 : .byte_count = rte_cpu_to_be_32(byte_count),
496 : : .lkey = lkey,
497 : : };
498 : : }
499 : 0 : rxq->consumed_strd = 0;
500 : : rxq->decompressed = 0;
501 : 0 : rxq->rq_pi = 0;
502 [ # # ]: 0 : rxq->zip = (struct rxq_zip){
503 : : .ai = 0,
504 : : };
505 : 0 : rxq->elts_ci = mlx5_rxq_mprq_enabled(rxq) ?
506 [ # # ]: 0 : (wqe_n >> rxq->sges_n) * RTE_BIT32(rxq->log_strd_num) : 0;
507 : : /* Update doorbell counter. */
508 : 0 : rxq->rq_ci = wqe_n >> rxq->sges_n;
509 : 0 : rxq->rq_ci_ooo = rxq->rq_ci;
510 [ # # ]: 0 : if (mlx5_rq_win_init(rxq))
511 : : return -ENOMEM;
512 : 0 : rte_io_wmb();
513 [ # # ]: 0 : *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
514 : 0 : return 0;
515 : : }
516 : :
517 : : #define MLX5_ERROR_CQE_MASK 0x40000000
518 : : /* Must be negative. */
519 : : #define MLX5_REGULAR_ERROR_CQE_RET (-5)
520 : : #define MLX5_CRITICAL_ERROR_CQE_RET (-4)
521 : : /* Must not be negative. */
522 : : #define MLX5_RECOVERY_ERROR_RET 0
523 : : #define MLX5_RECOVERY_IGNORE_RET 1
524 : : #define MLX5_RECOVERY_COMPLETED_RET 2
525 : :
526 : : /**
527 : : * Handle a Rx error.
528 : : * The function inserts the RQ state to reset when the first error CQE is
529 : : * shown, then drains the CQ by the caller function loop. When the CQ is empty,
530 : : * it moves the RQ state to ready and initializes the RQ.
531 : : * Next CQE identification and error counting are in the caller responsibility.
532 : : *
533 : : * @param[in] rxq
534 : : * Pointer to RX queue structure.
535 : : * @param[in] vec
536 : : * 1 when called from vectorized Rx burst, need to prepare mbufs for the RQ.
537 : : * 0 when called from non-vectorized Rx burst.
538 : : * @param[in] err_n
539 : : * Number of CQEs to check for an error.
540 : : *
541 : : * @return
542 : : * MLX5_RECOVERY_ERROR_RET in case of recovery error,
543 : : * MLX5_RECOVERY_IGNORE_RET in case of non-critical error syndrome,
544 : : * MLX5_RECOVERY_COMPLETED_RET in case of recovery is completed,
545 : : * otherwise the CQE status after ignored error syndrome or queue reset.
546 : : */
547 : : int
548 : 0 : mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec,
549 : : uint16_t err_n, uint16_t *skip_cnt)
550 : : {
551 : 0 : const uint16_t cqe_n = 1 << rxq->cqe_n;
552 : 0 : const uint16_t cqe_mask = cqe_n - 1;
553 : 0 : const uint16_t wqe_n = 1 << rxq->elts_n;
554 : 0 : const uint16_t strd_n = RTE_BIT32(rxq->log_strd_num);
555 : : struct mlx5_rxq_ctrl *rxq_ctrl =
556 : : container_of(rxq, struct mlx5_rxq_ctrl, rxq);
557 : : union {
558 : : volatile struct mlx5_cqe *cqe;
559 : : volatile struct mlx5_error_cqe *err_cqe;
560 : : } u = {
561 : 0 : .cqe = &(*rxq->cqes)[(rxq->cq_ci - vec) & cqe_mask],
562 : : };
563 : : struct mlx5_mp_arg_queue_state_modify sm;
564 : : bool critical_syndrome = false;
565 : : int ret, i;
566 : :
567 [ # # # # : 0 : switch (rxq->err_state) {
# ]
568 : 0 : case MLX5_RXQ_ERR_STATE_IGNORE:
569 [ # # ]: 0 : ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci - vec);
570 : : if (ret != MLX5_CQE_STATUS_ERR) {
571 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
572 : 0 : return ret;
573 : : }
574 : : /* Fall-through */
575 : : case MLX5_RXQ_ERR_STATE_NO_ERROR:
576 [ # # ]: 0 : for (i = 0; i < (int)err_n; i++) {
577 : 0 : u.cqe = &(*rxq->cqes)[(rxq->cq_ci - vec - i) & cqe_mask];
578 [ # # ]: 0 : if (MLX5_CQE_OPCODE(u.cqe->op_own) == MLX5_CQE_RESP_ERR) {
579 [ # # ]: 0 : if (u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
580 [ # # ]: 0 : u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_PROT_ERR ||
581 [ # # ]: 0 : u.err_cqe->syndrome == MLX5_CQE_SYNDROME_WR_FLUSH_ERR)
582 : : critical_syndrome = true;
583 : : break;
584 : : }
585 : : }
586 : : if (!critical_syndrome) {
587 [ # # ]: 0 : if (rxq->err_state == MLX5_RXQ_ERR_STATE_NO_ERROR) {
588 : 0 : *skip_cnt = 0;
589 [ # # ]: 0 : if (i == err_n)
590 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_IGNORE;
591 : : }
592 : 0 : return MLX5_RECOVERY_IGNORE_RET;
593 : : }
594 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET;
595 : : /* Fall-through */
596 : 0 : case MLX5_RXQ_ERR_STATE_NEED_RESET:
597 : 0 : sm.is_wq = 1;
598 : 0 : sm.queue_id = rxq->idx;
599 : 0 : sm.state = IBV_WQS_RESET;
600 [ # # ]: 0 : if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm))
601 : : return MLX5_RECOVERY_ERROR_RET;
602 : 0 : if (rxq_ctrl->dump_file_n <
603 [ # # ]: 0 : RXQ_PORT(rxq_ctrl)->config.max_dump_files_num) {
604 : 0 : MKSTR(err_str, "Unexpected CQE error syndrome "
605 : : "0x%02x CQN = %u RQN = %u wqe_counter = %u"
606 : : " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome,
607 : : rxq->cqn, rxq_ctrl->wqn,
608 : : rte_be_to_cpu_16(u.err_cqe->wqe_counter),
609 : : rxq->rq_ci << rxq->sges_n, rxq->cq_ci);
610 : 0 : MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u",
611 : : rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc());
612 : 0 : mlx5_dump_debug_information(name, NULL, err_str, 0);
613 : 0 : mlx5_dump_debug_information(name, "MLX5 Error CQ:",
614 : : (const void *)((uintptr_t)
615 : 0 : rxq->cqes),
616 : : sizeof(*u.cqe) * cqe_n);
617 : 0 : mlx5_dump_debug_information(name, "MLX5 Error RQ:",
618 : : (const void *)((uintptr_t)
619 : 0 : rxq->wqes),
620 : 0 : 16 * wqe_n);
621 : 0 : rxq_ctrl->dump_file_n++;
622 : : }
623 : : /* Try to find the actual cq_ci in hardware for shared queue. */
624 [ # # ]: 0 : if (rxq->shared)
625 : 0 : mlx5_rxq_sync_cq(rxq);
626 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY;
627 : : /* Fall-through */
628 : 0 : case MLX5_RXQ_ERR_STATE_NEED_READY:
629 [ # # ]: 0 : ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci);
630 : : if (ret == MLX5_CQE_STATUS_HW_OWN) {
631 : 0 : rte_io_wmb();
632 [ # # ]: 0 : *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
633 : 0 : rte_io_wmb();
634 : : /*
635 : : * The RQ consumer index must be zeroed while moving
636 : : * from RESET state to RDY state.
637 : : */
638 : 0 : *rxq->rq_db = rte_cpu_to_be_32(0);
639 : 0 : rte_io_wmb();
640 : 0 : sm.is_wq = 1;
641 : 0 : sm.queue_id = rxq->idx;
642 : 0 : sm.state = IBV_WQS_RDY;
643 [ # # ]: 0 : if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm))
644 : : return MLX5_RECOVERY_ERROR_RET;
645 [ # # ]: 0 : if (vec) {
646 : : const uint32_t elts_n =
647 : : mlx5_rxq_mprq_enabled(rxq) ?
648 [ # # ]: 0 : wqe_n * strd_n : wqe_n;
649 : 0 : const uint32_t e_mask = elts_n - 1;
650 : : uint32_t elts_ci =
651 : : mlx5_rxq_mprq_enabled(rxq) ?
652 [ # # ]: 0 : rxq->elts_ci : rxq->rq_ci;
653 : : uint32_t elt_idx;
654 : : struct rte_mbuf **elt;
655 : 0 : unsigned int n = elts_n - (elts_ci -
656 : 0 : rxq->rq_pi);
657 : :
658 [ # # ]: 0 : for (i = 0; i < (int)n; ++i) {
659 : 0 : elt_idx = (elts_ci + i) & e_mask;
660 : 0 : elt = &(*rxq->elts)[elt_idx];
661 : 0 : *elt = rte_mbuf_raw_alloc(rxq->mp);
662 [ # # ]: 0 : if (!*elt) {
663 [ # # ]: 0 : for (i--; i >= 0; --i) {
664 : 0 : elt_idx = (elts_ci +
665 : : i) & elts_n;
666 : 0 : elt = &(*rxq->elts)
667 : : [elt_idx];
668 [ # # ]: 0 : rte_pktmbuf_free_seg
669 : : (*elt);
670 : : }
671 : : return MLX5_RECOVERY_ERROR_RET;
672 : : }
673 : : }
674 [ # # ]: 0 : for (i = 0; i < (int)elts_n; ++i) {
675 : 0 : elt = &(*rxq->elts)[i];
676 : 0 : DATA_LEN(*elt) =
677 : 0 : (uint16_t)((*elt)->buf_len -
678 : : rte_pktmbuf_headroom(*elt));
679 : : }
680 : : /* Padding with a fake mbuf for vec Rx. */
681 [ # # ]: 0 : for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i)
682 : 0 : (*rxq->elts)[elts_n + i] =
683 : 0 : &rxq->fake_mbuf;
684 : : }
685 [ # # ]: 0 : if (mlx5_rxq_initialize(rxq))
686 : : return MLX5_RECOVERY_ERROR_RET;
687 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
688 : 0 : return MLX5_RECOVERY_COMPLETED_RET;
689 : : }
690 : : return ret;
691 : : default:
692 : : return MLX5_RECOVERY_ERROR_RET;
693 : : }
694 : : }
695 : :
696 : : /**
697 : : * Get size of the next packet for a given CQE. For compressed CQEs, the
698 : : * consumer index is updated only once all packets of the current one have
699 : : * been processed.
700 : : *
701 : : * @param rxq
702 : : * Pointer to RX queue.
703 : : * @param cqe
704 : : * CQE to process.
705 : : * @param cqe_n
706 : : * Completion queue count.
707 : : * @param cqe_mask
708 : : * Completion queue mask.
709 : : * @param[out] mcqe
710 : : * Store pointer to mini-CQE if compressed. Otherwise, the pointer is not
711 : : * written.
712 : : * @param[out] skip_cnt
713 : : * Number of packets skipped due to recoverable errors.
714 : : * @param mprq
715 : : * Indication if it is called from MPRQ.
716 : : * @param[out] widx
717 : : * Store WQE index from CQE to support out of order completions. NULL
718 : : * can be specified if index is not needed
719 : : *
720 : : * @return
721 : : * 0 in case of empty CQE,
722 : : * MLX5_REGULAR_ERROR_CQE_RET in case of error CQE,
723 : : * MLX5_CRITICAL_ERROR_CQE_RET in case of error CQE lead to Rx queue reset,
724 : : * otherwise the packet size in regular RxQ,
725 : : * and striding byte count format in mprq case.
726 : : */
727 : : static inline int
728 : : mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe,
729 : : uint16_t cqe_n, uint16_t cqe_mask,
730 : : volatile struct mlx5_mini_cqe8 **mcqe,
731 : : uint16_t *skip_cnt, bool mprq, uint32_t *widx)
732 : : {
733 : : struct rxq_zip *zip = &rxq->zip;
734 : : int len = 0, ret = 0;
735 : : uint32_t idx, end;
736 : :
737 : : do {
738 : 0 : len = 0;
739 : : /* Process compressed data in the CQE and mini arrays. */
740 [ # # # # : 0 : if (zip->ai) {
# # ]
741 : 0 : volatile struct mlx5_mini_cqe8 (*mc)[8] =
742 : : (volatile struct mlx5_mini_cqe8 (*)[8])
743 : 0 : (uintptr_t)(&(*rxq->cqes)[zip->ca &
744 : : cqe_mask].pkt_info);
745 : 0 : len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt &
746 : : rxq->byte_mask);
747 : : if (widx != NULL)
748 : 0 : *widx = zip->wqe_idx + zip->ai;
749 : 0 : *mcqe = &(*mc)[zip->ai & 7];
750 [ # # # # : 0 : if (rxq->cqe_comp_layout) {
# # ]
751 : 0 : zip->ai++;
752 [ # # # # : 0 : if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
# # ]
753 : 0 : rxq->cq_ci = zip->cq_ci;
754 : 0 : zip->ai = 0;
755 : : }
756 : : } else {
757 [ # # # # : 0 : if ((++zip->ai & 7) == 0) {
# # ]
758 : : /* Invalidate consumed CQEs */
759 : : idx = zip->ca;
760 : 0 : end = zip->na;
761 [ # # # # : 0 : while (idx != end) {
# # ]
762 : 0 : (*rxq->cqes)[idx & cqe_mask].op_own =
763 : : MLX5_CQE_INVALIDATE;
764 : 0 : ++idx;
765 : : }
766 : : /*
767 : : * Increment consumer index to skip the number
768 : : * of CQEs consumed. Hardware leaves holes in
769 : : * the CQ ring for software use.
770 : : */
771 : 0 : zip->ca = zip->na;
772 : 0 : zip->na += 8;
773 : : }
774 [ # # # # : 0 : if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) {
# # ]
775 : : /* Invalidate the rest */
776 : 0 : idx = zip->ca;
777 : 0 : end = zip->cq_ci;
778 : :
779 [ # # # # : 0 : while (idx != end) {
# # ]
780 : 0 : (*rxq->cqes)[idx & cqe_mask].op_own =
781 : : MLX5_CQE_INVALIDATE;
782 : 0 : ++idx;
783 : : }
784 : 0 : rxq->cq_ci = zip->cq_ci;
785 : 0 : zip->ai = 0;
786 : : }
787 : : }
788 : : /*
789 : : * No compressed data, get next CQE and verify if it is
790 : : * compressed.
791 : : */
792 : : } else {
793 : : int8_t op_own;
794 : : uint32_t cq_ci;
795 : :
796 : 0 : ret = (rxq->cqe_comp_layout) ?
797 [ # # # # : 0 : check_cqe_iteration(cqe, rxq->cqe_n, rxq->cq_ci) :
# # # # #
# # # ]
798 [ # # # # : 0 : check_cqe(cqe, cqe_n, rxq->cq_ci);
# # ]
799 [ # # # # : 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
# # ]
800 [ # # # # : 0 : if (unlikely(ret == MLX5_CQE_STATUS_ERR ||
# # # # #
# # # ]
801 : : rxq->err_state)) {
802 : : /* We should try to track out-pf-order WQE */
803 : : if (widx != NULL)
804 : 0 : *widx = rte_be_to_cpu_16(cqe->wqe_counter);
805 : 0 : ret = mlx5_rx_err_handle(rxq, 0, 1, skip_cnt);
806 [ # # # # : 0 : if (ret == MLX5_CQE_STATUS_HW_OWN)
# # ]
807 : : return MLX5_ERROR_CQE_MASK;
808 : 0 : if (ret == MLX5_RECOVERY_ERROR_RET ||
809 [ # # # # : 0 : ret == MLX5_RECOVERY_COMPLETED_RET)
# # ]
810 : : return MLX5_CRITICAL_ERROR_CQE_RET;
811 [ # # # # ]: 0 : if (!mprq && ret == MLX5_RECOVERY_IGNORE_RET) {
812 : 0 : *skip_cnt = 1;
813 : 0 : ++rxq->cq_ci;
814 : 0 : return MLX5_ERROR_CQE_MASK;
815 : : }
816 : : } else {
817 : : return 0;
818 : : }
819 : : }
820 : : /*
821 : : * Introduce the local variable to have queue cq_ci
822 : : * index in queue structure always consistent with
823 : : * actual CQE boundary (not pointing to the middle
824 : : * of compressed CQE session).
825 : : */
826 : 0 : cq_ci = rxq->cq_ci + !rxq->cqe_comp_layout;
827 : 0 : op_own = cqe->op_own;
828 [ # # # # : 0 : if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) {
# # ]
829 : 0 : volatile struct mlx5_mini_cqe8 (*mc)[8] =
830 : : (volatile struct mlx5_mini_cqe8 (*)[8])
831 : 0 : (uintptr_t)(&(*rxq->cqes)
832 : 0 : [cq_ci & cqe_mask].pkt_info);
833 : :
834 : : /* Fix endianness. */
835 [ # # # # : 0 : zip->cqe_cnt = rxq->cqe_comp_layout ?
# # ]
836 : 0 : (MLX5_CQE_NUM_MINIS(op_own) + 1U) :
837 : 0 : rte_be_to_cpu_32(cqe->byte_cnt);
838 : : /*
839 : : * Current mini array position is the one
840 : : * returned by check_cqe64().
841 : : *
842 : : * If completion comprises several mini arrays,
843 : : * as a special case the second one is located
844 : : * 7 CQEs after the initial CQE instead of 8
845 : : * for subsequent ones.
846 : : */
847 : 0 : zip->ca = cq_ci;
848 : 0 : zip->na = zip->ca + 7;
849 : : if (widx != NULL) {
850 : 0 : zip->wqe_idx = rte_be_to_cpu_16(cqe->wqe_counter);
851 : 0 : *widx = zip->wqe_idx;
852 : : }
853 : : /* Compute the next non compressed CQE. */
854 : 0 : zip->cq_ci = rxq->cq_ci + zip->cqe_cnt;
855 : : /* Get packet size to return. */
856 : 0 : len = rte_be_to_cpu_32((*mc)[0].byte_cnt &
857 : : rxq->byte_mask);
858 : 0 : *mcqe = &(*mc)[0];
859 [ # # # # : 0 : if (rxq->cqe_comp_layout) {
# # ]
860 [ # # # # : 0 : if (MLX5_CQE_NUM_MINIS(op_own))
# # ]
861 : 0 : zip->ai = 1;
862 : : else
863 : 0 : rxq->cq_ci = zip->cq_ci;
864 : : } else {
865 : 0 : zip->ai = 1;
866 : : /* Prefetch all to be invalidated */
867 : : idx = zip->ca;
868 : : end = zip->cq_ci;
869 [ # # # # : 0 : while (idx != end) {
# # ]
870 : 0 : rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_mask]);
871 : 0 : ++idx;
872 : : }
873 : : }
874 : : } else {
875 : 0 : ++rxq->cq_ci;
876 : 0 : len = rte_be_to_cpu_32(cqe->byte_cnt);
877 : : if (widx != NULL)
878 : 0 : *widx = rte_be_to_cpu_16(cqe->wqe_counter);
879 [ # # # # : 0 : if (rxq->cqe_comp_layout) {
# # ]
880 : : volatile struct mlx5_cqe *next;
881 : :
882 : 0 : next = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
883 [ # # # # : 0 : ret = check_cqe_iteration(next, rxq->cqe_n, rxq->cq_ci);
# # ]
884 : 0 : if (ret != MLX5_CQE_STATUS_SW_OWN ||
885 [ # # # # : 0 : MLX5_CQE_FORMAT(next->op_own) == MLX5_COMPRESSED)
# # ]
886 : : rte_memcpy(&rxq->title_cqe,
887 : : (const void *)(uintptr_t)cqe,
888 : : sizeof(struct mlx5_cqe));
889 : : }
890 : : }
891 : : }
892 [ # # # # : 0 : if (unlikely(rxq->err_state)) {
# # ]
893 [ # # # # : 0 : if (rxq->err_state == MLX5_RXQ_ERR_STATE_IGNORE &&
# # # # #
# # # ]
894 : : ret == MLX5_CQE_STATUS_SW_OWN) {
895 : 0 : rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR;
896 : 0 : return len & MLX5_ERROR_CQE_MASK;
897 : : }
898 : 0 : cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
899 : 0 : ++rxq->stats.idropped;
900 : 0 : (*skip_cnt) += mprq ? (len & MLX5_MPRQ_STRIDE_NUM_MASK) >>
901 : : MLX5_MPRQ_STRIDE_NUM_SHIFT : 1;
902 : : } else {
903 : : return len;
904 : : }
905 : : } while (1);
906 : : }
907 : :
908 : : /**
909 : : * Translate RX completion flags to offload flags.
910 : : *
911 : : * @param[in] cqe
912 : : * Pointer to CQE.
913 : : *
914 : : * @return
915 : : * Offload flags (ol_flags) for struct rte_mbuf.
916 : : */
917 : : static inline uint32_t
918 : : rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe)
919 : : {
920 : : uint32_t ol_flags = 0;
921 : 0 : uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc);
922 : :
923 : 0 : ol_flags =
924 : 0 : TRANSPOSE(flags,
925 : : MLX5_CQE_RX_L3_HDR_VALID,
926 : 0 : RTE_MBUF_F_RX_IP_CKSUM_GOOD) |
927 : 0 : TRANSPOSE(flags,
928 : : MLX5_CQE_RX_L4_HDR_VALID,
929 : : RTE_MBUF_F_RX_L4_CKSUM_GOOD);
930 : : return ol_flags;
931 : : }
932 : :
933 : : /**
934 : : * Fill in mbuf fields from RX completion flags.
935 : : * Note that pkt->ol_flags should be initialized outside of this function.
936 : : *
937 : : * @param rxq
938 : : * Pointer to RX queue.
939 : : * @param pkt
940 : : * mbuf to fill.
941 : : * @param cqe
942 : : * CQE to process.
943 : : * @param rss_hash_res
944 : : * Packet RSS Hash result.
945 : : */
946 : : static inline void
947 : : rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt,
948 : : volatile struct mlx5_cqe *cqe,
949 : : volatile struct mlx5_mini_cqe8 *mcqe)
950 : : {
951 : : /* Update packet information. */
952 : 0 : pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe, mcqe);
953 [ # # # # : 0 : pkt->port = unlikely(rxq->shared) ? cqe->user_index_low : rxq->port_id;
# # ]
954 : :
955 [ # # # # : 0 : if (rxq->rss_hash) {
# # ]
956 : : uint32_t rss_hash_res = 0;
957 : :
958 : : /* If compressed, take hash result from mini-CQE. */
959 [ # # # # : 0 : if (mcqe == NULL ||
# # ]
960 [ # # # # : 0 : rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_HASH)
# # ]
961 : 0 : rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res);
962 : : else
963 : 0 : rss_hash_res = rte_be_to_cpu_32(mcqe->rx_hash_result);
964 [ # # # # : 0 : if (rss_hash_res) {
# # ]
965 : 0 : pkt->hash.rss = rss_hash_res;
966 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
967 : : }
968 : : }
969 [ # # # # : 0 : if (rxq->mark) {
# # ]
970 : : uint32_t mark = 0;
971 : :
972 : : /* If compressed, take flow tag from mini-CQE. */
973 [ # # # # : 0 : if (mcqe == NULL ||
# # ]
974 [ # # # # : 0 : rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
# # ]
975 : 0 : mark = cqe->sop_drop_qpn;
976 : : else
977 : 0 : mark = ((mcqe->byte_cnt_flow & 0xff) << 8) |
978 : 0 : (mcqe->flow_tag_high << 16);
979 [ # # # # : 0 : if (MLX5_FLOW_MARK_IS_VALID(mark)) {
# # ]
980 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_FDIR;
981 [ # # # # : 0 : if (mark != RTE_BE32(MLX5_FLOW_MARK_DEFAULT)) {
# # ]
982 : 0 : pkt->ol_flags |= rxq->mark_flag;
983 : 0 : pkt->hash.fdir.hi = mlx5_flow_mark_get(mark);
984 : : }
985 : : }
986 : : }
987 [ # # # # : 0 : if (rxq->dynf_meta) {
# # ]
988 : 0 : uint32_t meta = rte_be_to_cpu_32(cqe->flow_table_metadata) &
989 : 0 : rxq->flow_meta_port_mask;
990 : :
991 [ # # # # : 0 : if (meta) {
# # ]
992 : 0 : pkt->ol_flags |= rxq->flow_meta_mask;
993 : 0 : *RTE_MBUF_DYNFIELD(pkt, rxq->flow_meta_offset,
994 : 0 : uint32_t *) = meta;
995 : : }
996 : : }
997 [ # # # # : 0 : if (rxq->csum)
# # ]
998 : 0 : pkt->ol_flags |= rxq_cq_to_ol_flags(cqe);
999 [ # # # # : 0 : if (rxq->vlan_strip) {
# # ]
1000 : : bool vlan_strip;
1001 : :
1002 [ # # # # : 0 : if (mcqe == NULL ||
# # ]
1003 [ # # # # : 0 : rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
# # ]
1004 : 0 : vlan_strip = cqe->hdr_type_etc &
1005 : : RTE_BE16(MLX5_CQE_VLAN_STRIPPED);
1006 : : else
1007 : 0 : vlan_strip = mcqe->hdr_type & MLX5_CQE_VLAN_STRIPPED;
1008 [ # # # # : 0 : if (vlan_strip) {
# # ]
1009 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
1010 : 0 : pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info);
1011 : : }
1012 : : }
1013 [ # # # # : 0 : if (rxq->hw_timestamp) {
# # ]
1014 : 0 : uint64_t ts = rte_be_to_cpu_64(cqe->timestamp);
1015 : :
1016 [ # # # # : 0 : if (rxq->rt_timestamp)
# # ]
1017 : : ts = mlx5_txpp_convert_rx_ts(rxq->sh, ts);
1018 : 0 : mlx5_timestamp_set(pkt, rxq->timestamp_offset, ts);
1019 : 0 : pkt->ol_flags |= rxq->timestamp_rx_flag;
1020 : : }
1021 : : }
1022 : :
1023 : : /**
1024 : : * DPDK callback for RX.
1025 : : *
1026 : : * @param dpdk_rxq
1027 : : * Generic pointer to RX queue structure.
1028 : : * @param[out] pkts
1029 : : * Array to store received packets.
1030 : : * @param pkts_n
1031 : : * Maximum number of packets in array.
1032 : : *
1033 : : * @return
1034 : : * Number of packets successfully received (<= pkts_n).
1035 : : */
1036 : : uint16_t
1037 : 0 : mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1038 : : {
1039 : : struct mlx5_rxq_data *rxq = dpdk_rxq;
1040 : 0 : const uint32_t wqe_n = 1 << rxq->elts_n;
1041 : 0 : const uint32_t wqe_mask = wqe_n - 1;
1042 : 0 : const uint32_t cqe_n = 1 << rxq->cqe_n;
1043 : 0 : const uint32_t cqe_mask = cqe_n - 1;
1044 : 0 : const unsigned int sges_n = rxq->sges_n;
1045 : : struct rte_mbuf *pkt = NULL;
1046 : : struct rte_mbuf *seg = NULL;
1047 : : struct rte_mbuf *tail = NULL;
1048 : 0 : volatile struct mlx5_cqe *cqe =
1049 : 0 : &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
1050 : : volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1051 : : unsigned int i = 0;
1052 : 0 : unsigned int rq_ci = rxq->rq_ci << sges_n;
1053 : : int len = 0; /* keep its value across iterations. */
1054 : : uint32_t data_seg_len = 0;
1055 : :
1056 [ # # ]: 0 : while (pkts_n) {
1057 : 0 : uint16_t skip_cnt = 0;
1058 : 0 : unsigned int idx = rq_ci & wqe_mask;
1059 : 0 : volatile struct mlx5_wqe_data_seg *wqe =
1060 : 0 : &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
1061 : 0 : struct rte_mbuf *rep = (*rxq->elts)[idx];
1062 : :
1063 [ # # ]: 0 : if (pkt) {
1064 [ # # ]: 0 : if (rep->pool)
1065 : 0 : NEXT(tail) = rep;
1066 : : else
1067 : 0 : --NB_SEGS(pkt);
1068 : : }
1069 : : seg = rep;
1070 : : rte_prefetch0(seg);
1071 : : rte_prefetch0(cqe);
1072 : : rte_prefetch0(wqe);
1073 [ # # ]: 0 : if (seg->pool) {
1074 : : /* Allocate the buf from the same pool. */
1075 : 0 : rep = rte_mbuf_raw_alloc(seg->pool);
1076 [ # # ]: 0 : if (unlikely(rep == NULL)) {
1077 : 0 : ++rxq->stats.rx_nombuf;
1078 [ # # ]: 0 : if (!pkt) {
1079 : : /*
1080 : : * no buffers before we even started,
1081 : : * bail out silently.
1082 : : */
1083 : : break;
1084 : : }
1085 [ # # ]: 0 : while (pkt != seg) {
1086 : : MLX5_ASSERT(pkt != (*rxq->elts)[idx]);
1087 : 0 : rep = NEXT(pkt);
1088 : 0 : NEXT(pkt) = NULL;
1089 [ # # ]: 0 : NB_SEGS(pkt) = 1;
1090 : : rte_mbuf_raw_free(pkt);
1091 : : pkt = rep;
1092 : : }
1093 : 0 : rq_ci >>= sges_n;
1094 : 0 : ++rq_ci;
1095 : 0 : rq_ci <<= sges_n;
1096 : 0 : break;
1097 : : }
1098 : : }
1099 [ # # ]: 0 : if (!pkt) { /* new packet */
1100 [ # # ]: 0 : if (len == 0) { /* no CQE polled yet */
1101 : : mcqe = NULL;
1102 : 0 : cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
1103 : 0 : len = mlx5_rx_poll_len(rxq, cqe, cqe_n, cqe_mask,
1104 : : &mcqe, &skip_cnt, false, NULL);
1105 [ # # ]: 0 : if (unlikely(len & MLX5_ERROR_CQE_MASK)) {
1106 : : /* We drop packets with non-critical errors */
1107 [ # # ]: 0 : if (seg->pool)
1108 : : rte_mbuf_raw_free(rep);
1109 [ # # ]: 0 : if (len == MLX5_CRITICAL_ERROR_CQE_RET) {
1110 : 0 : rq_ci = rxq->rq_ci << sges_n;
1111 : 0 : break;
1112 : : }
1113 : : /* Skip specified amount of error CQEs packets */
1114 : 0 : rq_ci >>= sges_n;
1115 : 0 : rq_ci += skip_cnt;
1116 : 0 : rq_ci <<= sges_n;
1117 : : MLX5_ASSERT(!pkt);
1118 : : len = 0;
1119 : 0 : continue;
1120 : : }
1121 [ # # ]: 0 : if (len == 0) {
1122 [ # # ]: 0 : if (seg->pool)
1123 : : rte_mbuf_raw_free(rep);
1124 : : break;
1125 : : }
1126 : : MLX5_ASSERT(len >= (int)(rxq->crc_present << 2));
1127 [ # # ]: 0 : if (rxq->crc_present)
1128 : 0 : len -= RTE_ETHER_CRC_LEN;
1129 : : }
1130 [ # # ]: 0 : if (seg->pool) { /* first real segment */
1131 : : pkt = seg;
1132 : 0 : pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
1133 [ # # # # ]: 0 : if (rxq->cqe_comp_layout && mcqe)
1134 : 0 : cqe = &rxq->title_cqe;
1135 : : rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1136 : 0 : PKT_LEN(pkt) = len;
1137 [ # # ]: 0 : if (cqe->lro_num_seg > 1) {
1138 : 0 : mlx5_lro_update_hdr
1139 : 0 : (rte_pktmbuf_mtod(pkt, uint8_t *), cqe,
1140 : : mcqe, rxq, len);
1141 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1142 : 0 : pkt->tso_segsz = len / cqe->lro_num_seg;
1143 : : }
1144 : : }
1145 : : }
1146 [ # # ]: 0 : if (seg->pool) { /* real segment: replenish WQE */
1147 : : tail = seg;
1148 : 0 : DATA_LEN(rep) = DATA_LEN(seg);
1149 : 0 : PKT_LEN(rep) = PKT_LEN(seg);
1150 : 0 : SET_DATA_OFF(rep, DATA_OFF(seg));
1151 : 0 : PORT(rep) = PORT(seg);
1152 : 0 : (*rxq->elts)[idx] = rep;
1153 : : /*
1154 : : * Fill NIC descriptor with the new buffer. The lkey and size
1155 : : * of the buffers are already known, only the buffer address
1156 : : * changes.
1157 : : */
1158 : 0 : wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
1159 : : /* If there's only one MR, no need to replace LKey in WQE. */
1160 [ # # ]: 0 : if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1161 : 0 : wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
1162 : : }
1163 [ # # ]: 0 : if (len > DATA_LEN(seg)) { /* more data: move to next segment */
1164 [ # # ]: 0 : if (seg->pool)
1165 : 0 : data_seg_len += DATA_LEN(seg);
1166 : 0 : len -= DATA_LEN(seg);
1167 [ # # ]: 0 : if (pkt)
1168 : 0 : ++NB_SEGS(pkt);
1169 : 0 : ++rq_ci;
1170 : 0 : continue;
1171 : : }
1172 [ # # ]: 0 : if (seg->pool) { /* last segment */
1173 : 0 : DATA_LEN(seg) = len;
1174 : 0 : data_seg_len += len;
1175 : : }
1176 [ # # ]: 0 : if (unlikely(!pkt)) { /* no real segment found, skip packet */
1177 : : len = 0;
1178 : 0 : rq_ci >>= sges_n;
1179 : 0 : ++rq_ci;
1180 : 0 : rq_ci <<= sges_n;
1181 : 0 : continue;
1182 : : }
1183 : 0 : PKT_LEN(pkt) = RTE_MIN(PKT_LEN(pkt), data_seg_len);
1184 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1185 : : /* Increment bytes counter. */
1186 : 0 : rxq->stats.ibytes += PKT_LEN(pkt);
1187 : : #endif
1188 : : data_seg_len = 0;
1189 : : /* Return packet. */
1190 : 0 : *(pkts++) = pkt;
1191 : : pkt = NULL;
1192 : : len = 0;
1193 : 0 : --pkts_n;
1194 : 0 : ++i;
1195 : : /* Align consumer index to the next stride. */
1196 : 0 : rq_ci >>= sges_n;
1197 : 0 : ++rq_ci;
1198 : 0 : rq_ci <<= sges_n;
1199 : : }
1200 [ # # # # ]: 0 : if (unlikely(i == 0 && ((rq_ci >> sges_n) == rxq->rq_ci)))
1201 : : return 0;
1202 : : /* Update the consumer index. */
1203 : 0 : rxq->rq_ci = rq_ci >> sges_n;
1204 : 0 : rte_io_wmb();
1205 [ # # ]: 0 : *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1206 : 0 : rte_io_wmb();
1207 [ # # ]: 0 : *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1208 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1209 : : /* Increment packets counter. */
1210 : 0 : rxq->stats.ipackets += i;
1211 : : #endif
1212 : 0 : return i;
1213 : : }
1214 : :
1215 : : /**
1216 : : * DPDK callback for RX with Out-of-Order completions support.
1217 : : *
1218 : : * @param dpdk_rxq
1219 : : * Generic pointer to RX queue structure.
1220 : : * @param[out] pkts
1221 : : * Array to store received packets.
1222 : : * @param pkts_n
1223 : : * Maximum number of packets in array.
1224 : : *
1225 : : * @return
1226 : : * Number of packets successfully received (<= pkts_n).
1227 : : */
1228 : : uint16_t
1229 : 0 : mlx5_rx_burst_out_of_order(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1230 : : {
1231 : : struct mlx5_rxq_data *rxq = dpdk_rxq;
1232 : 0 : const uint32_t wqe_n = 1 << rxq->elts_n;
1233 : 0 : const uint32_t wqe_mask = wqe_n - 1;
1234 : 0 : const uint32_t cqe_n = 1 << rxq->cqe_n;
1235 : 0 : const uint32_t cqe_mask = cqe_n - 1;
1236 : 0 : const unsigned int sges_n = rxq->sges_n;
1237 : 0 : const uint32_t pkt_mask = wqe_mask >> sges_n;
1238 : : struct rte_mbuf *pkt = NULL;
1239 : : struct rte_mbuf *seg = NULL;
1240 : 0 : volatile struct mlx5_cqe *cqe =
1241 : 0 : &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
1242 : : unsigned int i = 0;
1243 : : int len = 0; /* keep its value across iterations. */
1244 : 0 : const uint32_t rq_ci = rxq->rq_ci;
1245 : : uint32_t idx = 0;
1246 : :
1247 : : do {
1248 : : volatile struct mlx5_wqe_data_seg *wqe;
1249 : : struct rte_mbuf *rep = NULL;
1250 : : volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1251 : : uint32_t delta;
1252 : : uint16_t skip_cnt;
1253 : :
1254 [ # # ]: 0 : if (!pkt) {
1255 : 0 : cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask];
1256 : : rte_prefetch0(cqe);
1257 : : /* Allocate from the first packet mbuf pool */
1258 : 0 : rep = (*rxq->elts)[0];
1259 : : /* We must allocate before CQE consuming to allow retry */
1260 : 0 : rep = rte_mbuf_raw_alloc(rep->pool);
1261 [ # # ]: 0 : if (unlikely(rep == NULL)) {
1262 : 0 : ++rxq->stats.rx_nombuf;
1263 : 0 : break;
1264 : : }
1265 : 0 : len = mlx5_rx_poll_len(rxq, cqe, cqe_n, cqe_mask,
1266 : : &mcqe, &skip_cnt, false, &idx);
1267 [ # # ]: 0 : if (unlikely(len == MLX5_CRITICAL_ERROR_CQE_RET)) {
1268 : : rte_mbuf_raw_free(rep);
1269 : 0 : mlx5_rq_win_reset(rxq);
1270 : 0 : break;
1271 : : }
1272 [ # # ]: 0 : if (len == 0) {
1273 : : rte_mbuf_raw_free(rep);
1274 : : break;
1275 : : }
1276 : 0 : idx &= pkt_mask;
1277 : 0 : delta = (idx - rxq->rq_ci) & pkt_mask;
1278 : : MLX5_ASSERT(delta < ((rxq->rq_win_idx_mask + 1) * MLX5_WINOOO_BITS));
1279 [ # # ]: 0 : if (likely(!mlx5_rq_win_test(rxq))) {
1280 : : /* No out of order completions in sliding window */
1281 [ # # ]: 0 : if (likely(delta == 0))
1282 : 0 : rxq->rq_ci++;
1283 : : else
1284 : : mlx5_rq_win_update(rxq, delta);
1285 : : } else {
1286 : : /* We have out of order completions */
1287 : 0 : rxq->rq_ci += mlx5_rq_win_advance(rxq, delta);
1288 : : }
1289 [ # # ]: 0 : if (rxq->zip.ai == 0)
1290 : 0 : rxq->rq_ci_ooo = rxq->rq_ci;
1291 : 0 : idx <<= sges_n;
1292 : : /* We drop packets with non-critical errors */
1293 [ # # ]: 0 : if (unlikely(len & MLX5_ERROR_CQE_MASK)) {
1294 : : rte_mbuf_raw_free(rep);
1295 : 0 : continue;
1296 : : }
1297 : : }
1298 : 0 : wqe = &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx];
1299 [ # # ]: 0 : if (unlikely(pkt))
1300 : 0 : NEXT(seg) = (*rxq->elts)[idx];
1301 : 0 : seg = (*rxq->elts)[idx];
1302 : : rte_prefetch0(seg);
1303 : : rte_prefetch0(wqe);
1304 : : /* Allocate the buf from the same pool. */
1305 [ # # ]: 0 : if (unlikely(rep == NULL)) {
1306 : 0 : rep = rte_mbuf_raw_alloc(seg->pool);
1307 [ # # ]: 0 : if (unlikely(rep == NULL)) {
1308 : 0 : ++rxq->stats.rx_nombuf;
1309 [ # # ]: 0 : if (!pkt) {
1310 : : /*
1311 : : * no buffers before we even started,
1312 : : * bail out silently.
1313 : : */
1314 : : break;
1315 : : }
1316 [ # # ]: 0 : while (pkt != seg) {
1317 : : MLX5_ASSERT(pkt != (*rxq->elts)[idx]);
1318 : 0 : rep = NEXT(pkt);
1319 : 0 : NEXT(pkt) = NULL;
1320 [ # # ]: 0 : NB_SEGS(pkt) = 1;
1321 : : rte_mbuf_raw_free(pkt);
1322 : : pkt = rep;
1323 : : }
1324 : : break;
1325 : : }
1326 : : }
1327 [ # # ]: 0 : if (!pkt) {
1328 : : pkt = seg;
1329 : : MLX5_ASSERT(len >= (int)(rxq->crc_present << 2));
1330 : 0 : pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
1331 [ # # # # ]: 0 : if (rxq->cqe_comp_layout && mcqe)
1332 : 0 : cqe = &rxq->title_cqe;
1333 : : rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1334 [ # # ]: 0 : if (rxq->crc_present)
1335 : 0 : len -= RTE_ETHER_CRC_LEN;
1336 : 0 : PKT_LEN(pkt) = len;
1337 [ # # ]: 0 : if (cqe->lro_num_seg > 1) {
1338 : 0 : mlx5_lro_update_hdr
1339 : 0 : (rte_pktmbuf_mtod(pkt, uint8_t *), cqe,
1340 : : mcqe, rxq, len);
1341 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1342 : 0 : pkt->tso_segsz = len / cqe->lro_num_seg;
1343 : : }
1344 : : }
1345 : 0 : DATA_LEN(rep) = DATA_LEN(seg);
1346 : 0 : PKT_LEN(rep) = PKT_LEN(seg);
1347 : 0 : SET_DATA_OFF(rep, DATA_OFF(seg));
1348 : 0 : PORT(rep) = PORT(seg);
1349 : 0 : (*rxq->elts)[idx] = rep;
1350 : : /*
1351 : : * Fill NIC descriptor with the new buffer. The lkey and size
1352 : : * of the buffers are already known, only the buffer address
1353 : : * changes.
1354 : : */
1355 : 0 : wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
1356 : : /* If there's only one MR, no need to replace LKey in WQE. */
1357 [ # # ]: 0 : if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
1358 : 0 : wqe->lkey = mlx5_rx_mb2mr(rxq, rep);
1359 [ # # ]: 0 : if (len > DATA_LEN(seg)) {
1360 : 0 : len -= DATA_LEN(seg);
1361 : 0 : ++NB_SEGS(pkt);
1362 : 0 : ++idx;
1363 : 0 : idx &= wqe_mask;
1364 : 0 : continue;
1365 : : }
1366 : 0 : DATA_LEN(seg) = len;
1367 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1368 : : /* Increment bytes counter. */
1369 : 0 : rxq->stats.ibytes += PKT_LEN(pkt);
1370 : : #endif
1371 : : /* Return packet. */
1372 : 0 : *(pkts++) = pkt;
1373 : : pkt = NULL;
1374 : 0 : ++i;
1375 [ # # ]: 0 : } while (i < pkts_n);
1376 [ # # # # ]: 0 : if (unlikely(i == 0 && rq_ci == rxq->rq_ci_ooo))
1377 : : return 0;
1378 : : /* Update the consumer index. */
1379 : 0 : rte_io_wmb();
1380 [ # # ]: 0 : *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1381 : 0 : rte_io_wmb();
1382 [ # # ]: 0 : *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci_ooo);
1383 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1384 : : /* Increment packets counter. */
1385 : 0 : rxq->stats.ipackets += i;
1386 : : #endif
1387 : 0 : return i;
1388 : : }
1389 : :
1390 : : /**
1391 : : * Update LRO packet TCP header.
1392 : : * The HW LRO feature doesn't update the TCP header after coalescing the
1393 : : * TCP segments but supplies information in CQE to fill it by SW.
1394 : : *
1395 : : * @param tcp
1396 : : * Pointer to the TCP header.
1397 : : * @param cqe
1398 : : * Pointer to the completion entry.
1399 : : * @param phcsum
1400 : : * The L3 pseudo-header checksum.
1401 : : */
1402 : : static inline void
1403 : 0 : mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp,
1404 : : volatile struct mlx5_cqe *__rte_restrict cqe,
1405 : : uint32_t phcsum, uint8_t l4_type)
1406 : : {
1407 : : /*
1408 : : * The HW calculates only the TCP payload checksum, need to complete
1409 : : * the TCP header checksum and the L3 pseudo-header checksum.
1410 : : */
1411 : 0 : uint32_t csum = phcsum + cqe->csum;
1412 : :
1413 [ # # ]: 0 : if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK ||
1414 : : l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) {
1415 : 0 : tcp->tcp_flags |= RTE_TCP_ACK_FLAG;
1416 : 0 : tcp->recv_ack = cqe->lro_ack_seq_num;
1417 : 0 : tcp->rx_win = cqe->lro_tcp_win;
1418 : : }
1419 [ # # ]: 0 : if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK)
1420 : 0 : tcp->tcp_flags |= RTE_TCP_PSH_FLAG;
1421 : 0 : tcp->cksum = 0;
1422 : 0 : csum += rte_raw_cksum(tcp, (tcp->data_off >> 4) * 4);
1423 : 0 : csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
1424 : 0 : csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff);
1425 : 0 : csum = (~csum) & 0xffff;
1426 [ # # ]: 0 : if (csum == 0)
1427 : : csum = 0xffff;
1428 : 0 : tcp->cksum = csum;
1429 : 0 : }
1430 : :
1431 : : /**
1432 : : * Update LRO packet headers.
1433 : : * The HW LRO feature doesn't update the L3/TCP headers after coalescing the
1434 : : * TCP segments but supply information in CQE to fill it by SW.
1435 : : *
1436 : : * @param padd
1437 : : * The packet address.
1438 : : * @param cqe
1439 : : * Pointer to the completion entry.
1440 : : * @param len
1441 : : * The packet length.
1442 : : */
1443 : : static inline void
1444 : 0 : mlx5_lro_update_hdr(uint8_t *__rte_restrict padd,
1445 : : volatile struct mlx5_cqe *__rte_restrict cqe,
1446 : : volatile struct mlx5_mini_cqe8 *mcqe,
1447 : : struct mlx5_rxq_data *rxq, uint32_t len)
1448 : : {
1449 : : union {
1450 : : struct rte_ether_hdr *eth;
1451 : : struct rte_vlan_hdr *vlan;
1452 : : struct rte_ipv4_hdr *ipv4;
1453 : : struct rte_ipv6_hdr *ipv6;
1454 : : struct rte_tcp_hdr *tcp;
1455 : : uint8_t *hdr;
1456 : : } h = {
1457 : : .hdr = padd,
1458 : : };
1459 : 0 : uint16_t proto = h.eth->ether_type;
1460 : : uint32_t phcsum;
1461 : : uint8_t l4_type;
1462 : :
1463 : 0 : h.eth++;
1464 : 0 : while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) ||
1465 [ # # ]: 0 : proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) {
1466 : 0 : proto = h.vlan->eth_proto;
1467 : 0 : h.vlan++;
1468 : : }
1469 [ # # ]: 0 : if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) {
1470 : 0 : h.ipv4->time_to_live = cqe->lro_min_ttl;
1471 [ # # ]: 0 : h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd));
1472 : 0 : h.ipv4->hdr_checksum = 0;
1473 : 0 : h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4);
1474 : 0 : phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0);
1475 : 0 : h.ipv4++;
1476 : : } else {
1477 : 0 : h.ipv6->hop_limits = cqe->lro_min_ttl;
1478 [ # # ]: 0 : h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) -
1479 : : sizeof(*h.ipv6));
1480 : 0 : phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0);
1481 : 0 : h.ipv6++;
1482 : : }
1483 [ # # ]: 0 : if (mcqe == NULL ||
1484 [ # # ]: 0 : rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX)
1485 : 0 : l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) &
1486 : 0 : MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1487 : : else
1488 : 0 : l4_type = (rte_be_to_cpu_16(mcqe->hdr_type) &
1489 : 0 : MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT;
1490 : 0 : mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum, l4_type);
1491 : 0 : }
1492 : :
1493 : : void
1494 : 0 : mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf)
1495 : : {
1496 : 0 : mlx5_mprq_buf_free_cb(NULL, buf);
1497 : 0 : }
1498 : :
1499 : : /**
1500 : : * DPDK callback for RX with Multi-Packet RQ support.
1501 : : *
1502 : : * @param dpdk_rxq
1503 : : * Generic pointer to RX queue structure.
1504 : : * @param[out] pkts
1505 : : * Array to store received packets.
1506 : : * @param pkts_n
1507 : : * Maximum number of packets in array.
1508 : : *
1509 : : * @return
1510 : : * Number of packets successfully received (<= pkts_n).
1511 : : */
1512 : : uint16_t
1513 : 0 : mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1514 : : {
1515 : : struct mlx5_rxq_data *rxq = dpdk_rxq;
1516 : 0 : const uint32_t strd_n = RTE_BIT32(rxq->log_strd_num);
1517 : 0 : const uint32_t strd_sz = RTE_BIT32(rxq->log_strd_sz);
1518 : 0 : const uint32_t cqe_n = 1 << rxq->cqe_n;
1519 : 0 : const uint32_t cq_mask = cqe_n - 1;
1520 : 0 : const uint32_t wqe_n = 1 << rxq->elts_n;
1521 : 0 : const uint32_t wq_mask = wqe_n - 1;
1522 : : volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1523 : : unsigned int i = 0;
1524 : 0 : uint32_t rq_ci = rxq->rq_ci;
1525 : 0 : uint16_t consumed_strd = rxq->consumed_strd;
1526 : 0 : struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1527 : :
1528 [ # # ]: 0 : while (i < pkts_n) {
1529 : : struct rte_mbuf *pkt;
1530 : : int ret;
1531 : : uint32_t len;
1532 : : uint16_t strd_cnt;
1533 : : uint16_t strd_idx;
1534 : : uint32_t byte_cnt;
1535 : 0 : uint16_t skip_cnt = 0;
1536 : : volatile struct mlx5_mini_cqe8 *mcqe = NULL;
1537 : : enum mlx5_rqx_code rxq_code;
1538 : :
1539 [ # # ]: 0 : if (consumed_strd == strd_n) {
1540 : : /* Replace WQE if the buffer is still in use. */
1541 [ # # ]: 0 : mprq_buf_replace(rxq, rq_ci & wq_mask);
1542 : : /* Advance to the next WQE. */
1543 : : consumed_strd = 0;
1544 : 0 : ++rq_ci;
1545 : 0 : buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1546 : : }
1547 : 0 : cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1548 : 0 : ret = mlx5_rx_poll_len(rxq, cqe, cqe_n, cq_mask, &mcqe, &skip_cnt, true, NULL);
1549 [ # # ]: 0 : if (unlikely(ret & MLX5_ERROR_CQE_MASK)) {
1550 [ # # ]: 0 : if (ret == MLX5_CRITICAL_ERROR_CQE_RET) {
1551 : 0 : rq_ci = rxq->rq_ci;
1552 : 0 : consumed_strd = rxq->consumed_strd;
1553 : 0 : break;
1554 : : }
1555 : 0 : consumed_strd += skip_cnt;
1556 [ # # ]: 0 : while (consumed_strd >= strd_n) {
1557 : : /* Replace WQE if the buffer is still in use. */
1558 [ # # ]: 0 : mprq_buf_replace(rxq, rq_ci & wq_mask);
1559 : : /* Advance to the next WQE. */
1560 : 0 : consumed_strd -= strd_n;
1561 : 0 : ++rq_ci;
1562 : 0 : buf = (*rxq->mprq_bufs)[rq_ci & wq_mask];
1563 : : }
1564 : 0 : cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask];
1565 : : }
1566 [ # # ]: 0 : if (ret == 0)
1567 : : break;
1568 : 0 : byte_cnt = ret;
1569 : 0 : len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1570 : : MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1571 [ # # ]: 0 : if (rxq->crc_present)
1572 : 0 : len -= RTE_ETHER_CRC_LEN;
1573 [ # # ]: 0 : if (mcqe &&
1574 [ # # ]: 0 : rxq->mcqe_format == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX)
1575 : 0 : strd_cnt = (len / strd_sz) + !!(len % strd_sz);
1576 : : else
1577 : 0 : strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >>
1578 : : MLX5_MPRQ_STRIDE_NUM_SHIFT;
1579 : : MLX5_ASSERT(strd_cnt);
1580 : 0 : consumed_strd += strd_cnt;
1581 [ # # ]: 0 : if (byte_cnt & MLX5_MPRQ_FILLER_MASK)
1582 : 0 : continue;
1583 [ # # # # ]: 0 : if (rxq->cqe_comp_layout && mcqe)
1584 : 0 : cqe = &rxq->title_cqe;
1585 [ # # ]: 0 : strd_idx = rte_be_to_cpu_16(mcqe == NULL ?
1586 : : cqe->wqe_counter :
1587 : : mcqe->stride_idx);
1588 : : MLX5_ASSERT(strd_idx < strd_n);
1589 : : MLX5_ASSERT(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) &
1590 : : wq_mask));
1591 : 0 : pkt = rte_pktmbuf_alloc(rxq->mp);
1592 [ # # ]: 0 : if (unlikely(pkt == NULL)) {
1593 : 0 : ++rxq->stats.rx_nombuf;
1594 : 0 : break;
1595 : : }
1596 : : len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT;
1597 : : MLX5_ASSERT((int)len >= (rxq->crc_present << 2));
1598 [ # # ]: 0 : if (rxq->crc_present)
1599 : 0 : len -= RTE_ETHER_CRC_LEN;
1600 [ # # ]: 0 : rxq_code = mprq_buf_to_pkt(rxq, pkt, len, buf,
1601 : : strd_idx, strd_cnt);
1602 [ # # ]: 0 : if (unlikely(rxq_code != MLX5_RXQ_CODE_EXIT)) {
1603 : : rte_pktmbuf_free_seg(pkt);
1604 [ # # ]: 0 : if (rxq_code == MLX5_RXQ_CODE_DROPPED) {
1605 : 0 : ++rxq->stats.idropped;
1606 : 0 : continue;
1607 : : }
1608 [ # # ]: 0 : if (rxq_code == MLX5_RXQ_CODE_NOMBUF) {
1609 : 0 : ++rxq->stats.rx_nombuf;
1610 : 0 : break;
1611 : : }
1612 : : }
1613 : : rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe);
1614 [ # # ]: 0 : if (cqe->lro_num_seg > 1) {
1615 : 0 : mlx5_lro_update_hdr(rte_pktmbuf_mtod(pkt, uint8_t *),
1616 : : cqe, mcqe, rxq, len);
1617 : 0 : pkt->ol_flags |= RTE_MBUF_F_RX_LRO;
1618 : 0 : pkt->tso_segsz = len / cqe->lro_num_seg;
1619 : : }
1620 : 0 : PKT_LEN(pkt) = len;
1621 : 0 : PORT(pkt) = rxq->port_id;
1622 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1623 : : /* Increment bytes counter. */
1624 : 0 : rxq->stats.ibytes += PKT_LEN(pkt);
1625 : : #endif
1626 : : /* Return packet. */
1627 : 0 : *(pkts++) = pkt;
1628 : 0 : ++i;
1629 : : }
1630 : : /* Update the consumer indexes. */
1631 : 0 : rxq->consumed_strd = consumed_strd;
1632 : 0 : rte_io_wmb();
1633 [ # # ]: 0 : *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci);
1634 [ # # ]: 0 : if (rq_ci != rxq->rq_ci) {
1635 : 0 : rxq->rq_ci = rq_ci;
1636 : 0 : rte_io_wmb();
1637 [ # # ]: 0 : *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
1638 : : }
1639 : : #ifdef MLX5_PMD_SOFT_COUNTERS
1640 : : /* Increment packets counter. */
1641 : 0 : rxq->stats.ipackets += i;
1642 : : #endif
1643 : 0 : return i;
1644 : : }
1645 : :
1646 : : int
1647 : 0 : mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev,
1648 : : uint16_t *queue_id, uint8_t *lwm)
1649 : : {
1650 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1651 : : unsigned int rxq_id, found = 0, n;
1652 : : struct mlx5_rxq_priv *rxq;
1653 : :
1654 [ # # ]: 0 : if (!queue_id)
1655 : : return -EINVAL;
1656 : : /* Query all the Rx queues of the port in a circular way. */
1657 [ # # ]: 0 : for (rxq_id = *queue_id, n = 0; n < priv->rxqs_n; n++) {
1658 : 0 : rxq = mlx5_rxq_get(dev, rxq_id);
1659 [ # # # # ]: 0 : if (rxq && rxq->lwm_event_pending) {
1660 : 0 : pthread_mutex_lock(&priv->sh->lwm_config_lock);
1661 : 0 : rxq->lwm_event_pending = 0;
1662 : 0 : pthread_mutex_unlock(&priv->sh->lwm_config_lock);
1663 : 0 : *queue_id = rxq_id;
1664 : : found = 1;
1665 [ # # ]: 0 : if (lwm)
1666 : 0 : *lwm = mlx5_rxq_lwm_to_percentage(rxq);
1667 : : break;
1668 : : }
1669 : 0 : rxq_id = (rxq_id + 1) % priv->rxqs_n;
1670 : : }
1671 : 0 : return found;
1672 : : }
1673 : :
1674 : : /**
1675 : : * Rte interrupt handler for LWM event.
1676 : : * It first checks if the event arrives, if so process the callback for
1677 : : * RTE_ETH_EVENT_RX_LWM.
1678 : : *
1679 : : * @param args
1680 : : * Generic pointer to mlx5_priv.
1681 : : */
1682 : : void
1683 : 0 : mlx5_dev_interrupt_handler_lwm(void *args)
1684 : : {
1685 : : struct mlx5_priv *priv = args;
1686 : : struct mlx5_rxq_priv *rxq;
1687 : : struct rte_eth_dev *dev;
1688 : 0 : int ret, rxq_idx = 0, port_id = 0;
1689 : :
1690 : 0 : ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id);
1691 [ # # ]: 0 : if (unlikely(ret < 0)) {
1692 : 0 : DRV_LOG(WARNING, "Cannot get LWM event context.");
1693 : 0 : return;
1694 : : }
1695 : 0 : DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__,
1696 : : port_id, rxq_idx);
1697 : 0 : dev = &rte_eth_devices[port_id];
1698 : 0 : rxq = mlx5_rxq_get(dev, rxq_idx);
1699 [ # # ]: 0 : if (rxq) {
1700 : 0 : pthread_mutex_lock(&priv->sh->lwm_config_lock);
1701 : 0 : rxq->lwm_event_pending = 1;
1702 : 0 : pthread_mutex_unlock(&priv->sh->lwm_config_lock);
1703 : : }
1704 : 0 : rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL);
1705 : : }
1706 : :
1707 : : /**
1708 : : * DPDK callback to arm an Rx queue LWM(limit watermark) event.
1709 : : * While the Rx queue fullness reaches the LWM limit, the driver catches
1710 : : * an HW event and invokes the user event callback.
1711 : : * After the last event handling, the user needs to call this API again
1712 : : * to arm an additional event.
1713 : : *
1714 : : * @param dev
1715 : : * Pointer to the device structure.
1716 : : * @param[in] rx_queue_id
1717 : : * Rx queue identificator.
1718 : : * @param[in] lwm
1719 : : * The LWM value, is defined by a percentage of the Rx queue size.
1720 : : * [1-99] to set a new LWM (update the old value).
1721 : : * 0 to unarm the event.
1722 : : *
1723 : : * @return
1724 : : * 0 : operation success.
1725 : : * Otherwise:
1726 : : * - ENOMEM - not enough memory to create LWM event channel.
1727 : : * - EINVAL - the input Rxq is not created by devx.
1728 : : * - E2BIG - lwm is bigger than 99.
1729 : : */
1730 : : int
1731 : 0 : mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id,
1732 : : uint8_t lwm)
1733 : : {
1734 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1735 : 0 : uint16_t port_id = PORT_ID(priv);
1736 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id);
1737 : 0 : uint16_t event_nums[1] = {MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED};
1738 : : struct mlx5_rxq_data *rxq_data;
1739 : : uint32_t wqe_cnt;
1740 : : uint64_t cookie;
1741 : : int ret = 0;
1742 : :
1743 [ # # ]: 0 : if (!rxq) {
1744 : 0 : rte_errno = EINVAL;
1745 : 0 : return -rte_errno;
1746 : : }
1747 : 0 : rxq_data = &rxq->ctrl->rxq;
1748 : : /* Ensure the Rq is created by devx. */
1749 [ # # ]: 0 : if (priv->obj_ops.rxq_obj_new != mlx5_devx_obj_ops.rxq_obj_new) {
1750 : 0 : rte_errno = EINVAL;
1751 : 0 : return -rte_errno;
1752 : : }
1753 [ # # ]: 0 : if (lwm > 99) {
1754 : 0 : DRV_LOG(WARNING, "Too big LWM configuration.");
1755 : 0 : rte_errno = E2BIG;
1756 : 0 : return -rte_errno;
1757 : : }
1758 : : /* Start config LWM. */
1759 : 0 : pthread_mutex_lock(&priv->sh->lwm_config_lock);
1760 [ # # # # ]: 0 : if (rxq->lwm == 0 && lwm == 0) {
1761 : : /* Both old/new values are 0, do nothing. */
1762 : : ret = 0;
1763 : 0 : goto end;
1764 : : }
1765 : 0 : wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n);
1766 [ # # ]: 0 : if (lwm) {
1767 [ # # ]: 0 : if (!priv->sh->devx_channel_lwm) {
1768 : 0 : ret = mlx5_lwm_setup(priv);
1769 [ # # ]: 0 : if (ret) {
1770 : 0 : DRV_LOG(WARNING,
1771 : : "Failed to create shared_lwm.");
1772 : 0 : rte_errno = ENOMEM;
1773 : : ret = -rte_errno;
1774 : 0 : goto end;
1775 : : }
1776 : : }
1777 [ # # ]: 0 : if (!rxq->lwm_devx_subscribed) {
1778 : 0 : cookie = ((uint32_t)
1779 : 0 : (port_id << LWM_COOKIE_PORTID_OFFSET)) |
1780 : 0 : (rx_queue_id << LWM_COOKIE_RXQID_OFFSET);
1781 : 0 : ret = mlx5_os_devx_subscribe_devx_event
1782 : 0 : (priv->sh->devx_channel_lwm,
1783 : 0 : rxq->devx_rq.rq->obj,
1784 : : sizeof(event_nums),
1785 : : event_nums,
1786 : : cookie);
1787 [ # # ]: 0 : if (ret) {
1788 [ # # ]: 0 : rte_errno = rte_errno ? rte_errno : EINVAL;
1789 : 0 : ret = -rte_errno;
1790 : 0 : goto end;
1791 : : }
1792 : 0 : rxq->lwm_devx_subscribed = 1;
1793 : : }
1794 : : }
1795 : : /* Save LWM to rxq and send modify_rq devx command. */
1796 : 0 : rxq->lwm = lwm * wqe_cnt / 100;
1797 : : /* Prevent integer division loss when switch lwm number to percentage. */
1798 [ # # # # ]: 0 : if (lwm && (lwm * wqe_cnt % 100)) {
1799 [ # # ]: 0 : rxq->lwm = ((uint32_t)(rxq->lwm + 1) >= wqe_cnt) ?
1800 : : rxq->lwm : (rxq->lwm + 1);
1801 : : }
1802 [ # # # # ]: 0 : if (lwm && !rxq->lwm) {
1803 : : /* With mprq, wqe_cnt may be < 100. */
1804 : 0 : DRV_LOG(WARNING, "Too small LWM configuration.");
1805 : 0 : rte_errno = EINVAL;
1806 : : ret = -rte_errno;
1807 : 0 : goto end;
1808 : : }
1809 : 0 : ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RDY2RDY);
1810 : 0 : end:
1811 : 0 : pthread_mutex_unlock(&priv->sh->lwm_config_lock);
1812 : 0 : return ret;
1813 : : }
1814 : :
1815 : : /**
1816 : : * Mlx5 access register function to configure host shaper.
1817 : : * It calls API in libmtcr_ul to access QSHR(Qos Shaper Host Register)
1818 : : * in firmware.
1819 : : *
1820 : : * @param dev
1821 : : * Pointer to rte_eth_dev.
1822 : : * @param lwm_triggered
1823 : : * Flag to enable/disable lwm_triggered bit in QSHR.
1824 : : * @param rate
1825 : : * Host shaper rate, unit is 100Mbps, set to 0 means disable the shaper.
1826 : : * @return
1827 : : * 0 : operation success.
1828 : : * Otherwise:
1829 : : * - ENOENT - no ibdev interface.
1830 : : * - EBUSY - the register access unit is busy.
1831 : : * - EIO - the register access command meets IO error.
1832 : : */
1833 : : static int
1834 : : mlxreg_host_shaper_config(struct rte_eth_dev *dev,
1835 : : bool lwm_triggered, uint8_t rate)
1836 : : {
1837 : : #ifdef HAVE_MLX5_MSTFLINT
1838 : : struct mlx5_priv *priv = dev->data->dev_private;
1839 : : uint32_t data[MLX5_ST_SZ_DW(register_qshr)] = {0};
1840 : : int rc, retry_count = 3;
1841 : : mfile *mf = NULL;
1842 : : int status;
1843 : : void *ptr;
1844 : :
1845 : : mf = mopen(priv->sh->ibdev_name);
1846 : : if (!mf) {
1847 : : DRV_LOG(WARNING, "mopen failed\n");
1848 : : rte_errno = ENOENT;
1849 : : return -rte_errno;
1850 : : }
1851 : : MLX5_SET(register_qshr, data, connected_host, 1);
1852 : : MLX5_SET(register_qshr, data, fast_response, lwm_triggered ? 1 : 0);
1853 : : MLX5_SET(register_qshr, data, local_port, 1);
1854 : : ptr = MLX5_ADDR_OF(register_qshr, data, global_config);
1855 : : MLX5_SET(ets_global_config_register, ptr, rate_limit_update, 1);
1856 : : MLX5_SET(ets_global_config_register, ptr, max_bw_units,
1857 : : rate ? ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS :
1858 : : ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED);
1859 : : MLX5_SET(ets_global_config_register, ptr, max_bw_value, rate);
1860 : : do {
1861 : : rc = maccess_reg(mf,
1862 : : MLX5_QSHR_REGISTER_ID,
1863 : : MACCESS_REG_METHOD_SET,
1864 : : (u_int32_t *)&data[0],
1865 : : sizeof(data),
1866 : : sizeof(data),
1867 : : sizeof(data),
1868 : : &status);
1869 : : if ((rc != ME_ICMD_STATUS_IFC_BUSY &&
1870 : : status != ME_REG_ACCESS_BAD_PARAM) ||
1871 : : !(mf->flags & MDEVS_REM)) {
1872 : : break;
1873 : : }
1874 : : DRV_LOG(WARNING, "%s retry.", __func__);
1875 : : usleep(10000);
1876 : : } while (retry_count-- > 0);
1877 : : mclose(mf);
1878 : : rte_errno = (rc == ME_REG_ACCESS_DEV_BUSY) ? EBUSY : EIO;
1879 : : return rc ? -rte_errno : 0;
1880 : : #else
1881 : : (void)dev;
1882 : : (void)lwm_triggered;
1883 : : (void)rate;
1884 : : return -1;
1885 : : #endif
1886 : : }
1887 : :
1888 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_host_shaper_config, 22.07)
1889 : 0 : int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate,
1890 : : uint32_t flags)
1891 : : {
1892 : : struct rte_eth_dev *dev = &rte_eth_devices[port_id];
1893 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1894 : : bool lwm_triggered =
1895 : 0 : !!(flags & RTE_BIT32(RTE_PMD_MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED));
1896 : :
1897 [ # # ]: 0 : if (!lwm_triggered) {
1898 : 0 : priv->sh->host_shaper_rate = rate;
1899 : : } else {
1900 [ # # # ]: 0 : switch (rate) {
1901 : 0 : case 0:
1902 : : /* Rate 0 means disable lwm_triggered. */
1903 : 0 : priv->sh->lwm_triggered = 0;
1904 : 0 : break;
1905 : 0 : case 1:
1906 : : /* Rate 1 means enable lwm_triggered. */
1907 : 0 : priv->sh->lwm_triggered = 1;
1908 : 0 : break;
1909 : : default:
1910 : : return -ENOTSUP;
1911 : : }
1912 : : }
1913 : 0 : return mlxreg_host_shaper_config(dev, priv->sh->lwm_triggered,
1914 : : priv->sh->host_shaper_rate);
1915 : : }
1916 : :
1917 : : /**
1918 : : * Dump RQ/CQ Context to a file.
1919 : : *
1920 : : * @param[in] port_id
1921 : : * Port ID
1922 : : * @param[in] queue_id
1923 : : * Queue ID
1924 : : * @param[in] filename
1925 : : * Name of file to dump the Rx Queue Context
1926 : : *
1927 : : * @return
1928 : : * 0 for Success, non-zero value depending on failure type
1929 : : */
1930 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_rxq_dump_contexts, 24.07)
1931 : 0 : int rte_pmd_mlx5_rxq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename)
1932 : : {
1933 : : struct rte_eth_dev *dev;
1934 : : struct mlx5_rxq_priv *rxq;
1935 : : struct mlx5_rxq_ctrl *rxq_ctrl;
1936 : : struct mlx5_rxq_obj *rxq_obj;
1937 : : struct mlx5_devx_rq *rq;
1938 : : struct mlx5_devx_cq *cq;
1939 : : struct mlx5_devx_obj *rq_devx_obj;
1940 : : struct mlx5_devx_obj *cq_devx_obj;
1941 : :
1942 : 0 : uint32_t rq_out[MLX5_ST_SZ_DW(query_rq_out)] = {0};
1943 : 0 : uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0};
1944 : :
1945 : : int ret;
1946 : : FILE *fd;
1947 : 0 : MKSTR(path, "./%s", filename);
1948 : :
1949 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id))
1950 : : return -ENODEV;
1951 : :
1952 [ # # ]: 0 : if (rte_eth_rx_queue_is_valid(port_id, queue_id))
1953 : : return -EINVAL;
1954 : :
1955 : 0 : fd = fopen(path, "w");
1956 [ # # ]: 0 : if (!fd) {
1957 : 0 : rte_errno = errno;
1958 : 0 : return -EIO;
1959 : : }
1960 : :
1961 : 0 : dev = &rte_eth_devices[port_id];
1962 : 0 : rxq = mlx5_rxq_ref(dev, queue_id);
1963 : 0 : rxq_ctrl = rxq->ctrl;
1964 : 0 : rxq_obj = rxq_ctrl->obj;
1965 : : rq = &rxq->devx_rq;
1966 : : cq = &rxq_obj->cq_obj;
1967 : 0 : rq_devx_obj = rq->rq;
1968 : 0 : cq_devx_obj = cq->cq;
1969 : :
1970 : : do {
1971 : 0 : ret = mlx5_devx_cmd_query_rq(rq_devx_obj, rq_out, sizeof(rq_out));
1972 [ # # ]: 0 : if (ret)
1973 : : break;
1974 : :
1975 : : /* Dump rq query output to file */
1976 : 0 : MKSTR(rq_headline, "RQ DevX ID = %u Port = %u Queue index = %u ",
1977 : : rq_devx_obj->id, port_id, queue_id);
1978 : 0 : mlx5_dump_to_file(fd, NULL, rq_headline, 0);
1979 : 0 : mlx5_dump_to_file(fd, "Query RQ Dump:",
1980 : : (const void *)((uintptr_t)rq_out),
1981 : : sizeof(rq_out));
1982 : :
1983 : 0 : ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out));
1984 [ # # ]: 0 : if (ret)
1985 : : break;
1986 : :
1987 : : /* Dump cq query output to file */
1988 : 0 : MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ",
1989 : : cq_devx_obj->id, port_id, queue_id);
1990 : 0 : mlx5_dump_to_file(fd, NULL, cq_headline, 0);
1991 : 0 : mlx5_dump_to_file(fd, "Query CQ Dump:",
1992 : : (const void *)((uintptr_t)cq_out),
1993 : : sizeof(cq_out));
1994 : : } while (false);
1995 : :
1996 : 0 : fclose(fd);
1997 : 0 : return ret;
1998 : : }
|