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