Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2015 6WIND S.A.
3 : : * Copyright 2015 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #include <stddef.h>
7 : : #include <errno.h>
8 : : #include <string.h>
9 : : #include <stdint.h>
10 : : #include <unistd.h>
11 : : #include <inttypes.h>
12 : :
13 : : #include <eal_export.h>
14 : : #include <rte_mbuf.h>
15 : : #include <rte_malloc.h>
16 : : #include <ethdev_driver.h>
17 : : #include <bus_pci_driver.h>
18 : : #include <rte_common.h>
19 : : #include <rte_eal_paging.h>
20 : : #include <rte_bitops.h>
21 : :
22 : : #include <mlx5_common.h>
23 : : #include <mlx5_common_mr.h>
24 : : #include <mlx5_malloc.h>
25 : :
26 : : #include "mlx5_defs.h"
27 : : #include "mlx5_utils.h"
28 : : #include "mlx5.h"
29 : : #include "mlx5_tx.h"
30 : : #include "mlx5_rxtx.h"
31 : : #include "mlx5_autoconf.h"
32 : : #include "mlx5_devx.h"
33 : : #include "rte_pmd_mlx5.h"
34 : : #include "mlx5_flow.h"
35 : :
36 : : /**
37 : : * Allocate TX queue elements.
38 : : *
39 : : * @param txq_ctrl
40 : : * Pointer to TX queue structure.
41 : : */
42 : : void
43 : 0 : txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl)
44 : : {
45 : 0 : const unsigned int elts_n = 1 << txq_ctrl->txq.elts_n;
46 : : unsigned int i;
47 : :
48 [ # # ]: 0 : for (i = 0; (i != elts_n); ++i)
49 : 0 : txq_ctrl->txq.elts[i] = NULL;
50 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %u allocated and configured %u WRs",
51 : : PORT_ID(txq_ctrl->priv), txq_ctrl->txq.idx, elts_n);
52 : 0 : txq_ctrl->txq.elts_head = 0;
53 : 0 : txq_ctrl->txq.elts_tail = 0;
54 : 0 : txq_ctrl->txq.elts_comp = 0;
55 : 0 : }
56 : :
57 : : /**
58 : : * Free TX queue elements.
59 : : *
60 : : * @param txq_ctrl
61 : : * Pointer to TX queue structure.
62 : : */
63 : : void
64 : 0 : txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl)
65 : : {
66 : 0 : const uint16_t elts_n = 1 << txq_ctrl->txq.elts_n;
67 : 0 : const uint16_t elts_m = elts_n - 1;
68 : 0 : uint16_t elts_head = txq_ctrl->txq.elts_head;
69 : 0 : uint16_t elts_tail = txq_ctrl->txq.elts_tail;
70 : : struct rte_mbuf *(*elts)[] = &txq_ctrl->txq.elts;
71 : :
72 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %u freeing WRs",
73 : : PORT_ID(txq_ctrl->priv), txq_ctrl->txq.idx);
74 : 0 : txq_ctrl->txq.elts_head = 0;
75 : 0 : txq_ctrl->txq.elts_tail = 0;
76 : 0 : txq_ctrl->txq.elts_comp = 0;
77 : :
78 [ # # ]: 0 : while (elts_tail != elts_head) {
79 [ # # ]: 0 : struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
80 : :
81 : : MLX5_ASSERT(elt != NULL);
82 : : rte_pktmbuf_free_seg(elt);
83 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
84 : : /* Poisoning. */
85 : : memset(&(*elts)[elts_tail & elts_m],
86 : : 0x77,
87 : : sizeof((*elts)[elts_tail & elts_m]));
88 : : #endif
89 : 0 : ++elts_tail;
90 : : }
91 : 0 : }
92 : :
93 : : /**
94 : : * Returns the per-port supported offloads.
95 : : *
96 : : * @param dev
97 : : * Pointer to Ethernet device.
98 : : *
99 : : * @return
100 : : * Supported Tx offloads.
101 : : */
102 : : uint64_t
103 : 0 : mlx5_get_tx_port_offloads(struct rte_eth_dev *dev)
104 : : {
105 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
106 : : uint64_t offloads = (RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
107 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT);
108 : : struct mlx5_port_config *config = &priv->config;
109 : 0 : struct mlx5_dev_cap *dev_cap = &priv->sh->dev_cap;
110 : :
111 [ # # ]: 0 : if (dev_cap->hw_csum)
112 : : offloads |= (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
113 : : RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
114 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM);
115 [ # # ]: 0 : if (dev_cap->tso)
116 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
117 [ # # ]: 0 : if (priv->sh->config.tx_pp ||
118 [ # # ]: 0 : priv->sh->cdev->config.hca_attr.wait_on_time)
119 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP;
120 [ # # ]: 0 : if (dev_cap->swp) {
121 [ # # ]: 0 : if (dev_cap->swp & MLX5_SW_PARSING_CSUM_CAP)
122 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM;
123 [ # # ]: 0 : if (dev_cap->swp & MLX5_SW_PARSING_TSO_CAP)
124 : 0 : offloads |= (RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
125 : : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO);
126 : : }
127 [ # # ]: 0 : if (dev_cap->tunnel_en) {
128 [ # # ]: 0 : if (dev_cap->hw_csum)
129 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM;
130 [ # # ]: 0 : if (dev_cap->tso) {
131 [ # # ]: 0 : if (dev_cap->tunnel_en &
132 : : MLX5_TUNNELED_OFFLOADS_VXLAN_CAP)
133 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO;
134 [ # # ]: 0 : if (dev_cap->tunnel_en &
135 : : MLX5_TUNNELED_OFFLOADS_GRE_CAP)
136 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO;
137 [ # # ]: 0 : if (dev_cap->tunnel_en &
138 : : MLX5_TUNNELED_OFFLOADS_GENEVE_CAP)
139 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
140 : : }
141 : : }
142 [ # # ]: 0 : if (!config->mprq.enabled)
143 : 0 : offloads |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
144 : 0 : return offloads;
145 : : }
146 : :
147 : : /* Fetches and drops all SW-owned and error CQEs to synchronize CQ. */
148 : : static void
149 : 0 : txq_sync_cq(struct mlx5_txq_data *txq)
150 : : {
151 : : volatile struct mlx5_cqe *cqe;
152 : : int ret, i;
153 : :
154 : 0 : i = txq->cqe_s;
155 : : do {
156 : 0 : cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
157 [ # # ]: 0 : ret = check_cqe(cqe, txq->cqe_s, txq->cq_ci);
158 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
159 [ # # ]: 0 : if (likely(ret != MLX5_CQE_STATUS_ERR)) {
160 : : /* No new CQEs in completion queue. */
161 : : MLX5_ASSERT(ret == MLX5_CQE_STATUS_HW_OWN);
162 : : break;
163 : : }
164 : : }
165 : 0 : ++txq->cq_ci;
166 [ # # ]: 0 : } while (--i);
167 : : /* Move all CQEs to HW ownership. */
168 [ # # ]: 0 : for (i = 0; i < txq->cqe_s; i++) {
169 : 0 : cqe = &txq->cqes[i];
170 : 0 : cqe->op_own = MLX5_CQE_INVALIDATE;
171 : : }
172 : : /* Resync CQE and WQE (WQ in reset state). */
173 : 0 : rte_io_wmb();
174 [ # # ]: 0 : *txq->cq_db = rte_cpu_to_be_32(txq->cq_ci);
175 : 0 : txq->cq_pi = txq->cq_ci;
176 : 0 : rte_io_wmb();
177 : 0 : }
178 : :
179 : : /**
180 : : * Tx queue stop. Device queue goes to the idle state,
181 : : * all involved mbufs are freed from elts/WQ.
182 : : *
183 : : * @param dev
184 : : * Pointer to Ethernet device structure.
185 : : * @param idx
186 : : * Tx queue index.
187 : : *
188 : : * @return
189 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
190 : : */
191 : : int
192 : 0 : mlx5_tx_queue_stop_primary(struct rte_eth_dev *dev, uint16_t idx)
193 : : {
194 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
195 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[idx];
196 : : struct mlx5_txq_ctrl *txq_ctrl =
197 : 0 : container_of(txq, struct mlx5_txq_ctrl, txq);
198 : : int ret;
199 : :
200 : : MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
201 : : /* Move QP to RESET state. */
202 : 0 : ret = priv->obj_ops.txq_obj_modify(txq_ctrl->obj, MLX5_TXQ_MOD_RDY2RST,
203 : 0 : (uint8_t)priv->dev_port);
204 [ # # ]: 0 : if (ret)
205 : : return ret;
206 : : /* Handle all send completions. */
207 : 0 : txq_sync_cq(txq);
208 : : /* Free elts stored in the SQ. */
209 : 0 : txq_free_elts(txq_ctrl);
210 : : /* Prevent writing new pkts to SQ by setting no free WQE.*/
211 : 0 : txq->wqe_ci = txq->wqe_s;
212 : 0 : txq->wqe_pi = 0;
213 : 0 : txq->elts_comp = 0;
214 : : /* Set the actual queue state. */
215 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STOPPED;
216 : 0 : return 0;
217 : : }
218 : :
219 : : /**
220 : : * Tx queue stop. Device queue goes to the idle state,
221 : : * all involved mbufs are freed from elts/WQ.
222 : : *
223 : : * @param dev
224 : : * Pointer to Ethernet device structure.
225 : : * @param idx
226 : : * Tx queue index.
227 : : *
228 : : * @return
229 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
230 : : */
231 : : int
232 : 0 : mlx5_tx_queue_stop(struct rte_eth_dev *dev, uint16_t idx)
233 : : {
234 : : int ret;
235 : :
236 [ # # ]: 0 : if (rte_eth_dev_is_tx_hairpin_queue(dev, idx)) {
237 : 0 : DRV_LOG(ERR, "Hairpin queue can't be stopped");
238 : 0 : rte_errno = EINVAL;
239 : 0 : return -EINVAL;
240 : : }
241 [ # # ]: 0 : if (dev->data->tx_queue_state[idx] == RTE_ETH_QUEUE_STATE_STOPPED)
242 : : return 0;
243 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
244 : 0 : ret = mlx5_mp_os_req_queue_control(dev, idx,
245 : : MLX5_MP_REQ_QUEUE_TX_STOP);
246 : : } else {
247 : 0 : ret = mlx5_tx_queue_stop_primary(dev, idx);
248 : : }
249 : : return ret;
250 : : }
251 : :
252 : : /**
253 : : * Rx queue start. Device queue goes to the ready state,
254 : : * all required mbufs are allocated and WQ is replenished.
255 : : *
256 : : * @param dev
257 : : * Pointer to Ethernet device structure.
258 : : * @param idx
259 : : * RX queue index.
260 : : *
261 : : * @return
262 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
263 : : */
264 : : int
265 : 0 : mlx5_tx_queue_start_primary(struct rte_eth_dev *dev, uint16_t idx)
266 : : {
267 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
268 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[idx];
269 : : struct mlx5_txq_ctrl *txq_ctrl =
270 : 0 : container_of(txq, struct mlx5_txq_ctrl, txq);
271 : : int ret;
272 : :
273 : : MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
274 : 0 : ret = priv->obj_ops.txq_obj_modify(txq_ctrl->obj,
275 : : MLX5_TXQ_MOD_RST2RDY,
276 : 0 : (uint8_t)priv->dev_port);
277 [ # # ]: 0 : if (ret)
278 : : return ret;
279 : 0 : txq_ctrl->txq.wqe_ci = 0;
280 : 0 : txq_ctrl->txq.wqe_pi = 0;
281 : 0 : txq_ctrl->txq.elts_comp = 0;
282 : : /* Set the actual queue state. */
283 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
284 : 0 : return 0;
285 : : }
286 : :
287 : : /**
288 : : * Rx queue start. Device queue goes to the ready state,
289 : : * all required mbufs are allocated and WQ is replenished.
290 : : *
291 : : * @param dev
292 : : * Pointer to Ethernet device structure.
293 : : * @param idx
294 : : * RX queue index.
295 : : *
296 : : * @return
297 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
298 : : */
299 : : int
300 : 0 : mlx5_tx_queue_start(struct rte_eth_dev *dev, uint16_t idx)
301 : : {
302 : : int ret;
303 : :
304 [ # # ]: 0 : if (rte_eth_dev_is_tx_hairpin_queue(dev, idx)) {
305 : 0 : DRV_LOG(ERR, "Hairpin queue can't be started");
306 : 0 : rte_errno = EINVAL;
307 : 0 : return -EINVAL;
308 : : }
309 [ # # ]: 0 : if (dev->data->tx_queue_state[idx] == RTE_ETH_QUEUE_STATE_STARTED)
310 : : return 0;
311 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
312 : 0 : ret = mlx5_mp_os_req_queue_control(dev, idx,
313 : : MLX5_MP_REQ_QUEUE_TX_START);
314 : : } else {
315 : 0 : ret = mlx5_tx_queue_start_primary(dev, idx);
316 : : }
317 : : return ret;
318 : : }
319 : :
320 : : /**
321 : : * Tx queue presetup checks.
322 : : *
323 : : * @param dev
324 : : * Pointer to Ethernet device structure.
325 : : * @param idx
326 : : * Tx queue index.
327 : : * @param desc
328 : : * Number of descriptors to configure in queue.
329 : : *
330 : : * @return
331 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
332 : : */
333 : : static int
334 : 0 : mlx5_tx_queue_pre_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t *desc)
335 : : {
336 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
337 : :
338 [ # # ]: 0 : if (*desc > mlx5_dev_get_max_wq_size(priv->sh)) {
339 : 0 : DRV_LOG(ERR,
340 : : "port %u number of descriptors requested for Tx queue"
341 : : " %u is more than supported",
342 : : dev->data->port_id, idx);
343 : 0 : rte_errno = EINVAL;
344 : 0 : return -EINVAL;
345 : : }
346 [ # # ]: 0 : if (*desc <= MLX5_TX_COMP_THRESH) {
347 : 0 : DRV_LOG(WARNING,
348 : : "port %u number of descriptors requested for Tx queue"
349 : : " %u must be higher than MLX5_TX_COMP_THRESH, using %u"
350 : : " instead of %u", dev->data->port_id, idx,
351 : : MLX5_TX_COMP_THRESH + 1, *desc);
352 : 0 : *desc = MLX5_TX_COMP_THRESH + 1;
353 : : }
354 [ # # ]: 0 : if (!rte_is_power_of_2(*desc)) {
355 : 0 : *desc = 1 << log2above(*desc);
356 : 0 : DRV_LOG(WARNING,
357 : : "port %u increased number of descriptors in Tx queue"
358 : : " %u to the next power of two (%d)",
359 : : dev->data->port_id, idx, *desc);
360 : : }
361 : 0 : DRV_LOG(DEBUG, "port %u configuring queue %u for %u descriptors",
362 : : dev->data->port_id, idx, *desc);
363 [ # # ]: 0 : if (idx >= priv->txqs_n) {
364 : 0 : DRV_LOG(ERR, "port %u Tx queue index out of range (%u >= %u)",
365 : : dev->data->port_id, idx, priv->txqs_n);
366 : 0 : rte_errno = EOVERFLOW;
367 : 0 : return -rte_errno;
368 : : }
369 [ # # ]: 0 : if (!mlx5_txq_releasable(dev, idx)) {
370 : 0 : rte_errno = EBUSY;
371 : 0 : DRV_LOG(ERR, "port %u unable to release queue index %u",
372 : : dev->data->port_id, idx);
373 : 0 : return -rte_errno;
374 : : }
375 : 0 : mlx5_txq_release(dev, idx);
376 : 0 : return 0;
377 : : }
378 : :
379 : : /**
380 : : * DPDK callback to configure a TX queue.
381 : : *
382 : : * @param dev
383 : : * Pointer to Ethernet device structure.
384 : : * @param idx
385 : : * TX queue index.
386 : : * @param desc
387 : : * Number of descriptors to configure in queue.
388 : : * @param socket
389 : : * NUMA socket on which memory must be allocated.
390 : : * @param[in] conf
391 : : * Thresholds parameters.
392 : : *
393 : : * @return
394 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
395 : : */
396 : : int
397 : 0 : mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
398 : : unsigned int socket, const struct rte_eth_txconf *conf)
399 : : {
400 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
401 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[idx];
402 : : struct mlx5_txq_ctrl *txq_ctrl =
403 : : container_of(txq, struct mlx5_txq_ctrl, txq);
404 : : int res;
405 : :
406 : 0 : res = mlx5_tx_queue_pre_setup(dev, idx, &desc);
407 [ # # ]: 0 : if (res)
408 : : return res;
409 : 0 : txq_ctrl = mlx5_txq_new(dev, idx, desc, socket, conf);
410 [ # # ]: 0 : if (!txq_ctrl) {
411 : 0 : DRV_LOG(ERR, "port %u unable to allocate queue index %u",
412 : : dev->data->port_id, idx);
413 : 0 : return -rte_errno;
414 : : }
415 : 0 : DRV_LOG(DEBUG, "port %u adding Tx queue %u to list",
416 : : dev->data->port_id, idx);
417 : 0 : (*priv->txqs)[idx] = &txq_ctrl->txq;
418 : 0 : return 0;
419 : : }
420 : :
421 : : /**
422 : : * DPDK callback to configure a TX hairpin queue.
423 : : *
424 : : * @param dev
425 : : * Pointer to Ethernet device structure.
426 : : * @param idx
427 : : * TX queue index.
428 : : * @param desc
429 : : * Number of descriptors to configure in queue.
430 : : * @param[in] hairpin_conf
431 : : * The hairpin binding configuration.
432 : : *
433 : : * @return
434 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
435 : : */
436 : : int
437 : 0 : mlx5_tx_hairpin_queue_setup(struct rte_eth_dev *dev, uint16_t idx,
438 : : uint16_t desc,
439 : : const struct rte_eth_hairpin_conf *hairpin_conf)
440 : : {
441 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
442 : 0 : struct mlx5_txq_data *txq = (*priv->txqs)[idx];
443 : : struct mlx5_txq_ctrl *txq_ctrl =
444 : : container_of(txq, struct mlx5_txq_ctrl, txq);
445 : : int res;
446 : :
447 : 0 : res = mlx5_tx_queue_pre_setup(dev, idx, &desc);
448 [ # # ]: 0 : if (res)
449 : : return res;
450 [ # # ]: 0 : if (hairpin_conf->peer_count != 1) {
451 : 0 : rte_errno = EINVAL;
452 : 0 : DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue index %u"
453 : : " peer count is %u", dev->data->port_id,
454 : : idx, hairpin_conf->peer_count);
455 : 0 : return -rte_errno;
456 : : }
457 [ # # ]: 0 : if (hairpin_conf->peers[0].port == dev->data->port_id) {
458 [ # # ]: 0 : if (hairpin_conf->peers[0].queue >= priv->rxqs_n) {
459 : 0 : rte_errno = EINVAL;
460 : 0 : DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue"
461 : : " index %u, Rx %u is larger than %u",
462 : : dev->data->port_id, idx,
463 : : hairpin_conf->peers[0].queue, priv->txqs_n);
464 : 0 : return -rte_errno;
465 : : }
466 : : } else {
467 [ # # ]: 0 : if (hairpin_conf->manual_bind == 0 ||
468 : : hairpin_conf->tx_explicit == 0) {
469 : 0 : rte_errno = EINVAL;
470 : 0 : DRV_LOG(ERR, "port %u unable to setup Tx hairpin queue"
471 : : " index %u peer port %u with attributes %u %u",
472 : : dev->data->port_id, idx,
473 : : hairpin_conf->peers[0].port,
474 : : hairpin_conf->manual_bind,
475 : : hairpin_conf->tx_explicit);
476 : 0 : return -rte_errno;
477 : : }
478 : : }
479 : 0 : txq_ctrl = mlx5_txq_hairpin_new(dev, idx, desc, hairpin_conf);
480 [ # # ]: 0 : if (!txq_ctrl) {
481 : 0 : DRV_LOG(ERR, "port %u unable to allocate queue index %u",
482 : : dev->data->port_id, idx);
483 : 0 : return -rte_errno;
484 : : }
485 : 0 : DRV_LOG(DEBUG, "port %u adding Tx queue %u to list",
486 : : dev->data->port_id, idx);
487 : 0 : (*priv->txqs)[idx] = &txq_ctrl->txq;
488 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_HAIRPIN;
489 : 0 : return 0;
490 : : }
491 : :
492 : : /**
493 : : * DPDK callback to release a TX queue.
494 : : *
495 : : * @param dev
496 : : * Pointer to Ethernet device structure.
497 : : * @param qid
498 : : * Transmit queue index.
499 : : */
500 : : void
501 : 0 : mlx5_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
502 : : {
503 : 0 : struct mlx5_txq_data *txq = dev->data->tx_queues[qid];
504 : :
505 [ # # ]: 0 : if (txq == NULL)
506 : : return;
507 : 0 : DRV_LOG(DEBUG, "port %u removing Tx queue %u from list",
508 : : dev->data->port_id, qid);
509 : 0 : mlx5_txq_release(dev, qid);
510 : : }
511 : :
512 : : /**
513 : : * Remap UAR register of a Tx queue for secondary process.
514 : : *
515 : : * Remapped address is stored at the table in the process private structure of
516 : : * the device, indexed by queue index.
517 : : *
518 : : * @param txq_ctrl
519 : : * Pointer to Tx queue control structure.
520 : : * @param fd
521 : : * Verbs file descriptor to map UAR pages.
522 : : *
523 : : * @return
524 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
525 : : */
526 : : static int
527 : 0 : txq_uar_init_secondary(struct mlx5_txq_ctrl *txq_ctrl, int fd)
528 : : {
529 : 0 : struct mlx5_priv *priv = txq_ctrl->priv;
530 : 0 : struct mlx5_proc_priv *ppriv = MLX5_PROC_PRIV(PORT_ID(priv));
531 : 0 : struct mlx5_proc_priv *primary_ppriv = priv->sh->pppriv;
532 : : struct mlx5_txq_data *txq = &txq_ctrl->txq;
533 : : void *addr;
534 : : uintptr_t uar_va;
535 : : uintptr_t offset;
536 : 0 : const size_t page_size = rte_mem_page_size();
537 [ # # ]: 0 : if (page_size == (size_t)-1) {
538 : 0 : DRV_LOG(ERR, "Failed to get mem page size");
539 : 0 : rte_errno = ENOMEM;
540 : 0 : return -rte_errno;
541 : : }
542 : :
543 [ # # ]: 0 : if (txq_ctrl->is_hairpin)
544 : : return 0;
545 : : MLX5_ASSERT(ppriv);
546 : : /*
547 : : * As rdma-core, UARs are mapped in size of OS page
548 : : * size. Ref to libmlx5 function: mlx5_init_context()
549 : : */
550 : 0 : uar_va = (uintptr_t)primary_ppriv->uar_table[txq->idx].db;
551 : 0 : offset = uar_va & (page_size - 1); /* Offset in page. */
552 : 0 : addr = rte_mem_map(NULL, page_size, RTE_PROT_WRITE, RTE_MAP_SHARED,
553 : 0 : fd, txq_ctrl->uar_mmap_offset);
554 [ # # ]: 0 : if (!addr) {
555 : 0 : DRV_LOG(ERR, "Port %u mmap failed for BF reg of txq %u.",
556 : : txq->port_id, txq->idx);
557 : 0 : rte_errno = ENXIO;
558 : 0 : return -rte_errno;
559 : : }
560 : 0 : addr = RTE_PTR_ADD(addr, offset);
561 : 0 : ppriv->uar_table[txq->idx].db = addr;
562 : : #ifndef RTE_ARCH_64
563 : : ppriv->uar_table[txq->idx].sl_p =
564 : : primary_ppriv->uar_table[txq->idx].sl_p;
565 : : #endif
566 : 0 : return 0;
567 : : }
568 : :
569 : : /**
570 : : * Unmap UAR register of a Tx queue for secondary process.
571 : : *
572 : : * @param txq_ctrl
573 : : * Pointer to Tx queue control structure.
574 : : */
575 : : static void
576 : 0 : txq_uar_uninit_secondary(struct mlx5_txq_ctrl *txq_ctrl)
577 : : {
578 : 0 : struct mlx5_proc_priv *ppriv = MLX5_PROC_PRIV(PORT_ID(txq_ctrl->priv));
579 : : void *addr;
580 : 0 : const size_t page_size = rte_mem_page_size();
581 [ # # ]: 0 : if (page_size == (size_t)-1) {
582 : 0 : DRV_LOG(ERR, "Failed to get mem page size");
583 : 0 : rte_errno = ENOMEM;
584 : : }
585 : :
586 [ # # ]: 0 : if (txq_ctrl->is_hairpin)
587 : : return;
588 : 0 : addr = ppriv->uar_table[txq_ctrl->txq.idx].db;
589 : 0 : rte_mem_unmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
590 : : }
591 : :
592 : : /**
593 : : * Deinitialize Tx UAR registers for secondary process.
594 : : *
595 : : * @param dev
596 : : * Pointer to Ethernet device.
597 : : */
598 : : void
599 : 0 : mlx5_tx_uar_uninit_secondary(struct rte_eth_dev *dev)
600 : : {
601 : 0 : struct mlx5_proc_priv *ppriv = (struct mlx5_proc_priv *)
602 : : dev->process_private;
603 : 0 : const size_t page_size = rte_mem_page_size();
604 : : void *addr;
605 : : unsigned int i;
606 : :
607 [ # # ]: 0 : if (page_size == (size_t)-1) {
608 : 0 : DRV_LOG(ERR, "Failed to get mem page size");
609 : 0 : return;
610 : : }
611 : : MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
612 [ # # ]: 0 : for (i = 0; i != ppriv->uar_table_sz; ++i) {
613 [ # # ]: 0 : if (!ppriv->uar_table[i].db)
614 : 0 : continue;
615 : : addr = ppriv->uar_table[i].db;
616 : 0 : rte_mem_unmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
617 : :
618 : : }
619 : : }
620 : :
621 : : /**
622 : : * Initialize Tx UAR registers for secondary process.
623 : : *
624 : : * @param dev
625 : : * Pointer to Ethernet device.
626 : : * @param fd
627 : : * Verbs file descriptor to map UAR pages.
628 : : *
629 : : * @return
630 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
631 : : */
632 : : int
633 : 0 : mlx5_tx_uar_init_secondary(struct rte_eth_dev *dev, int fd)
634 : : {
635 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
636 : : struct mlx5_txq_data *txq;
637 : : struct mlx5_txq_ctrl *txq_ctrl;
638 : : unsigned int i;
639 : : int ret;
640 : :
641 : : MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
642 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
643 [ # # ]: 0 : if (!(*priv->txqs)[i])
644 : 0 : continue;
645 : : txq = (*priv->txqs)[i];
646 : 0 : txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
647 [ # # ]: 0 : if (txq_ctrl->is_hairpin)
648 : 0 : continue;
649 : : MLX5_ASSERT(txq->idx == (uint16_t)i);
650 : 0 : ret = txq_uar_init_secondary(txq_ctrl, fd);
651 [ # # ]: 0 : if (ret)
652 : 0 : goto error;
653 : : }
654 : : return 0;
655 : : error:
656 : : /* Rollback. */
657 : : do {
658 [ # # ]: 0 : if (!(*priv->txqs)[i])
659 : 0 : continue;
660 : : txq = (*priv->txqs)[i];
661 : 0 : txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
662 : 0 : txq_uar_uninit_secondary(txq_ctrl);
663 [ # # ]: 0 : } while (i--);
664 : 0 : return -rte_errno;
665 : : }
666 : :
667 : : /**
668 : : * Verify the Verbs Tx queue list is empty
669 : : *
670 : : * @param dev
671 : : * Pointer to Ethernet device.
672 : : *
673 : : * @return
674 : : * The number of object not released.
675 : : */
676 : : int
677 : 0 : mlx5_txq_obj_verify(struct rte_eth_dev *dev)
678 : : {
679 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
680 : : int ret = 0;
681 : : struct mlx5_txq_obj *txq_obj;
682 : :
683 [ # # ]: 0 : LIST_FOREACH(txq_obj, &priv->txqsobj, next) {
684 : 0 : DRV_LOG(DEBUG, "port %u Verbs Tx queue %u still referenced",
685 : : dev->data->port_id, txq_obj->txq_ctrl->txq.idx);
686 : 0 : ++ret;
687 : : }
688 : 0 : return ret;
689 : : }
690 : :
691 : : /**
692 : : * Calculate the total number of WQEBB for Tx queue.
693 : : *
694 : : * Simplified version of calc_sq_size() in rdma-core.
695 : : *
696 : : * @param txq_ctrl
697 : : * Pointer to Tx queue control structure.
698 : : * @param devx
699 : : * If the calculation is used for Devx queue.
700 : : *
701 : : * @return
702 : : * The number of WQEBB.
703 : : */
704 : : static int
705 : 0 : txq_calc_wqebb_cnt(struct mlx5_txq_ctrl *txq_ctrl, bool devx)
706 : : {
707 : : unsigned int wqe_size;
708 : 0 : const unsigned int desc = 1 << txq_ctrl->txq.elts_n;
709 : :
710 [ # # ]: 0 : if (devx) {
711 : 0 : wqe_size = txq_ctrl->txq.tso_en ?
712 [ # # ]: 0 : RTE_ALIGN(txq_ctrl->max_tso_header, MLX5_WSEG_SIZE) : 0;
713 : 0 : wqe_size += MLX5_WQE_CSEG_SIZE +
714 : : MLX5_WQE_ESEG_SIZE +
715 : : MLX5_WQE_DSEG_SIZE;
716 [ # # ]: 0 : if (txq_ctrl->txq.inlen_send)
717 : 0 : wqe_size = RTE_MAX(wqe_size, sizeof(struct mlx5_wqe_cseg) +
718 : : sizeof(struct mlx5_wqe_eseg) +
719 : : RTE_ALIGN(txq_ctrl->txq.inlen_send +
720 : : sizeof(uint32_t),
721 : : MLX5_WSEG_SIZE));
722 : 0 : wqe_size = RTE_ALIGN(wqe_size, MLX5_WQE_SIZE);
723 : : } else {
724 : 0 : wqe_size = MLX5_WQE_CSEG_SIZE +
725 : : MLX5_WQE_ESEG_SIZE +
726 : : MLX5_WSEG_SIZE -
727 : : MLX5_ESEG_MIN_INLINE_SIZE +
728 : 0 : txq_ctrl->max_inline_data;
729 : 0 : wqe_size = RTE_MAX(wqe_size, MLX5_WQE_SIZE);
730 : : }
731 : 0 : return rte_align32pow2(wqe_size * desc) / MLX5_WQE_SIZE;
732 : : }
733 : :
734 : : /**
735 : : * Calculate the maximal inline data size for Tx queue.
736 : : *
737 : : * @param txq_ctrl
738 : : * Pointer to Tx queue control structure.
739 : : *
740 : : * @return
741 : : * The maximal inline data size.
742 : : */
743 : : static unsigned int
744 : : txq_calc_inline_max(struct mlx5_txq_ctrl *txq_ctrl)
745 : : {
746 : 0 : const unsigned int desc = 1 << txq_ctrl->txq.elts_n;
747 : : struct mlx5_priv *priv = txq_ctrl->priv;
748 : : unsigned int wqe_size;
749 : :
750 : 0 : wqe_size = mlx5_dev_get_max_wq_size(priv->sh) / desc;
751 [ # # ]: 0 : if (!wqe_size)
752 : : return 0;
753 : : /*
754 : : * This calculation is derived from the source of
755 : : * mlx5_calc_send_wqe() in rdma_core library.
756 : : */
757 : 0 : wqe_size = wqe_size * MLX5_WQE_SIZE -
758 : : MLX5_WQE_CSEG_SIZE -
759 : : MLX5_WQE_ESEG_SIZE -
760 : : MLX5_WSEG_SIZE -
761 : : MLX5_WSEG_SIZE +
762 : : MLX5_ESEG_MIN_INLINE_SIZE;
763 : 0 : return wqe_size;
764 : : }
765 : :
766 : : /**
767 : : * Set Tx queue parameters from device configuration.
768 : : *
769 : : * @param txq_ctrl
770 : : * Pointer to Tx queue control structure.
771 : : */
772 : : static void
773 : 0 : txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
774 : : {
775 : 0 : struct mlx5_priv *priv = txq_ctrl->priv;
776 : : struct mlx5_port_config *config = &priv->config;
777 : 0 : struct mlx5_dev_cap *dev_cap = &priv->sh->dev_cap;
778 : : unsigned int inlen_send; /* Inline data for ordinary SEND.*/
779 : : unsigned int inlen_empw; /* Inline data for enhanced MPW. */
780 : : unsigned int inlen_mode; /* Minimal required Inline data. */
781 : : unsigned int txqs_inline; /* Min Tx queues to enable inline. */
782 : 0 : uint64_t dev_txoff = priv->dev_data->dev_conf.txmode.offloads;
783 : 0 : bool tso = txq_ctrl->txq.offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
784 : : RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
785 : : RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
786 : : RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
787 : : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO);
788 : : bool vlan_inline;
789 : : unsigned int temp;
790 : :
791 : 0 : txq_ctrl->txq.fast_free =
792 [ # # ]: 0 : !!((txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) &&
793 : : !(txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS) &&
794 [ # # ]: 0 : !config->mprq.enabled);
795 [ # # ]: 0 : if (config->txqs_inline == MLX5_ARG_UNSET)
796 : : txqs_inline =
797 : : #if defined(RTE_ARCH_ARM64)
798 : : (priv->pci_dev && priv->pci_dev->id.device_id ==
799 : : PCI_DEVICE_ID_MELLANOX_BLUEFIELD) ?
800 : : MLX5_INLINE_MAX_TXQS_BLUEFIELD :
801 : : #endif
802 : : MLX5_INLINE_MAX_TXQS;
803 : : else
804 : : txqs_inline = (unsigned int)config->txqs_inline;
805 [ # # ]: 0 : inlen_send = (config->txq_inline_max == MLX5_ARG_UNSET) ?
806 : : MLX5_SEND_DEF_INLINE_LEN :
807 : : (unsigned int)config->txq_inline_max;
808 [ # # ]: 0 : inlen_empw = (config->txq_inline_mpw == MLX5_ARG_UNSET) ?
809 : : MLX5_EMPW_DEF_INLINE_LEN :
810 : : (unsigned int)config->txq_inline_mpw;
811 : 0 : inlen_mode = (config->txq_inline_min == MLX5_ARG_UNSET) ?
812 [ # # ]: 0 : 0 : (unsigned int)config->txq_inline_min;
813 [ # # ]: 0 : if (config->mps != MLX5_MPW_ENHANCED && config->mps != MLX5_MPW)
814 : : inlen_empw = 0;
815 : : /*
816 : : * If there is requested minimal amount of data to inline
817 : : * we MUST enable inlining. This is a case for ConnectX-4
818 : : * which usually requires L2 inlined for correct operating
819 : : * and ConnectX-4 Lx which requires L2-L4 inlined to
820 : : * support E-Switch Flows.
821 : : */
822 [ # # ]: 0 : if (inlen_mode) {
823 [ # # ]: 0 : if (inlen_mode <= MLX5_ESEG_MIN_INLINE_SIZE) {
824 : : /*
825 : : * Optimize minimal inlining for single
826 : : * segment packets to fill one WQEBB
827 : : * without gaps.
828 : : */
829 : : temp = MLX5_ESEG_MIN_INLINE_SIZE;
830 : : } else {
831 : : temp = inlen_mode - MLX5_ESEG_MIN_INLINE_SIZE;
832 : 0 : temp = RTE_ALIGN(temp, MLX5_WSEG_SIZE) +
833 : : MLX5_ESEG_MIN_INLINE_SIZE;
834 : 0 : temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
835 : : }
836 [ # # ]: 0 : if (temp != inlen_mode) {
837 : 0 : DRV_LOG(INFO,
838 : : "port %u minimal required inline setting"
839 : : " aligned from %u to %u",
840 : : PORT_ID(priv), inlen_mode, temp);
841 : : inlen_mode = temp;
842 : : }
843 : : }
844 : : /*
845 : : * If port is configured to support VLAN insertion and device
846 : : * does not support this feature by HW (for NICs before ConnectX-5
847 : : * or in case of wqe_vlan_insert flag is not set) we must enable
848 : : * data inline on all queues because it is supported by single
849 : : * tx_burst routine.
850 : : */
851 : 0 : txq_ctrl->txq.vlan_en = config->hw_vlan_insert;
852 [ # # ]: 0 : vlan_inline = (dev_txoff & RTE_ETH_TX_OFFLOAD_VLAN_INSERT) &&
853 [ # # ]: 0 : !config->hw_vlan_insert;
854 : : /*
855 : : * If there are few Tx queues it is prioritized
856 : : * to save CPU cycles and disable data inlining at all.
857 : : */
858 [ # # # # ]: 0 : if (inlen_send && priv->txqs_n >= txqs_inline) {
859 : : /*
860 : : * The data sent with ordinal MLX5_OPCODE_SEND
861 : : * may be inlined in Ethernet Segment, align the
862 : : * length accordingly to fit entire WQEBBs.
863 : : */
864 : 0 : temp = RTE_MAX(inlen_send,
865 : : MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE);
866 : : temp -= MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE;
867 : 0 : temp = RTE_ALIGN(temp, MLX5_WQE_SIZE);
868 : 0 : temp += MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE;
869 : 0 : temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
870 : : MLX5_ESEG_MIN_INLINE_SIZE -
871 : : MLX5_WQE_CSEG_SIZE -
872 : : MLX5_WQE_ESEG_SIZE -
873 : : MLX5_WQE_DSEG_SIZE * 2);
874 : 0 : temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
875 : 0 : temp = RTE_MAX(temp, inlen_mode);
876 [ # # ]: 0 : if (temp != inlen_send) {
877 : 0 : DRV_LOG(INFO,
878 : : "port %u ordinary send inline setting"
879 : : " aligned from %u to %u",
880 : : PORT_ID(priv), inlen_send, temp);
881 : : inlen_send = temp;
882 : : }
883 : : /*
884 : : * Not aligned to cache lines, but to WQEs.
885 : : * First bytes of data (initial alignment)
886 : : * is going to be copied explicitly at the
887 : : * beginning of inlining buffer in Ethernet
888 : : * Segment.
889 : : */
890 : : MLX5_ASSERT(inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE);
891 : : MLX5_ASSERT(inlen_send <= MLX5_WQE_SIZE_MAX +
892 : : MLX5_ESEG_MIN_INLINE_SIZE -
893 : : MLX5_WQE_CSEG_SIZE -
894 : : MLX5_WQE_ESEG_SIZE -
895 : : MLX5_WQE_DSEG_SIZE * 2);
896 [ # # ]: 0 : } else if (inlen_mode) {
897 : : /*
898 : : * If minimal inlining is requested we must
899 : : * enable inlining in general, despite the
900 : : * number of configured queues. Ignore the
901 : : * txq_inline_max devarg, this is not
902 : : * full-featured inline.
903 : : */
904 : : inlen_send = inlen_mode;
905 : : inlen_empw = 0;
906 [ # # ]: 0 : } else if (vlan_inline) {
907 : : /*
908 : : * Hardware does not report offload for
909 : : * VLAN insertion, we must enable data inline
910 : : * to implement feature by software.
911 : : */
912 : : inlen_send = MLX5_ESEG_MIN_INLINE_SIZE;
913 : : inlen_empw = 0;
914 : : } else {
915 : : inlen_send = 0;
916 : : inlen_empw = 0;
917 : : }
918 : 0 : txq_ctrl->txq.inlen_send = inlen_send;
919 : 0 : txq_ctrl->txq.inlen_mode = inlen_mode;
920 : 0 : txq_ctrl->txq.inlen_empw = 0;
921 [ # # # # ]: 0 : if (inlen_send && inlen_empw && priv->txqs_n >= txqs_inline) {
922 : : /*
923 : : * The data sent with MLX5_OPCODE_ENHANCED_MPSW
924 : : * may be inlined in Data Segment, align the
925 : : * length accordingly to fit entire WQEBBs.
926 : : */
927 : 0 : temp = RTE_MAX(inlen_empw,
928 : : MLX5_WQE_SIZE + MLX5_DSEG_MIN_INLINE_SIZE);
929 : : temp -= MLX5_DSEG_MIN_INLINE_SIZE;
930 : 0 : temp = RTE_ALIGN(temp, MLX5_WQE_SIZE);
931 : 0 : temp += MLX5_DSEG_MIN_INLINE_SIZE;
932 : 0 : temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
933 : : MLX5_DSEG_MIN_INLINE_SIZE -
934 : : MLX5_WQE_CSEG_SIZE -
935 : : MLX5_WQE_ESEG_SIZE -
936 : : MLX5_WQE_DSEG_SIZE);
937 : 0 : temp = RTE_MIN(temp, MLX5_EMPW_MAX_INLINE_LEN);
938 [ # # ]: 0 : if (temp != inlen_empw) {
939 : 0 : DRV_LOG(INFO,
940 : : "port %u enhanced empw inline setting"
941 : : " aligned from %u to %u",
942 : : PORT_ID(priv), inlen_empw, temp);
943 : : inlen_empw = temp;
944 : : }
945 : : MLX5_ASSERT(inlen_empw >= MLX5_ESEG_MIN_INLINE_SIZE);
946 : : MLX5_ASSERT(inlen_empw <= MLX5_WQE_SIZE_MAX +
947 : : MLX5_DSEG_MIN_INLINE_SIZE -
948 : : MLX5_WQE_CSEG_SIZE -
949 : : MLX5_WQE_ESEG_SIZE -
950 : : MLX5_WQE_DSEG_SIZE);
951 : 0 : txq_ctrl->txq.inlen_empw = inlen_empw;
952 : : }
953 : 0 : txq_ctrl->max_inline_data = RTE_MAX(inlen_send, inlen_empw);
954 [ # # ]: 0 : if (tso) {
955 : 0 : txq_ctrl->max_tso_header = MLX5_MAX_TSO_HEADER;
956 : 0 : txq_ctrl->max_inline_data = RTE_MAX(txq_ctrl->max_inline_data,
957 : : MLX5_MAX_TSO_HEADER);
958 : 0 : txq_ctrl->txq.tso_en = 1;
959 : : }
960 [ # # ]: 0 : if (((RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO & txq_ctrl->txq.offloads) &&
961 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_VXLAN_CAP)) |
962 [ # # ]: 0 : ((RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO & txq_ctrl->txq.offloads) &&
963 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_GRE_CAP)) |
964 [ # # ]: 0 : ((RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO & txq_ctrl->txq.offloads) &&
965 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_GENEVE_CAP)) |
966 [ # # ]: 0 : (dev_cap->swp & MLX5_SW_PARSING_TSO_CAP))
967 : 0 : txq_ctrl->txq.tunnel_en = 1;
968 : 0 : txq_ctrl->txq.swp_en = (((RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
969 : 0 : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO) &
970 [ # # # # ]: 0 : txq_ctrl->txq.offloads) && (dev_cap->swp &
971 : 0 : MLX5_SW_PARSING_TSO_CAP)) |
972 : 0 : ((RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM &
973 [ # # # # ]: 0 : txq_ctrl->txq.offloads) && (dev_cap->swp &
974 : : MLX5_SW_PARSING_CSUM_CAP));
975 : 0 : }
976 : :
977 : : /**
978 : : * Adjust Tx queue data inline parameters for large queue sizes.
979 : : * The data inline feature requires multiple WQEs to fit the packets,
980 : : * and if the large amount of Tx descriptors is requested by application
981 : : * the total WQE amount may exceed the hardware capabilities. If the
982 : : * default inline setting are used we can try to adjust these ones and
983 : : * meet the hardware requirements and not exceed the queue size.
984 : : *
985 : : * @param txq_ctrl
986 : : * Pointer to Tx queue control structure.
987 : : */
988 : : static void
989 : 0 : txq_adjust_params(struct mlx5_txq_ctrl *txq_ctrl)
990 : : {
991 : 0 : struct mlx5_priv *priv = txq_ctrl->priv;
992 : : struct mlx5_port_config *config = &priv->config;
993 : : unsigned int max_inline;
994 : :
995 : : max_inline = txq_calc_inline_max(txq_ctrl);
996 [ # # ]: 0 : if (!txq_ctrl->txq.inlen_send) {
997 : : /*
998 : : * Inline data feature is not engaged at all.
999 : : * There is nothing to adjust.
1000 : : */
1001 : : return;
1002 : : }
1003 [ # # ]: 0 : if (txq_ctrl->max_inline_data <= max_inline) {
1004 : : /*
1005 : : * The requested inline data length does not
1006 : : * exceed queue capabilities.
1007 : : */
1008 : : return;
1009 : : }
1010 [ # # ]: 0 : if (txq_ctrl->txq.inlen_mode > max_inline) {
1011 : 0 : DRV_LOG(WARNING,
1012 : : "minimal data inline requirements (%u) are not satisfied (%u) on port %u",
1013 : : txq_ctrl->txq.inlen_mode, max_inline, priv->dev_data->port_id);
1014 : : }
1015 [ # # ]: 0 : if (txq_ctrl->txq.inlen_send > max_inline &&
1016 [ # # ]: 0 : config->txq_inline_max != MLX5_ARG_UNSET &&
1017 [ # # ]: 0 : config->txq_inline_max > (int)max_inline) {
1018 : 0 : DRV_LOG(WARNING,
1019 : : "txq_inline_max requirements (%u) are not satisfied (%u) on port %u",
1020 : : txq_ctrl->txq.inlen_send, max_inline, priv->dev_data->port_id);
1021 : : }
1022 [ # # ]: 0 : if (txq_ctrl->txq.inlen_empw > max_inline &&
1023 [ # # ]: 0 : config->txq_inline_mpw != MLX5_ARG_UNSET &&
1024 [ # # ]: 0 : config->txq_inline_mpw > (int)max_inline) {
1025 : 0 : DRV_LOG(WARNING,
1026 : : "txq_inline_mpw requirements (%u) are not satisfied (%u) on port %u",
1027 : : txq_ctrl->txq.inlen_empw, max_inline, priv->dev_data->port_id);
1028 : : }
1029 : : MLX5_ASSERT(max_inline >= (MLX5_ESEG_MIN_INLINE_SIZE - MLX5_DSEG_MIN_INLINE_SIZE));
1030 : 0 : max_inline -= MLX5_ESEG_MIN_INLINE_SIZE - MLX5_DSEG_MIN_INLINE_SIZE;
1031 [ # # # # ]: 0 : if (txq_ctrl->txq.tso_en && max_inline < MLX5_MAX_TSO_HEADER) {
1032 : 0 : DRV_LOG(WARNING,
1033 : : "tso header inline requirements (%u) are not satisfied (%u) on port %u",
1034 : : MLX5_MAX_TSO_HEADER, max_inline, priv->dev_data->port_id);
1035 : : }
1036 [ # # ]: 0 : if (txq_ctrl->txq.inlen_send > max_inline) {
1037 : 0 : DRV_LOG(WARNING,
1038 : : "adjust txq_inline_max (%u->%u) due to large Tx queue on port %u",
1039 : : txq_ctrl->txq.inlen_send, max_inline, priv->dev_data->port_id);
1040 : 0 : txq_ctrl->txq.inlen_send = max_inline;
1041 : : }
1042 [ # # ]: 0 : if (txq_ctrl->txq.inlen_empw > max_inline) {
1043 : 0 : DRV_LOG(WARNING,
1044 : : "adjust txq_inline_mpw (%u->%u) due to large Tx queue on port %u",
1045 : : txq_ctrl->txq.inlen_empw, max_inline, priv->dev_data->port_id);
1046 : 0 : txq_ctrl->txq.inlen_empw = max_inline;
1047 : : }
1048 : 0 : txq_ctrl->max_inline_data = RTE_MAX(txq_ctrl->txq.inlen_send,
1049 : : txq_ctrl->txq.inlen_empw);
1050 : : MLX5_ASSERT(txq_ctrl->txq.inlen_mode <= txq_ctrl->txq.inlen_send);
1051 : : MLX5_ASSERT(txq_ctrl->txq.inlen_mode <= txq_ctrl->txq.inlen_empw ||
1052 : : !txq_ctrl->txq.inlen_empw);
1053 : : }
1054 : :
1055 : : /*
1056 : : * Calculate WQ memory length for a Tx queue.
1057 : : *
1058 : : * @param log_wqe_cnt
1059 : : * Logarithm value of WQE numbers.
1060 : : *
1061 : : * @return
1062 : : * memory length of this WQ.
1063 : : */
1064 : : static uint32_t mlx5_txq_wq_mem_length(uint32_t log_wqe_cnt)
1065 : : {
1066 : : uint32_t num_of_wqbbs = 1U << log_wqe_cnt;
1067 : : uint32_t umem_size;
1068 : :
1069 : 0 : umem_size = MLX5_WQE_SIZE * num_of_wqbbs;
1070 : : return umem_size;
1071 : : }
1072 : :
1073 : : /*
1074 : : * Calculate CQ memory length for a Tx queue.
1075 : : *
1076 : : * @param dev
1077 : : * Pointer to Ethernet device.
1078 : : * @param txq_ctrl
1079 : : * Pointer to the TxQ control structure of the CQ.
1080 : : *
1081 : : * @return
1082 : : * memory length of this CQ.
1083 : : */
1084 : : static uint32_t
1085 : 0 : mlx5_txq_cq_mem_length(struct rte_eth_dev *dev, struct mlx5_txq_ctrl *txq_ctrl)
1086 : : {
1087 : : uint32_t cqe_n, log_desc_n;
1088 : :
1089 : : if (__rte_trace_point_fp_is_enabled() &&
1090 : : txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP)
1091 : : cqe_n = UINT16_MAX / 2 - 1;
1092 : : else
1093 : 0 : cqe_n = (1UL << txq_ctrl->txq.elts_n) / MLX5_TX_COMP_THRESH +
1094 : 0 : 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
1095 : : log_desc_n = log2above(cqe_n);
1096 : 0 : cqe_n = 1UL << log_desc_n;
1097 [ # # ]: 0 : if (cqe_n > UINT16_MAX) {
1098 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u requests to many CQEs %u.",
1099 : : dev->data->port_id, txq_ctrl->txq.idx, cqe_n);
1100 : 0 : rte_errno = EINVAL;
1101 : 0 : return 0;
1102 : : }
1103 : 0 : return sizeof(struct mlx5_cqe) * cqe_n;
1104 : : }
1105 : :
1106 : : /**
1107 : : * Create a DPDK Tx queue.
1108 : : *
1109 : : * @param dev
1110 : : * Pointer to Ethernet device.
1111 : : * @param idx
1112 : : * TX queue index.
1113 : : * @param desc
1114 : : * Number of descriptors to configure in queue.
1115 : : * @param socket
1116 : : * NUMA socket on which memory must be allocated.
1117 : : * @param[in] conf
1118 : : * Thresholds parameters.
1119 : : *
1120 : : * @return
1121 : : * A DPDK queue object on success, NULL otherwise and rte_errno is set.
1122 : : */
1123 : : struct mlx5_txq_ctrl *
1124 : 0 : mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1125 : : unsigned int socket, const struct rte_eth_txconf *conf)
1126 : : {
1127 : : int ret;
1128 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1129 : : struct mlx5_txq_ctrl *tmpl;
1130 : : uint16_t max_wqe;
1131 : : uint32_t wqebb_cnt, log_desc_n;
1132 : :
1133 [ # # ]: 0 : if (socket != (unsigned int)SOCKET_ID_ANY) {
1134 : 0 : tmpl = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl) +
1135 : : desc * sizeof(struct rte_mbuf *), 0, socket);
1136 : : } else {
1137 [ # # # # : 0 : tmpl = mlx5_malloc_numa_tolerant(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl) +
# # ]
1138 : : desc * sizeof(struct rte_mbuf *), 0,
1139 : : dev->device->numa_node);
1140 : : }
1141 [ # # ]: 0 : if (!tmpl) {
1142 : 0 : rte_errno = ENOMEM;
1143 : 0 : return NULL;
1144 : : }
1145 [ # # ]: 0 : if (socket != (unsigned int)SOCKET_ID_ANY) {
1146 [ # # ]: 0 : if (mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1147 : 0 : &priv->sh->cdev->mr_scache.dev_gen, socket))
1148 : : /* rte_errno is already set. */
1149 : 0 : goto error;
1150 : : } else {
1151 : 0 : ret = mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1152 : 0 : &priv->sh->cdev->mr_scache.dev_gen, dev->device->numa_node);
1153 [ # # ]: 0 : if (ret == -ENOMEM) {
1154 : 0 : ret = mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1155 : 0 : &priv->sh->cdev->mr_scache.dev_gen, SOCKET_ID_ANY);
1156 : : }
1157 [ # # ]: 0 : if (ret)
1158 : : /* rte_errno is already set. */
1159 : 0 : goto error;
1160 : : }
1161 : : MLX5_ASSERT(desc > MLX5_TX_COMP_THRESH);
1162 : 0 : tmpl->txq.offloads = conf->offloads |
1163 : 0 : dev->data->dev_conf.txmode.offloads;
1164 : 0 : tmpl->priv = priv;
1165 : 0 : tmpl->socket = (socket == (unsigned int)SOCKET_ID_ANY ?
1166 [ # # ]: 0 : (unsigned int)dev->device->numa_node : socket);
1167 : 0 : tmpl->txq.elts_n = log2above(desc);
1168 : 0 : tmpl->txq.elts_s = desc;
1169 : 0 : tmpl->txq.elts_m = desc - 1;
1170 : 0 : tmpl->txq.port_id = dev->data->port_id;
1171 : 0 : tmpl->txq.idx = idx;
1172 : 0 : txq_set_params(tmpl);
1173 : 0 : txq_adjust_params(tmpl);
1174 [ # # ]: 0 : wqebb_cnt = txq_calc_wqebb_cnt(tmpl, !!mlx5_devx_obj_ops_en(priv->sh));
1175 : 0 : max_wqe = mlx5_dev_get_max_wq_size(priv->sh);
1176 [ # # ]: 0 : if (wqebb_cnt > max_wqe) {
1177 : 0 : DRV_LOG(ERR,
1178 : : "port %u Tx WQEBB count (%d) exceeds the limit (%d),"
1179 : : " try smaller queue size",
1180 : : dev->data->port_id, wqebb_cnt, max_wqe);
1181 : 0 : rte_errno = ENOMEM;
1182 : 0 : goto error;
1183 : : }
1184 [ # # ]: 0 : if (priv->sh->config.txq_mem_algn != 0) {
1185 : : log_desc_n = log2above(wqebb_cnt);
1186 : 0 : tmpl->txq.sq_mem_len = mlx5_txq_wq_mem_length(log_desc_n);
1187 : 0 : tmpl->txq.cq_mem_len = mlx5_txq_cq_mem_length(dev, tmpl);
1188 : 0 : DRV_LOG(DEBUG, "Port %u TxQ %u WQ length %u, CQ length %u before align.",
1189 : : dev->data->port_id, idx, tmpl->txq.sq_mem_len, tmpl->txq.cq_mem_len);
1190 : 0 : priv->consec_tx_mem.sq_total_size += tmpl->txq.sq_mem_len;
1191 : 0 : priv->consec_tx_mem.cq_total_size += tmpl->txq.cq_mem_len;
1192 : : }
1193 : 0 : rte_atomic_fetch_add_explicit(&tmpl->refcnt, 1, rte_memory_order_relaxed);
1194 : 0 : tmpl->is_hairpin = false;
1195 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
1196 : 0 : return tmpl;
1197 : 0 : error:
1198 : 0 : mlx5_mr_btree_free(&tmpl->txq.mr_ctrl.cache_bh);
1199 : 0 : mlx5_free(tmpl);
1200 : 0 : return NULL;
1201 : : }
1202 : :
1203 : : /**
1204 : : * Create a DPDK Tx hairpin queue.
1205 : : *
1206 : : * @param dev
1207 : : * Pointer to Ethernet device.
1208 : : * @param idx
1209 : : * TX queue index.
1210 : : * @param desc
1211 : : * Number of descriptors to configure in queue.
1212 : : * @param hairpin_conf
1213 : : * The hairpin configuration.
1214 : : *
1215 : : * @return
1216 : : * A DPDK queue object on success, NULL otherwise and rte_errno is set.
1217 : : */
1218 : : struct mlx5_txq_ctrl *
1219 : 0 : mlx5_txq_hairpin_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1220 : : const struct rte_eth_hairpin_conf *hairpin_conf)
1221 : : {
1222 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1223 : : struct mlx5_txq_ctrl *tmpl;
1224 : :
1225 : 0 : tmpl = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl), 0,
1226 : : SOCKET_ID_ANY);
1227 [ # # ]: 0 : if (!tmpl) {
1228 : 0 : rte_errno = ENOMEM;
1229 : 0 : return NULL;
1230 : : }
1231 : 0 : tmpl->priv = priv;
1232 : 0 : tmpl->socket = SOCKET_ID_ANY;
1233 : 0 : tmpl->txq.elts_n = log2above(desc);
1234 : 0 : tmpl->txq.port_id = dev->data->port_id;
1235 : 0 : tmpl->txq.idx = idx;
1236 : 0 : tmpl->hairpin_conf = *hairpin_conf;
1237 : 0 : tmpl->is_hairpin = true;
1238 : 0 : rte_atomic_fetch_add_explicit(&tmpl->refcnt, 1, rte_memory_order_relaxed);
1239 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
1240 : 0 : return tmpl;
1241 : : }
1242 : :
1243 : : /**
1244 : : * Get a Tx queue.
1245 : : *
1246 : : * @param dev
1247 : : * Pointer to Ethernet device.
1248 : : * @param idx
1249 : : * TX queue index.
1250 : : *
1251 : : * @return
1252 : : * A pointer to the queue if it exists.
1253 : : */
1254 : : struct mlx5_txq_ctrl *
1255 : 0 : mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
1256 : : {
1257 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1258 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1259 : : struct mlx5_txq_ctrl *ctrl = NULL;
1260 : :
1261 [ # # ]: 0 : if (txq_data) {
1262 : 0 : ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
1263 : 0 : rte_atomic_fetch_add_explicit(&ctrl->refcnt, 1, rte_memory_order_relaxed);
1264 : : }
1265 : 0 : return ctrl;
1266 : : }
1267 : :
1268 : : /**
1269 : : * Get an external Tx queue.
1270 : : *
1271 : : * @param dev
1272 : : * Pointer to Ethernet device.
1273 : : * @param idx
1274 : : * External Tx queue index.
1275 : : *
1276 : : * @return
1277 : : * A pointer to the queue if it exists, NULL otherwise.
1278 : : */
1279 : : struct mlx5_external_q *
1280 : 0 : mlx5_ext_txq_get(struct rte_eth_dev *dev, uint16_t idx)
1281 : : {
1282 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1283 : :
1284 : : MLX5_ASSERT(mlx5_is_external_txq(dev, idx));
1285 : 0 : return &priv->ext_txqs[idx - MLX5_EXTERNAL_TX_QUEUE_ID_MIN];
1286 : : }
1287 : :
1288 : : /**
1289 : : * Verify the external Tx Queue list is empty.
1290 : : *
1291 : : * @param dev
1292 : : * Pointer to Ethernet device.
1293 : : *
1294 : : * @return
1295 : : * The number of object not released.
1296 : : */
1297 : : int
1298 : 0 : mlx5_ext_txq_verify(struct rte_eth_dev *dev)
1299 : : {
1300 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1301 : : struct mlx5_external_q *txq;
1302 : : uint32_t i;
1303 : : int ret = 0;
1304 : :
1305 [ # # ]: 0 : if (priv->ext_txqs == NULL)
1306 : : return 0;
1307 : :
1308 [ # # ]: 0 : for (i = MLX5_EXTERNAL_TX_QUEUE_ID_MIN; i <= UINT16_MAX ; ++i) {
1309 : 0 : txq = mlx5_ext_txq_get(dev, i);
1310 [ # # ]: 0 : if (txq->refcnt < 2)
1311 : 0 : continue;
1312 : 0 : DRV_LOG(DEBUG, "Port %u external TxQ %u still referenced.",
1313 : : dev->data->port_id, i);
1314 : 0 : ++ret;
1315 : : }
1316 : : return ret;
1317 : : }
1318 : :
1319 : : /**
1320 : : * Release a Tx queue.
1321 : : *
1322 : : * @param dev
1323 : : * Pointer to Ethernet device.
1324 : : * @param idx
1325 : : * TX queue index.
1326 : : *
1327 : : * @return
1328 : : * 1 while a reference on it exists, 0 when freed.
1329 : : */
1330 : : int
1331 : 0 : mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
1332 : : {
1333 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1334 : : struct mlx5_txq_ctrl *txq_ctrl;
1335 : :
1336 [ # # # # ]: 0 : if (priv->txqs == NULL || (*priv->txqs)[idx] == NULL)
1337 : : return 0;
1338 : 0 : txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
1339 [ # # ]: 0 : if (rte_atomic_fetch_sub_explicit(&txq_ctrl->refcnt, 1, rte_memory_order_relaxed) - 1 > 1)
1340 : : return 1;
1341 [ # # ]: 0 : if (txq_ctrl->obj) {
1342 : 0 : priv->obj_ops.txq_obj_release(txq_ctrl->obj);
1343 [ # # ]: 0 : LIST_REMOVE(txq_ctrl->obj, next);
1344 : 0 : mlx5_free(txq_ctrl->obj);
1345 : 0 : txq_ctrl->obj = NULL;
1346 : : }
1347 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
1348 [ # # ]: 0 : if (txq_ctrl->txq.fcqs) {
1349 : 0 : mlx5_free(txq_ctrl->txq.fcqs);
1350 : 0 : txq_ctrl->txq.fcqs = NULL;
1351 : : }
1352 : 0 : txq_free_elts(txq_ctrl);
1353 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STOPPED;
1354 : : }
1355 [ # # ]: 0 : if (!rte_atomic_load_explicit(&txq_ctrl->refcnt, rte_memory_order_relaxed)) {
1356 [ # # ]: 0 : if (!txq_ctrl->is_hairpin)
1357 : 0 : mlx5_mr_btree_free(&txq_ctrl->txq.mr_ctrl.cache_bh);
1358 [ # # ]: 0 : LIST_REMOVE(txq_ctrl, next);
1359 : 0 : mlx5_free(txq_ctrl);
1360 : 0 : (*priv->txqs)[idx] = NULL;
1361 : : }
1362 : : return 0;
1363 : : }
1364 : :
1365 : : /**
1366 : : * Verify if the queue can be released.
1367 : : *
1368 : : * @param dev
1369 : : * Pointer to Ethernet device.
1370 : : * @param idx
1371 : : * TX queue index.
1372 : : *
1373 : : * @return
1374 : : * 1 if the queue can be released.
1375 : : */
1376 : : int
1377 : 0 : mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
1378 : : {
1379 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1380 : : struct mlx5_txq_ctrl *txq;
1381 : :
1382 [ # # ]: 0 : if (!(*priv->txqs)[idx])
1383 : : return -1;
1384 : 0 : txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
1385 : 0 : return (rte_atomic_load_explicit(&txq->refcnt, rte_memory_order_relaxed) == 1);
1386 : : }
1387 : :
1388 : : /**
1389 : : * Verify the Tx Queue list is empty
1390 : : *
1391 : : * @param dev
1392 : : * Pointer to Ethernet device.
1393 : : *
1394 : : * @return
1395 : : * The number of object not released.
1396 : : */
1397 : : int
1398 : 0 : mlx5_txq_verify(struct rte_eth_dev *dev)
1399 : : {
1400 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1401 : : struct mlx5_txq_ctrl *txq_ctrl;
1402 : : int ret = 0;
1403 : :
1404 [ # # ]: 0 : LIST_FOREACH(txq_ctrl, &priv->txqsctrl, next) {
1405 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %u still referenced",
1406 : : dev->data->port_id, txq_ctrl->txq.idx);
1407 : 0 : ++ret;
1408 : : }
1409 : 0 : return ret;
1410 : : }
1411 : :
1412 : : int
1413 : 0 : mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq)
1414 : : {
1415 [ # # ]: 0 : return txq->is_hairpin ? txq->obj->sq->id : txq->obj->sq_obj.sq->id;
1416 : : }
1417 : :
1418 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_sq_enable, 22.07)
1419 : : int
1420 : 0 : rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num)
1421 : : {
1422 : : struct rte_eth_dev *dev;
1423 : : struct mlx5_priv *priv;
1424 : : uint32_t flow;
1425 : :
1426 [ # # ]: 0 : if (rte_eth_dev_is_valid_port(port_id) < 0) {
1427 : 0 : DRV_LOG(ERR, "There is no Ethernet device for port %u.",
1428 : : port_id);
1429 : 0 : rte_errno = ENODEV;
1430 : 0 : return -rte_errno;
1431 : : }
1432 : 0 : dev = &rte_eth_devices[port_id];
1433 : 0 : priv = dev->data->dev_private;
1434 [ # # ]: 0 : if ((!priv->representor && !priv->master) ||
1435 [ # # ]: 0 : !priv->sh->config.dv_esw_en) {
1436 : 0 : DRV_LOG(ERR, "Port %u must be represetnor or master port in E-Switch mode.",
1437 : : port_id);
1438 : 0 : rte_errno = EINVAL;
1439 : 0 : return -rte_errno;
1440 : : }
1441 [ # # ]: 0 : if (sq_num == 0) {
1442 : 0 : DRV_LOG(ERR, "Invalid SQ number.");
1443 : 0 : rte_errno = EINVAL;
1444 : 0 : return -rte_errno;
1445 : : }
1446 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1447 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1448 : : bool sq_miss_created = false;
1449 : :
1450 [ # # ]: 0 : if (priv->sh->config.fdb_def_rule) {
1451 [ # # ]: 0 : if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, sq_num, true))
1452 : 0 : return -rte_errno;
1453 : : sq_miss_created = true;
1454 : : }
1455 : :
1456 [ # # # # ]: 0 : if (priv->sh->config.repr_matching &&
1457 : 0 : mlx5_flow_hw_tx_repr_matching_flow(dev, sq_num, true)) {
1458 [ # # ]: 0 : if (sq_miss_created)
1459 : 0 : mlx5_flow_hw_esw_destroy_sq_miss_flow(dev, sq_num);
1460 : 0 : return -rte_errno;
1461 : : }
1462 : 0 : return 0;
1463 : : }
1464 : : #endif
1465 : 0 : flow = mlx5_flow_create_devx_sq_miss_flow(dev, sq_num);
1466 [ # # ]: 0 : if (flow > 0)
1467 : : return 0;
1468 : 0 : DRV_LOG(ERR, "Port %u failed to create default miss flow for SQ %u.",
1469 : : port_id, sq_num);
1470 : 0 : return -rte_errno;
1471 : : }
1472 : :
1473 : : /**
1474 : : * Set the Tx queue dynamic timestamp (mask and offset)
1475 : : *
1476 : : * @param[in] dev
1477 : : * Pointer to the Ethernet device structure.
1478 : : */
1479 : : void
1480 : 0 : mlx5_txq_dynf_timestamp_set(struct rte_eth_dev *dev)
1481 : : {
1482 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1483 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1484 : : struct mlx5_txq_data *data;
1485 : : int off, nbit;
1486 : : unsigned int i;
1487 : : uint64_t mask = 0;
1488 : : uint64_t ts_mask;
1489 : :
1490 [ # # ]: 0 : if (sh->dev_cap.rt_timestamp ||
1491 [ # # ]: 0 : !sh->cdev->config.hca_attr.dev_freq_khz)
1492 : : ts_mask = MLX5_TS_MASK_SECS << 32;
1493 : : else
1494 : 0 : ts_mask = rte_align64pow2(MLX5_TS_MASK_SECS * 1000ull *
1495 : 0 : sh->cdev->config.hca_attr.dev_freq_khz);
1496 [ # # ]: 0 : ts_mask = rte_cpu_to_be_64(ts_mask - 1ull);
1497 : 0 : nbit = rte_mbuf_dynflag_lookup
1498 : : (RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, NULL);
1499 : 0 : off = rte_mbuf_dynfield_lookup
1500 : : (RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL);
1501 [ # # ]: 0 : if (nbit >= 0 && off >= 0 &&
1502 [ # # # # ]: 0 : (sh->txpp.refcnt || priv->sh->cdev->config.hca_attr.wait_on_time))
1503 : 0 : mask = 1ULL << nbit;
1504 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
1505 : 0 : data = (*priv->txqs)[i];
1506 [ # # ]: 0 : if (!data)
1507 : 0 : continue;
1508 : 0 : data->sh = sh;
1509 : 0 : data->ts_mask = mask;
1510 : 0 : data->ts_offset = off;
1511 : 0 : data->rt_timestamp = sh->dev_cap.rt_timestamp;
1512 : 0 : data->rt_timemask = (data->offloads &
1513 : : RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP) ?
1514 [ # # ]: 0 : ts_mask : 0;
1515 : : }
1516 : 0 : }
1517 : :
1518 : 0 : int mlx5_count_aggr_ports(struct rte_eth_dev *dev)
1519 : : {
1520 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1521 : :
1522 : 0 : return priv->sh->bond.n_port;
1523 : : }
1524 : :
1525 : 0 : int mlx5_map_aggr_tx_affinity(struct rte_eth_dev *dev, uint16_t tx_queue_id,
1526 : : uint8_t affinity)
1527 : : {
1528 : : struct mlx5_txq_ctrl *txq_ctrl;
1529 : : struct mlx5_txq_data *txq;
1530 : : struct mlx5_priv *priv;
1531 : :
1532 : 0 : priv = dev->data->dev_private;
1533 [ # # # # ]: 0 : if (!mlx5_devx_obj_ops_en(priv->sh)) {
1534 : 0 : DRV_LOG(ERR, "Tx affinity mapping isn't supported by Verbs API.");
1535 : 0 : rte_errno = ENOTSUP;
1536 : 0 : return -rte_errno;
1537 : : }
1538 : 0 : txq = (*priv->txqs)[tx_queue_id];
1539 [ # # ]: 0 : if (!txq)
1540 : : return -1;
1541 : 0 : txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
1542 [ # # ]: 0 : if (tx_queue_id >= priv->txqs_n) {
1543 : 0 : DRV_LOG(ERR, "port %u Tx queue index out of range (%u >= %u)",
1544 : : dev->data->port_id, tx_queue_id, priv->txqs_n);
1545 : 0 : rte_errno = EOVERFLOW;
1546 : 0 : return -rte_errno;
1547 : : }
1548 [ # # ]: 0 : if (affinity > priv->num_lag_ports) {
1549 : 0 : DRV_LOG(ERR, "port %u unable to setup Tx queue index %u"
1550 : : " affinity is %u exceeds the maximum %u", dev->data->port_id,
1551 : : tx_queue_id, affinity, priv->num_lag_ports);
1552 : 0 : rte_errno = EINVAL;
1553 : 0 : return -rte_errno;
1554 : : }
1555 : 0 : DRV_LOG(DEBUG, "port %u configuring queue %u for aggregated affinity %u",
1556 : : dev->data->port_id, tx_queue_id, affinity);
1557 : 0 : txq_ctrl->txq.tx_aggr_affinity = affinity;
1558 : 0 : return 0;
1559 : : }
1560 : :
1561 : : /**
1562 : : * Validate given external TxQ rte_flow index, and get pointer to concurrent
1563 : : * external TxQ object to map/unmap.
1564 : : *
1565 : : * @param[in] port_id
1566 : : * The port identifier of the Ethernet device.
1567 : : * @param[in] dpdk_idx
1568 : : * Tx Queue index in rte_flow.
1569 : : *
1570 : : * @return
1571 : : * Pointer to concurrent external TxQ on success,
1572 : : * NULL otherwise and rte_errno is set.
1573 : : */
1574 : : static struct mlx5_external_q *
1575 : 0 : mlx5_external_tx_queue_get_validate(uint16_t port_id, uint16_t dpdk_idx)
1576 : : {
1577 : : struct rte_eth_dev *dev;
1578 : : struct mlx5_priv *priv;
1579 : : int ret;
1580 : :
1581 [ # # ]: 0 : if (dpdk_idx < MLX5_EXTERNAL_TX_QUEUE_ID_MIN) {
1582 : 0 : DRV_LOG(ERR, "Queue index %u should be in range: [%u, %u].",
1583 : : dpdk_idx, MLX5_EXTERNAL_TX_QUEUE_ID_MIN, UINT16_MAX);
1584 : 0 : rte_errno = EINVAL;
1585 : 0 : return NULL;
1586 : : }
1587 : 0 : ret = mlx5_devx_extq_port_validate(port_id);
1588 [ # # ]: 0 : if (unlikely(ret))
1589 : : return NULL;
1590 : : dev = &rte_eth_devices[port_id];
1591 : 0 : priv = dev->data->dev_private;
1592 : : /*
1593 : : * When user configures remote PD and CTX and device creates TxQ by
1594 : : * DevX, external TxQs array is allocated.
1595 : : */
1596 : : MLX5_ASSERT(priv->ext_txqs != NULL);
1597 : 0 : return &priv->ext_txqs[dpdk_idx - MLX5_EXTERNAL_TX_QUEUE_ID_MIN];
1598 : : }
1599 : :
1600 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_tx_queue_id_map, 24.07)
1601 : : int
1602 : 0 : rte_pmd_mlx5_external_tx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
1603 : : uint32_t hw_idx)
1604 : : {
1605 : : struct mlx5_external_q *ext_txq;
1606 : : uint32_t unmapped = 0;
1607 : :
1608 : 0 : ext_txq = mlx5_external_tx_queue_get_validate(port_id, dpdk_idx);
1609 [ # # ]: 0 : if (ext_txq == NULL)
1610 : 0 : return -rte_errno;
1611 [ # # ]: 0 : if (!rte_atomic_compare_exchange_strong_explicit(&ext_txq->refcnt, &unmapped, 1,
1612 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
1613 [ # # ]: 0 : if (ext_txq->hw_id != hw_idx) {
1614 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u "
1615 : : "is already mapped to HW index (requesting is "
1616 : : "%u, existing is %u).",
1617 : : port_id, dpdk_idx, hw_idx, ext_txq->hw_id);
1618 : 0 : rte_errno = EEXIST;
1619 : 0 : return -rte_errno;
1620 : : }
1621 : 0 : DRV_LOG(WARNING, "Port %u external TxQ index %u "
1622 : : "is already mapped to the requested HW index (%u)",
1623 : : port_id, dpdk_idx, hw_idx);
1624 : :
1625 : : } else {
1626 : 0 : ext_txq->hw_id = hw_idx;
1627 : 0 : DRV_LOG(DEBUG, "Port %u external TxQ index %u "
1628 : : "is successfully mapped to the requested HW index (%u)",
1629 : : port_id, dpdk_idx, hw_idx);
1630 : : }
1631 : : return 0;
1632 : : }
1633 : :
1634 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_tx_queue_id_unmap, 24.07)
1635 : : int
1636 : 0 : rte_pmd_mlx5_external_tx_queue_id_unmap(uint16_t port_id, uint16_t dpdk_idx)
1637 : : {
1638 : : struct mlx5_external_q *ext_txq;
1639 : : uint32_t mapped = 1;
1640 : :
1641 : 0 : ext_txq = mlx5_external_tx_queue_get_validate(port_id, dpdk_idx);
1642 [ # # ]: 0 : if (ext_txq == NULL)
1643 : 0 : return -rte_errno;
1644 [ # # ]: 0 : if (ext_txq->refcnt > 1) {
1645 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u still referenced.",
1646 : : port_id, dpdk_idx);
1647 : 0 : rte_errno = EINVAL;
1648 : 0 : return -rte_errno;
1649 : : }
1650 [ # # ]: 0 : if (!rte_atomic_compare_exchange_strong_explicit(&ext_txq->refcnt, &mapped, 0,
1651 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
1652 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u doesn't exist.",
1653 : : port_id, dpdk_idx);
1654 : 0 : rte_errno = EINVAL;
1655 : 0 : return -rte_errno;
1656 : : }
1657 : 0 : DRV_LOG(DEBUG,
1658 : : "Port %u external TxQ index %u is successfully unmapped.",
1659 : : port_id, dpdk_idx);
1660 : 0 : return 0;
1661 : : }
|