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