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_malloc.h>
23 : :
24 : : #include "mlx5_autoconf.h"
25 : : #include "mlx5_defs.h"
26 : : #include "mlx5.h"
27 : : #include "mlx5_utils.h"
28 : : #include "mlx5_rxtx.h"
29 : : #include "mlx5_tx.h"
30 : :
31 : : #define MLX5_TXOFF_INFO(func, olx) {mlx5_tx_burst_##func, olx},
32 : :
33 : : /**
34 : : * Move QP from error state to running state and initialize indexes.
35 : : *
36 : : * @param txq_ctrl
37 : : * Pointer to TX queue control structure.
38 : : *
39 : : * @return
40 : : * 0 on success, else -1.
41 : : */
42 : : static int
43 : 0 : tx_recover_qp(struct mlx5_txq_ctrl *txq_ctrl)
44 : : {
45 : 0 : struct mlx5_mp_arg_queue_state_modify sm = {
46 : : .is_wq = 0,
47 : 0 : .queue_id = txq_ctrl->txq.idx,
48 : : };
49 : :
50 [ # # ]: 0 : if (mlx5_queue_state_modify(ETH_DEV(txq_ctrl->priv), &sm))
51 : : return -1;
52 : 0 : txq_ctrl->txq.wqe_ci = 0;
53 : 0 : txq_ctrl->txq.wqe_pi = 0;
54 : 0 : txq_ctrl->txq.elts_comp = 0;
55 : 0 : return 0;
56 : : }
57 : :
58 : : /* Return 1 if the error CQE is signed otherwise, sign it and return 0. */
59 : : static int
60 : : check_err_cqe_seen(volatile struct mlx5_error_cqe *err_cqe)
61 : : {
62 : : static const uint8_t magic[] = "seen";
63 : : int ret = 1;
64 : : unsigned int i;
65 : :
66 [ # # ]: 0 : for (i = 0; i < sizeof(magic); ++i)
67 [ # # # # ]: 0 : if (!ret || err_cqe->rsvd1[i] != magic[i]) {
68 : : ret = 0;
69 : 0 : err_cqe->rsvd1[i] = magic[i];
70 : : }
71 : : return ret;
72 : : }
73 : :
74 : : /**
75 : : * Handle error CQE.
76 : : *
77 : : * @param txq
78 : : * Pointer to TX queue structure.
79 : : * @param error_cqe
80 : : * Pointer to the error CQE.
81 : : *
82 : : * @return
83 : : * Negative value if queue recovery failed, otherwise
84 : : * the error completion entry is handled successfully.
85 : : */
86 : : static int
87 : 0 : mlx5_tx_error_cqe_handle(struct mlx5_txq_data *__rte_restrict txq,
88 : : volatile struct mlx5_error_cqe *err_cqe)
89 : : {
90 [ # # ]: 0 : if (err_cqe->syndrome != MLX5_CQE_SYNDROME_WR_FLUSH_ERR) {
91 : 0 : const uint16_t wqe_m = ((1 << txq->wqe_n) - 1);
92 : : struct mlx5_txq_ctrl *txq_ctrl =
93 : 0 : container_of(txq, struct mlx5_txq_ctrl, txq);
94 : 0 : uint16_t new_wqe_pi = rte_be_to_cpu_16(err_cqe->wqe_counter);
95 : : int seen = check_err_cqe_seen(err_cqe);
96 : :
97 [ # # ]: 0 : if (!seen && txq_ctrl->dump_file_n <
98 [ # # ]: 0 : txq_ctrl->priv->config.max_dump_files_num) {
99 : 0 : MKSTR(err_str, "Unexpected CQE error syndrome "
100 : : "0x%02x CQN = %u SQN = %u wqe_counter = %u "
101 : : "wq_ci = %u cq_ci = %u", err_cqe->syndrome,
102 : : txq->cqe_s, txq->qp_num_8s >> 8,
103 : : rte_be_to_cpu_16(err_cqe->wqe_counter),
104 : : txq->wqe_ci, txq->cq_ci);
105 : 0 : MKSTR(name, "dpdk_mlx5_port_%u_txq_%u_index_%u_%u",
106 : : PORT_ID(txq_ctrl->priv), txq->idx,
107 : : txq_ctrl->dump_file_n, (uint32_t)rte_rdtsc());
108 : 0 : mlx5_dump_debug_information(name, NULL, err_str, 0);
109 : 0 : mlx5_dump_debug_information(name, "MLX5 Error CQ:",
110 : : (const void *)((uintptr_t)
111 : 0 : txq->cqes),
112 : : sizeof(struct mlx5_error_cqe) *
113 : 0 : (size_t)RTE_BIT32(txq->cqe_n));
114 : 0 : mlx5_dump_debug_information(name, "MLX5 Error SQ:",
115 : : (const void *)((uintptr_t)
116 : 0 : txq->wqes),
117 : : MLX5_WQE_SIZE *
118 : 0 : (size_t)RTE_BIT32(txq->wqe_n));
119 : 0 : txq_ctrl->dump_file_n++;
120 : : }
121 [ # # ]: 0 : if (!seen)
122 : : /*
123 : : * Count errors in WQEs units.
124 : : * Later it can be improved to count error packets,
125 : : * for example, by SQ parsing to find how much packets
126 : : * should be counted for each WQE.
127 : : */
128 : 0 : txq->stats.oerrors += ((txq->wqe_ci & wqe_m) -
129 : 0 : new_wqe_pi) & wqe_m;
130 [ # # ]: 0 : if (tx_recover_qp(txq_ctrl)) {
131 : : /* Recovering failed - retry later on the same WQE. */
132 : : return -1;
133 : : }
134 : : /* Release all the remaining buffers. */
135 : 0 : mlx5_txq_free_elts(txq_ctrl);
136 : : }
137 : : return 0;
138 : : }
139 : :
140 : : /**
141 : : * Update completion queue consuming index via doorbell
142 : : * and flush the completed data buffers.
143 : : *
144 : : * @param txq
145 : : * Pointer to TX queue structure.
146 : : * @param last_cqe
147 : : * valid CQE pointer, if not NULL update txq->wqe_pi and flush the buffers.
148 : : */
149 : : static __rte_always_inline void
150 : : mlx5_tx_comp_flush(struct mlx5_txq_data *__rte_restrict txq,
151 : : volatile struct mlx5_cqe *last_cqe)
152 : : {
153 : 0 : if (likely(last_cqe != NULL)) {
154 : : uint16_t tail;
155 : :
156 : 0 : txq->wqe_pi = rte_be_to_cpu_16(last_cqe->wqe_counter);
157 : 0 : tail = txq->fcqs[(txq->cq_ci - 1) & txq->cqe_m];
158 [ # # ]: 0 : if (likely(tail != txq->elts_tail)) {
159 : : mlx5_tx_free_elts(txq, tail);
160 : : MLX5_ASSERT(tail == txq->elts_tail);
161 : : }
162 : : }
163 : : }
164 : :
165 : : /**
166 : : * Manage TX completions. This routine checks the CQ for
167 : : * arrived CQEs, deduces the last accomplished WQE in SQ,
168 : : * updates SQ producing index and frees all completed mbufs.
169 : : *
170 : : * @param txq
171 : : * Pointer to TX queue structure.
172 : : *
173 : : * NOTE: not inlined intentionally, it makes tx_burst
174 : : * routine smaller, simple and faster - from experiments.
175 : : */
176 : : void
177 : 0 : mlx5_tx_handle_completion(struct mlx5_txq_data *__rte_restrict txq)
178 : : {
179 : : unsigned int count = MLX5_TX_COMP_MAX_CQE;
180 : : volatile struct mlx5_cqe *last_cqe = NULL;
181 : : bool ring_doorbell = false;
182 : : int ret;
183 : :
184 : : do {
185 : : volatile struct mlx5_cqe *cqe;
186 : :
187 : 0 : cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
188 [ # # ]: 0 : ret = check_cqe(cqe, txq->cqe_s, txq->cq_ci);
189 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
190 [ # # ]: 0 : if (likely(ret != MLX5_CQE_STATUS_ERR)) {
191 : : /* No new CQEs in completion queue. */
192 : : MLX5_ASSERT(ret == MLX5_CQE_STATUS_HW_OWN);
193 : : break;
194 : : }
195 : : /*
196 : : * Some error occurred, try to restart.
197 : : * We have no barrier after WQE related Doorbell
198 : : * written, make sure all writes are completed
199 : : * here, before we might perform SQ reset.
200 : : */
201 : : rte_wmb();
202 : 0 : ret = mlx5_tx_error_cqe_handle
203 : : (txq, (volatile struct mlx5_error_cqe *)cqe);
204 [ # # ]: 0 : if (unlikely(ret < 0)) {
205 : : /*
206 : : * Some error occurred on queue error
207 : : * handling, we do not advance the index
208 : : * here, allowing to retry on next call.
209 : : */
210 : : return;
211 : : }
212 : : /*
213 : : * We are going to fetch all entries with
214 : : * MLX5_CQE_SYNDROME_WR_FLUSH_ERR status.
215 : : * The send queue is supposed to be empty.
216 : : */
217 : : ring_doorbell = true;
218 : 0 : ++txq->cq_ci;
219 : 0 : txq->cq_pi = txq->cq_ci;
220 : : last_cqe = NULL;
221 : 0 : continue;
222 : : }
223 : : /* Normal transmit completion. */
224 : : MLX5_ASSERT(txq->cq_ci != txq->cq_pi);
225 : : #ifdef RTE_PMD_MLX5_DEBUG
226 : : MLX5_ASSERT((txq->fcqs[txq->cq_ci & txq->cqe_m] >> 16) ==
227 : : cqe->wqe_counter);
228 : : #endif
229 : : if (__rte_trace_point_fp_is_enabled()) {
230 : : uint64_t ts = rte_be_to_cpu_64(cqe->timestamp);
231 : : uint16_t wqe_id = rte_be_to_cpu_16(cqe->wqe_counter);
232 : :
233 : : if (txq->rt_timestamp)
234 : : ts = mlx5_txpp_convert_rx_ts(NULL, ts);
235 : : rte_pmd_mlx5_trace_tx_complete(txq->port_id, txq->idx,
236 : : wqe_id, ts);
237 : : }
238 : : ring_doorbell = true;
239 : 0 : ++txq->cq_ci;
240 : : last_cqe = cqe;
241 : : /*
242 : : * We have to restrict the amount of processed CQEs
243 : : * in one tx_burst routine call. The CQ may be large
244 : : * and many CQEs may be updated by the NIC in one
245 : : * transaction. Buffers freeing is time consuming,
246 : : * multiple iterations may introduce significant latency.
247 : : */
248 [ # # ]: 0 : if (likely(--count == 0))
249 : : break;
250 : : } while (true);
251 [ # # ]: 0 : if (likely(ring_doorbell)) {
252 : : /* Ring doorbell to notify hardware. */
253 : 0 : rte_compiler_barrier();
254 [ # # # # ]: 0 : *txq->cq_db = rte_cpu_to_be_32(txq->cq_ci);
255 : : mlx5_tx_comp_flush(txq, last_cqe);
256 : : }
257 : : }
258 : :
259 : : /**
260 : : * DPDK callback to check the status of a Tx descriptor.
261 : : *
262 : : * @param tx_queue
263 : : * The Tx queue.
264 : : * @param[in] offset
265 : : * The index of the descriptor in the ring.
266 : : *
267 : : * @return
268 : : * The status of the Tx descriptor.
269 : : */
270 : : int
271 : 0 : mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
272 : : {
273 : : struct mlx5_txq_data *__rte_restrict txq = tx_queue;
274 : : uint16_t used;
275 : :
276 : 0 : mlx5_tx_handle_completion(txq);
277 : 0 : used = txq->elts_head - txq->elts_tail;
278 [ # # ]: 0 : if (offset < used)
279 : 0 : return RTE_ETH_TX_DESC_FULL;
280 : : return RTE_ETH_TX_DESC_DONE;
281 : : }
282 : :
283 : : /*
284 : : * Array of declared and compiled Tx burst function and corresponding
285 : : * supported offloads set. The array is used to select the Tx burst
286 : : * function for specified offloads set at Tx queue configuration time.
287 : : */
288 : : static const struct {
289 : : eth_tx_burst_t func;
290 : : unsigned int olx;
291 : : } txoff_func[] = {
292 : : MLX5_TXOFF_INFO(full_empw,
293 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
294 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
295 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
296 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
297 : :
298 : : MLX5_TXOFF_INFO(none_empw,
299 : : MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW)
300 : :
301 : : MLX5_TXOFF_INFO(md_empw,
302 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
303 : :
304 : : MLX5_TXOFF_INFO(mt_empw,
305 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
306 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
307 : :
308 : : MLX5_TXOFF_INFO(mtsc_empw,
309 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
310 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
311 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
312 : :
313 : : MLX5_TXOFF_INFO(mti_empw,
314 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
315 : : MLX5_TXOFF_CONFIG_INLINE |
316 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
317 : :
318 : : MLX5_TXOFF_INFO(mtv_empw,
319 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
320 : : MLX5_TXOFF_CONFIG_VLAN |
321 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
322 : :
323 : : MLX5_TXOFF_INFO(mtiv_empw,
324 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
325 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
326 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
327 : :
328 : : MLX5_TXOFF_INFO(sc_empw,
329 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
330 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
331 : :
332 : : MLX5_TXOFF_INFO(sci_empw,
333 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
334 : : MLX5_TXOFF_CONFIG_INLINE |
335 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
336 : :
337 : : MLX5_TXOFF_INFO(scv_empw,
338 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
339 : : MLX5_TXOFF_CONFIG_VLAN |
340 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
341 : :
342 : : MLX5_TXOFF_INFO(sciv_empw,
343 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
344 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
345 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
346 : :
347 : : MLX5_TXOFF_INFO(i_empw,
348 : : MLX5_TXOFF_CONFIG_INLINE |
349 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
350 : :
351 : : MLX5_TXOFF_INFO(v_empw,
352 : : MLX5_TXOFF_CONFIG_VLAN |
353 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
354 : :
355 : : MLX5_TXOFF_INFO(iv_empw,
356 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
357 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
358 : :
359 : : MLX5_TXOFF_INFO(full_ts_nompw,
360 : : MLX5_TXOFF_CONFIG_FULL | MLX5_TXOFF_CONFIG_TXPP)
361 : :
362 : : MLX5_TXOFF_INFO(full_ts_nompwi,
363 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
364 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
365 : : MLX5_TXOFF_CONFIG_VLAN | MLX5_TXOFF_CONFIG_METADATA |
366 : : MLX5_TXOFF_CONFIG_TXPP)
367 : :
368 : : MLX5_TXOFF_INFO(full_ts,
369 : : MLX5_TXOFF_CONFIG_FULL | MLX5_TXOFF_CONFIG_TXPP |
370 : : MLX5_TXOFF_CONFIG_EMPW)
371 : :
372 : : MLX5_TXOFF_INFO(full_ts_noi,
373 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
374 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
375 : : MLX5_TXOFF_CONFIG_VLAN | MLX5_TXOFF_CONFIG_METADATA |
376 : : MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
377 : :
378 : : MLX5_TXOFF_INFO(none_ts,
379 : : MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_TXPP |
380 : : MLX5_TXOFF_CONFIG_EMPW)
381 : :
382 : : MLX5_TXOFF_INFO(mdi_ts,
383 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_METADATA |
384 : : MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
385 : :
386 : : MLX5_TXOFF_INFO(mti_ts,
387 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
388 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_METADATA |
389 : : MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
390 : :
391 : : MLX5_TXOFF_INFO(mtiv_ts,
392 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
393 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
394 : : MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_TXPP |
395 : : MLX5_TXOFF_CONFIG_EMPW)
396 : :
397 : : MLX5_TXOFF_INFO(full,
398 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
399 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
400 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
401 : : MLX5_TXOFF_CONFIG_METADATA)
402 : :
403 : : MLX5_TXOFF_INFO(none,
404 : : MLX5_TXOFF_CONFIG_NONE)
405 : :
406 : : MLX5_TXOFF_INFO(md,
407 : : MLX5_TXOFF_CONFIG_METADATA)
408 : :
409 : : MLX5_TXOFF_INFO(mt,
410 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
411 : : MLX5_TXOFF_CONFIG_METADATA)
412 : :
413 : : MLX5_TXOFF_INFO(mtsc,
414 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
415 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
416 : : MLX5_TXOFF_CONFIG_METADATA)
417 : :
418 : : MLX5_TXOFF_INFO(mti,
419 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
420 : : MLX5_TXOFF_CONFIG_INLINE |
421 : : MLX5_TXOFF_CONFIG_METADATA)
422 : :
423 : : MLX5_TXOFF_INFO(mtv,
424 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
425 : : MLX5_TXOFF_CONFIG_VLAN |
426 : : MLX5_TXOFF_CONFIG_METADATA)
427 : :
428 : : MLX5_TXOFF_INFO(mtiv,
429 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
430 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
431 : : MLX5_TXOFF_CONFIG_METADATA)
432 : :
433 : : MLX5_TXOFF_INFO(sc,
434 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
435 : : MLX5_TXOFF_CONFIG_METADATA)
436 : :
437 : : MLX5_TXOFF_INFO(sci,
438 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
439 : : MLX5_TXOFF_CONFIG_INLINE |
440 : : MLX5_TXOFF_CONFIG_METADATA)
441 : :
442 : : MLX5_TXOFF_INFO(scv,
443 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
444 : : MLX5_TXOFF_CONFIG_VLAN |
445 : : MLX5_TXOFF_CONFIG_METADATA)
446 : :
447 : : MLX5_TXOFF_INFO(sciv,
448 : : MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
449 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
450 : : MLX5_TXOFF_CONFIG_METADATA)
451 : :
452 : : MLX5_TXOFF_INFO(i,
453 : : MLX5_TXOFF_CONFIG_INLINE |
454 : : MLX5_TXOFF_CONFIG_METADATA)
455 : :
456 : : MLX5_TXOFF_INFO(v,
457 : : MLX5_TXOFF_CONFIG_VLAN |
458 : : MLX5_TXOFF_CONFIG_METADATA)
459 : :
460 : : MLX5_TXOFF_INFO(iv,
461 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
462 : : MLX5_TXOFF_CONFIG_METADATA)
463 : :
464 : : MLX5_TXOFF_INFO(none_mpw,
465 : : MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW |
466 : : MLX5_TXOFF_CONFIG_MPW)
467 : :
468 : : MLX5_TXOFF_INFO(mci_mpw,
469 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
470 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
471 : : MLX5_TXOFF_CONFIG_MPW)
472 : :
473 : : MLX5_TXOFF_INFO(mc_mpw,
474 : : MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
475 : : MLX5_TXOFF_CONFIG_EMPW | MLX5_TXOFF_CONFIG_MPW)
476 : :
477 : : MLX5_TXOFF_INFO(i_mpw,
478 : : MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
479 : : MLX5_TXOFF_CONFIG_MPW)
480 : : };
481 : :
482 : : /**
483 : : * Configure the Tx function to use. The routine checks configured
484 : : * Tx offloads for the device and selects appropriate Tx burst routine.
485 : : * There are multiple Tx burst routines compiled from the same template
486 : : * in the most optimal way for the dedicated Tx offloads set.
487 : : *
488 : : * @param dev
489 : : * Pointer to private data structure.
490 : : *
491 : : * @return
492 : : * Pointer to selected Tx burst function.
493 : : */
494 : : eth_tx_burst_t
495 : 0 : mlx5_select_tx_function(struct rte_eth_dev *dev)
496 : : {
497 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
498 : : struct mlx5_port_config *config = &priv->config;
499 : 0 : uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads;
500 : : unsigned int diff = 0, olx = 0, i, m;
501 : :
502 : : MLX5_ASSERT(priv);
503 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS) {
504 : : /* We should support Multi-Segment Packets. */
505 : : olx |= MLX5_TXOFF_CONFIG_MULTI;
506 : : }
507 [ # # ]: 0 : if (tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
508 : : RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
509 : : RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
510 : : RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
511 : : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO)) {
512 : : /* We should support TCP Send Offload. */
513 : 0 : olx |= MLX5_TXOFF_CONFIG_TSO;
514 : : }
515 [ # # ]: 0 : if (tx_offloads & (RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
516 : : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO |
517 : : RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
518 : : /* We should support Software Parser for Tunnels. */
519 : 0 : olx |= MLX5_TXOFF_CONFIG_SWP;
520 : : }
521 [ # # ]: 0 : if (tx_offloads & (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
522 : : RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
523 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
524 : : RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
525 : : /* We should support IP/TCP/UDP Checksums. */
526 : 0 : olx |= MLX5_TXOFF_CONFIG_CSUM;
527 : : }
528 [ # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_VLAN_INSERT) {
529 : : /* We should support VLAN insertion. */
530 : 0 : olx |= MLX5_TXOFF_CONFIG_VLAN;
531 : : }
532 [ # # # # ]: 0 : if (tx_offloads & RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP &&
533 : 0 : rte_mbuf_dynflag_lookup
534 [ # # ]: 0 : (RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, NULL) >= 0 &&
535 : 0 : rte_mbuf_dynfield_lookup
536 : : (RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL) >= 0) {
537 : : /* Offload configured, dynamic entities registered. */
538 : 0 : olx |= MLX5_TXOFF_CONFIG_TXPP;
539 : : }
540 [ # # # # ]: 0 : if (priv->txqs_n && (*priv->txqs)[0]) {
541 : : struct mlx5_txq_data *txd = (*priv->txqs)[0];
542 : :
543 [ # # ]: 0 : if (txd->inlen_send) {
544 : : /*
545 : : * Check the data inline requirements. Data inline
546 : : * is enabled on per device basis, we can check
547 : : * the first Tx queue only.
548 : : *
549 : : * If device does not support VLAN insertion in WQE
550 : : * and some queues are requested to perform VLAN
551 : : * insertion offload than inline must be enabled.
552 : : */
553 : 0 : olx |= MLX5_TXOFF_CONFIG_INLINE;
554 : : }
555 : : }
556 [ # # ]: 0 : if (config->mps == MLX5_MPW_ENHANCED &&
557 [ # # ]: 0 : config->txq_inline_min <= 0) {
558 : : /*
559 : : * The NIC supports Enhanced Multi-Packet Write
560 : : * and does not require minimal inline data.
561 : : */
562 : 0 : olx |= MLX5_TXOFF_CONFIG_EMPW;
563 : : }
564 [ # # ]: 0 : if (rte_flow_dynf_metadata_avail()) {
565 : : /* We should support Flow metadata. */
566 : 0 : olx |= MLX5_TXOFF_CONFIG_METADATA;
567 : : }
568 [ # # ]: 0 : if (config->mps == MLX5_MPW) {
569 : : /*
570 : : * The NIC supports Legacy Multi-Packet Write.
571 : : * The MLX5_TXOFF_CONFIG_MPW controls the descriptor building
572 : : * method in combination with MLX5_TXOFF_CONFIG_EMPW.
573 : : */
574 [ # # ]: 0 : if (!(olx & (MLX5_TXOFF_CONFIG_TSO |
575 : : MLX5_TXOFF_CONFIG_SWP |
576 : : MLX5_TXOFF_CONFIG_VLAN |
577 : : MLX5_TXOFF_CONFIG_METADATA)))
578 : 0 : olx |= MLX5_TXOFF_CONFIG_EMPW |
579 : : MLX5_TXOFF_CONFIG_MPW;
580 : : }
581 : : /*
582 : : * Scan the routines table to find the minimal
583 : : * satisfying routine with requested offloads.
584 : : */
585 : : m = RTE_DIM(txoff_func);
586 [ # # ]: 0 : for (i = 0; i < RTE_DIM(txoff_func); i++) {
587 : : unsigned int tmp;
588 : :
589 : 0 : tmp = txoff_func[i].olx;
590 [ # # ]: 0 : if (tmp == olx) {
591 : : /* Meets requested offloads exactly.*/
592 : : m = i;
593 : : break;
594 : : }
595 [ # # ]: 0 : if ((tmp & olx) != olx) {
596 : : /* Does not meet requested offloads at all. */
597 : 0 : continue;
598 : : }
599 [ # # ]: 0 : if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_MPW)
600 : : /* Do not enable legacy MPW if not configured. */
601 : 0 : continue;
602 [ # # ]: 0 : if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_EMPW)
603 : : /* Do not enable eMPW if not configured. */
604 : 0 : continue;
605 [ # # ]: 0 : if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_INLINE)
606 : : /* Do not enable inlining if not configured. */
607 : 0 : continue;
608 [ # # ]: 0 : if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_TXPP)
609 : : /* Do not enable scheduling if not configured. */
610 : 0 : continue;
611 : : /*
612 : : * Some routine meets the requirements.
613 : : * Check whether it has minimal amount
614 : : * of not requested offloads.
615 : : */
616 [ # # ]: 0 : tmp = rte_popcount64(tmp & ~olx);
617 [ # # ]: 0 : if (m >= RTE_DIM(txoff_func) || tmp < diff) {
618 : : /* First or better match, save and continue. */
619 : : m = i;
620 : : diff = tmp;
621 : 0 : continue;
622 : : }
623 [ # # ]: 0 : if (tmp == diff) {
624 : 0 : tmp = txoff_func[i].olx ^ txoff_func[m].olx;
625 [ # # ]: 0 : if (rte_ffs32(txoff_func[i].olx & ~tmp) <
626 [ # # ]: 0 : rte_ffs32(txoff_func[m].olx & ~tmp)) {
627 : : /* Lighter not requested offload. */
628 : : m = i;
629 : : }
630 : : }
631 : : }
632 [ # # ]: 0 : if (m >= RTE_DIM(txoff_func)) {
633 : 0 : DRV_LOG(DEBUG, "port %u has no selected Tx function"
634 : : " for requested offloads %04X",
635 : : dev->data->port_id, olx);
636 : 0 : return NULL;
637 : : }
638 : 0 : DRV_LOG(DEBUG, "port %u has selected Tx function"
639 : : " supporting offloads %04X/%04X",
640 : : dev->data->port_id, olx, txoff_func[m].olx);
641 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MULTI)
642 : 0 : DRV_LOG(DEBUG, "\tMULTI (multi segment)");
643 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_TSO)
644 : 0 : DRV_LOG(DEBUG, "\tTSO (TCP send offload)");
645 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_SWP)
646 : 0 : DRV_LOG(DEBUG, "\tSWP (software parser)");
647 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_CSUM)
648 : 0 : DRV_LOG(DEBUG, "\tCSUM (checksum offload)");
649 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_INLINE)
650 : 0 : DRV_LOG(DEBUG, "\tINLIN (inline data)");
651 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_VLAN)
652 : 0 : DRV_LOG(DEBUG, "\tVLANI (VLAN insertion)");
653 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_METADATA)
654 : 0 : DRV_LOG(DEBUG, "\tMETAD (tx Flow metadata)");
655 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_TXPP)
656 : 0 : DRV_LOG(DEBUG, "\tMETAD (tx Scheduling)");
657 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_EMPW) {
658 [ # # ]: 0 : if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MPW)
659 : 0 : DRV_LOG(DEBUG, "\tMPW (Legacy MPW)");
660 : : else
661 : 0 : DRV_LOG(DEBUG, "\tEMPW (Enhanced MPW)");
662 : : }
663 : 0 : return txoff_func[m].func;
664 : : }
665 : :
666 : : /**
667 : : * DPDK callback to get the TX queue information.
668 : : *
669 : : * @param dev
670 : : * Pointer to the device structure.
671 : : *
672 : : * @param tx_queue_id
673 : : * Tx queue identificator.
674 : : *
675 : : * @param qinfo
676 : : * Pointer to the TX queue information structure.
677 : : *
678 : : * @return
679 : : * None.
680 : : */
681 : : void
682 : 0 : mlx5_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
683 : : struct rte_eth_txq_info *qinfo)
684 : : {
685 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
686 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[tx_queue_id];
687 : : struct mlx5_txq_ctrl *txq_ctrl =
688 : : container_of(txq, struct mlx5_txq_ctrl, txq);
689 : :
690 [ # # ]: 0 : if (!txq)
691 : : return;
692 : 0 : qinfo->nb_desc = txq->elts_s;
693 : 0 : qinfo->conf.tx_thresh.pthresh = 0;
694 : 0 : qinfo->conf.tx_thresh.hthresh = 0;
695 : 0 : qinfo->conf.tx_thresh.wthresh = 0;
696 : 0 : qinfo->conf.tx_rs_thresh = 0;
697 : 0 : qinfo->conf.tx_free_thresh = 0;
698 : 0 : qinfo->conf.tx_deferred_start = txq_ctrl ? 0 : 1;
699 : 0 : qinfo->conf.offloads = dev->data->dev_conf.txmode.offloads;
700 : : }
701 : :
702 : : /**
703 : : * DPDK callback to get the TX packet burst mode information.
704 : : *
705 : : * @param dev
706 : : * Pointer to the device structure.
707 : : *
708 : : * @param tx_queue_id
709 : : * Tx queue identification.
710 : : *
711 : : * @param mode
712 : : * Pointer to the burts mode information.
713 : : *
714 : : * @return
715 : : * 0 as success, -EINVAL as failure.
716 : : */
717 : : int
718 : 0 : mlx5_tx_burst_mode_get(struct rte_eth_dev *dev,
719 : : uint16_t tx_queue_id,
720 : : struct rte_eth_burst_mode *mode)
721 : : {
722 : 0 : eth_tx_burst_t pkt_burst = dev->tx_pkt_burst;
723 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
724 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[tx_queue_id];
725 : : unsigned int i, olx;
726 : :
727 [ # # ]: 0 : for (i = 0; i < RTE_DIM(txoff_func); i++) {
728 [ # # ]: 0 : if (pkt_burst == txoff_func[i].func) {
729 : 0 : olx = txoff_func[i].olx;
730 [ # # ]: 0 : snprintf(mode->info, sizeof(mode->info),
731 : : "%s%s%s%s%s%s%s%s%s%s",
732 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_EMPW) ?
733 : 0 : ((olx & MLX5_TXOFF_CONFIG_MPW) ?
734 [ # # ]: 0 : "Legacy MPW" : "Enhanced MPW") : "No MPW",
735 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_MULTI) ?
736 : : " + MULTI" : "",
737 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_TSO) ?
738 : : " + TSO" : "",
739 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_SWP) ?
740 : : " + SWP" : "",
741 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_CSUM) ?
742 : : " + CSUM" : "",
743 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_INLINE) ?
744 : : " + INLINE" : "",
745 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_VLAN) ?
746 : : " + VLAN" : "",
747 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_METADATA) ?
748 : : " + METADATA" : "",
749 [ # # ]: 0 : (olx & MLX5_TXOFF_CONFIG_TXPP) ?
750 : : " + TXPP" : "",
751 [ # # ]: 0 : (txq && txq->fast_free) ?
752 : : " + Fast Free" : "");
753 : 0 : return 0;
754 : : }
755 : : }
756 : : return -EINVAL;
757 : : }
758 : :
759 : : /**
760 : : * Dump SQ/CQ Context to a file.
761 : : *
762 : : * @param[in] port_id
763 : : * Port ID
764 : : * @param[in] queue_id
765 : : * Queue ID
766 : : * @param[in] filename
767 : : * Name of file to dump the Tx Queue Context
768 : : *
769 : : * @return
770 : : * 0 for success, non-zero value depending on failure.
771 : : *
772 : : */
773 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_txq_dump_contexts, 24.07)
774 : 0 : int rte_pmd_mlx5_txq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename)
775 : : {
776 : : struct rte_eth_dev *dev;
777 : : struct mlx5_priv *priv;
778 : : struct mlx5_txq_data *txq_data;
779 : : struct mlx5_txq_ctrl *txq_ctrl;
780 : : struct mlx5_txq_obj *txq_obj;
781 : : struct mlx5_devx_sq *sq;
782 : : struct mlx5_devx_cq *cq;
783 : : struct mlx5_devx_obj *sq_devx_obj;
784 : : struct mlx5_devx_obj *cq_devx_obj;
785 : :
786 : 0 : uint32_t sq_out[MLX5_ST_SZ_DW(query_sq_out)] = {0};
787 : 0 : uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0};
788 : :
789 : : int ret;
790 : : FILE *fd;
791 : 0 : MKSTR(path, "./%s", filename);
792 : :
793 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id))
794 : : return -ENODEV;
795 : :
796 [ # # ]: 0 : if (rte_eth_tx_queue_is_valid(port_id, queue_id) != 0)
797 : : return -EINVAL;
798 : :
799 : 0 : fd = fopen(path, "w");
800 [ # # ]: 0 : if (!fd) {
801 : 0 : rte_errno = errno;
802 : 0 : return -EIO;
803 : : }
804 : :
805 : : dev = &rte_eth_devices[port_id];
806 : 0 : priv = dev->data->dev_private;
807 : 0 : txq_data = (*priv->txqs)[queue_id];
808 : 0 : txq_ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
809 : 0 : txq_obj = txq_ctrl->obj;
810 : : sq = &txq_obj->sq_obj;
811 : : cq = &txq_obj->cq_obj;
812 : 0 : sq_devx_obj = sq->sq;
813 : 0 : cq_devx_obj = cq->cq;
814 : :
815 : : do {
816 : 0 : ret = mlx5_devx_cmd_query_sq(sq_devx_obj, sq_out, sizeof(sq_out));
817 [ # # ]: 0 : if (ret)
818 : : break;
819 : :
820 : : /* Dump sq query output to file */
821 : 0 : MKSTR(sq_headline, "SQ DevX ID = %u Port = %u Queue index = %u ",
822 : : sq_devx_obj->id, port_id, queue_id);
823 : 0 : mlx5_dump_to_file(fd, NULL, sq_headline, 0);
824 : 0 : mlx5_dump_to_file(fd, "Query SQ Dump:",
825 : : (const void *)((uintptr_t)sq_out),
826 : : sizeof(sq_out));
827 : :
828 : 0 : ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out));
829 [ # # ]: 0 : if (ret)
830 : : break;
831 : :
832 : : /* Dump cq query output to file */
833 : 0 : MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ",
834 : : cq_devx_obj->id, port_id, queue_id);
835 : 0 : mlx5_dump_to_file(fd, NULL, cq_headline, 0);
836 : 0 : mlx5_dump_to_file(fd, "Query CQ Dump:",
837 : : (const void *)((uintptr_t)cq_out),
838 : : sizeof(cq_out));
839 : : } while (false);
840 : :
841 : 0 : fclose(fd);
842 : 0 : return ret;
843 : : }
844 : :
845 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_txq_rate_limit_query, 26.07)
846 : 0 : int rte_pmd_mlx5_txq_rate_limit_query(uint16_t port_id, uint16_t queue_id,
847 : : struct rte_pmd_mlx5_txq_rate_limit_info *info)
848 : : {
849 : : struct rte_eth_dev *dev;
850 : : struct mlx5_priv *priv;
851 : : struct mlx5_txq_data *txq_data;
852 : : struct mlx5_txq_ctrl *txq_ctrl;
853 : 0 : uint32_t sq_out[MLX5_ST_SZ_DW(query_sq_out)] = {0};
854 : : int ret;
855 : :
856 [ # # ]: 0 : if (info == NULL)
857 : : return -EINVAL;
858 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id))
859 : : return -ENODEV;
860 [ # # ]: 0 : if (rte_eth_tx_queue_is_valid(port_id, queue_id) != 0)
861 : : return -EINVAL;
862 : : dev = &rte_eth_devices[port_id];
863 : 0 : priv = dev->data->dev_private;
864 : 0 : txq_data = (*priv->txqs)[queue_id];
865 [ # # ]: 0 : if (txq_data == NULL)
866 : : return -EINVAL;
867 : 0 : txq_ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
868 : 0 : info->rate_mbps = txq_ctrl->rate_limit.rate_mbps;
869 : 0 : info->pp_index = txq_ctrl->rate_limit.pp_id;
870 [ # # ]: 0 : if (txq_ctrl->obj == NULL) {
871 : 0 : info->fw_pp_index = 0;
872 : 0 : return 0;
873 : : }
874 : 0 : ret = mlx5_devx_cmd_query_sq(txq_ctrl->obj->sq_obj.sq,
875 : : sq_out, sizeof(sq_out));
876 [ # # ]: 0 : if (ret)
877 : : return -EIO;
878 [ # # ]: 0 : info->fw_pp_index = MLX5_GET(sqc,
879 : : MLX5_ADDR_OF(query_sq_out, sq_out,
880 : : sq_context),
881 : : packet_pacing_rate_limit_index);
882 : 0 : return 0;
883 : : }
884 : :
885 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_pp_rate_table_query, 26.07)
886 : 0 : int rte_pmd_mlx5_pp_rate_table_query(uint16_t port_id,
887 : : struct rte_pmd_mlx5_pp_rate_table_info *info)
888 : : {
889 : : struct rte_eth_dev *dev;
890 : : struct mlx5_priv *priv;
891 : : uint16_t used = 0;
892 : : uint16_t *seen;
893 : : unsigned int i;
894 : :
895 [ # # ]: 0 : if (info == NULL)
896 : : return -EINVAL;
897 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id))
898 : : return -ENODEV;
899 : : dev = &rte_eth_devices[port_id];
900 : 0 : priv = dev->data->dev_private;
901 [ # # ]: 0 : if (!priv->sh->cdev->config.hca_attr.qos.packet_pacing) {
902 : 0 : rte_errno = ENOTSUP;
903 : 0 : return -ENOTSUP;
904 : : }
905 : 0 : info->total = priv->sh->cdev->config.hca_attr.qos.packet_pacing_rate_table_size;
906 [ # # # # ]: 0 : if (priv->txqs == NULL || priv->txqs_n == 0) {
907 : 0 : info->port_used = 0;
908 : 0 : return 0;
909 : : }
910 : 0 : seen = mlx5_malloc(MLX5_MEM_SYS | MLX5_MEM_ZERO,
911 : 0 : priv->txqs_n * sizeof(*seen), 0, SOCKET_ID_ANY);
912 [ # # ]: 0 : if (seen == NULL)
913 : : return -ENOMEM;
914 : : /*
915 : : * Count unique non-zero PP indices across this port's Tx queues.
916 : : * Note: the count reflects only queues on this port; other ports
917 : : * sharing the same device may also consume rate table entries.
918 : : */
919 [ # # ]: 0 : for (i = 0; i < priv->txqs_n; i++) {
920 : : struct mlx5_txq_data *txq_data;
921 : : struct mlx5_txq_ctrl *txq_ctrl;
922 : : uint16_t pp_id;
923 : : uint16_t j;
924 : : bool dup;
925 : :
926 [ # # ]: 0 : if ((*priv->txqs)[i] == NULL)
927 : 0 : continue;
928 : : txq_data = (*priv->txqs)[i];
929 : 0 : txq_ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
930 : 0 : pp_id = txq_ctrl->rate_limit.pp_id;
931 [ # # ]: 0 : if (pp_id == 0)
932 : 0 : continue;
933 : : dup = false;
934 [ # # ]: 0 : for (j = 0; j < used; j++) {
935 [ # # ]: 0 : if (seen[j] == pp_id) {
936 : : dup = true;
937 : : break;
938 : : }
939 : : }
940 [ # # ]: 0 : if (!dup)
941 : 0 : seen[used++] = pp_id;
942 : : }
943 : 0 : mlx5_free(seen);
944 : 0 : info->port_used = used;
945 : 0 : return 0;
946 : : }
|