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