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 : : *
699 : : * @return
700 : : * The number of WQEBB.
701 : : */
702 : : static int
703 : : txq_calc_wqebb_cnt(struct mlx5_txq_ctrl *txq_ctrl)
704 : : {
705 : : unsigned int wqe_size;
706 : 0 : const unsigned int desc = 1 << txq_ctrl->txq.elts_n;
707 : :
708 : 0 : wqe_size = MLX5_WQE_CSEG_SIZE +
709 : : MLX5_WQE_ESEG_SIZE +
710 : : MLX5_WSEG_SIZE -
711 : : MLX5_ESEG_MIN_INLINE_SIZE +
712 : 0 : txq_ctrl->max_inline_data;
713 : 0 : wqe_size = RTE_MAX(wqe_size, MLX5_WQE_SIZE);
714 : 0 : return rte_align32pow2(wqe_size * desc) / MLX5_WQE_SIZE;
715 : : }
716 : :
717 : : /**
718 : : * Calculate the maximal inline data size for Tx queue.
719 : : *
720 : : * @param txq_ctrl
721 : : * Pointer to Tx queue control structure.
722 : : *
723 : : * @return
724 : : * The maximal inline data size.
725 : : */
726 : : static unsigned int
727 : : txq_calc_inline_max(struct mlx5_txq_ctrl *txq_ctrl)
728 : : {
729 : 0 : const unsigned int desc = 1 << txq_ctrl->txq.elts_n;
730 : : struct mlx5_priv *priv = txq_ctrl->priv;
731 : : unsigned int wqe_size;
732 : :
733 : 0 : wqe_size = mlx5_dev_get_max_wq_size(priv->sh) / desc;
734 [ # # ]: 0 : if (!wqe_size)
735 : : return 0;
736 : : /*
737 : : * This calculation is derived from the source of
738 : : * mlx5_calc_send_wqe() in rdma_core library.
739 : : */
740 : 0 : wqe_size = wqe_size * MLX5_WQE_SIZE -
741 : : MLX5_WQE_CSEG_SIZE -
742 : : MLX5_WQE_ESEG_SIZE -
743 : : MLX5_WSEG_SIZE -
744 : : MLX5_WSEG_SIZE +
745 : : MLX5_ESEG_MIN_INLINE_SIZE;
746 : 0 : return wqe_size;
747 : : }
748 : :
749 : : /**
750 : : * Set Tx queue parameters from device configuration.
751 : : *
752 : : * @param txq_ctrl
753 : : * Pointer to Tx queue control structure.
754 : : */
755 : : static void
756 : 0 : txq_set_params(struct mlx5_txq_ctrl *txq_ctrl)
757 : : {
758 : 0 : struct mlx5_priv *priv = txq_ctrl->priv;
759 : : struct mlx5_port_config *config = &priv->config;
760 : 0 : struct mlx5_dev_cap *dev_cap = &priv->sh->dev_cap;
761 : : unsigned int inlen_send; /* Inline data for ordinary SEND.*/
762 : : unsigned int inlen_empw; /* Inline data for enhanced MPW. */
763 : : unsigned int inlen_mode; /* Minimal required Inline data. */
764 : : unsigned int txqs_inline; /* Min Tx queues to enable inline. */
765 : 0 : uint64_t dev_txoff = priv->dev_data->dev_conf.txmode.offloads;
766 : 0 : bool tso = txq_ctrl->txq.offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO |
767 : : RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
768 : : RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
769 : : RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
770 : : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO);
771 : : bool vlan_inline;
772 : : unsigned int temp;
773 : :
774 : 0 : txq_ctrl->txq.fast_free =
775 [ # # ]: 0 : !!((txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) &&
776 : : !(txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS) &&
777 [ # # ]: 0 : !config->mprq.enabled);
778 [ # # ]: 0 : if (config->txqs_inline == MLX5_ARG_UNSET)
779 : : txqs_inline =
780 : : #if defined(RTE_ARCH_ARM64)
781 : : (priv->pci_dev && priv->pci_dev->id.device_id ==
782 : : PCI_DEVICE_ID_MELLANOX_BLUEFIELD) ?
783 : : MLX5_INLINE_MAX_TXQS_BLUEFIELD :
784 : : #endif
785 : : MLX5_INLINE_MAX_TXQS;
786 : : else
787 : : txqs_inline = (unsigned int)config->txqs_inline;
788 [ # # ]: 0 : inlen_send = (config->txq_inline_max == MLX5_ARG_UNSET) ?
789 : : MLX5_SEND_DEF_INLINE_LEN :
790 : : (unsigned int)config->txq_inline_max;
791 [ # # ]: 0 : inlen_empw = (config->txq_inline_mpw == MLX5_ARG_UNSET) ?
792 : : MLX5_EMPW_DEF_INLINE_LEN :
793 : : (unsigned int)config->txq_inline_mpw;
794 : 0 : inlen_mode = (config->txq_inline_min == MLX5_ARG_UNSET) ?
795 [ # # ]: 0 : 0 : (unsigned int)config->txq_inline_min;
796 [ # # ]: 0 : if (config->mps != MLX5_MPW_ENHANCED && config->mps != MLX5_MPW)
797 : : inlen_empw = 0;
798 : : /*
799 : : * If there is requested minimal amount of data to inline
800 : : * we MUST enable inlining. This is a case for ConnectX-4
801 : : * which usually requires L2 inlined for correct operating
802 : : * and ConnectX-4 Lx which requires L2-L4 inlined to
803 : : * support E-Switch Flows.
804 : : */
805 [ # # ]: 0 : if (inlen_mode) {
806 [ # # ]: 0 : if (inlen_mode <= MLX5_ESEG_MIN_INLINE_SIZE) {
807 : : /*
808 : : * Optimize minimal inlining for single
809 : : * segment packets to fill one WQEBB
810 : : * without gaps.
811 : : */
812 : : temp = MLX5_ESEG_MIN_INLINE_SIZE;
813 : : } else {
814 : : temp = inlen_mode - MLX5_ESEG_MIN_INLINE_SIZE;
815 : 0 : temp = RTE_ALIGN(temp, MLX5_WSEG_SIZE) +
816 : : MLX5_ESEG_MIN_INLINE_SIZE;
817 : 0 : temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
818 : : }
819 [ # # ]: 0 : if (temp != inlen_mode) {
820 : 0 : DRV_LOG(INFO,
821 : : "port %u minimal required inline setting"
822 : : " aligned from %u to %u",
823 : : PORT_ID(priv), inlen_mode, temp);
824 : : inlen_mode = temp;
825 : : }
826 : : }
827 : : /*
828 : : * If port is configured to support VLAN insertion and device
829 : : * does not support this feature by HW (for NICs before ConnectX-5
830 : : * or in case of wqe_vlan_insert flag is not set) we must enable
831 : : * data inline on all queues because it is supported by single
832 : : * tx_burst routine.
833 : : */
834 : 0 : txq_ctrl->txq.vlan_en = config->hw_vlan_insert;
835 [ # # ]: 0 : vlan_inline = (dev_txoff & RTE_ETH_TX_OFFLOAD_VLAN_INSERT) &&
836 [ # # ]: 0 : !config->hw_vlan_insert;
837 : : /*
838 : : * If there are few Tx queues it is prioritized
839 : : * to save CPU cycles and disable data inlining at all.
840 : : */
841 [ # # # # ]: 0 : if (inlen_send && priv->txqs_n >= txqs_inline) {
842 : : /*
843 : : * The data sent with ordinal MLX5_OPCODE_SEND
844 : : * may be inlined in Ethernet Segment, align the
845 : : * length accordingly to fit entire WQEBBs.
846 : : */
847 : 0 : temp = RTE_MAX(inlen_send,
848 : : MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE);
849 : : temp -= MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE;
850 : 0 : temp = RTE_ALIGN(temp, MLX5_WQE_SIZE);
851 : 0 : temp += MLX5_ESEG_MIN_INLINE_SIZE + MLX5_WQE_DSEG_SIZE;
852 : 0 : temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
853 : : MLX5_ESEG_MIN_INLINE_SIZE -
854 : : MLX5_WQE_CSEG_SIZE -
855 : : MLX5_WQE_ESEG_SIZE -
856 : : MLX5_WQE_DSEG_SIZE * 2);
857 : 0 : temp = RTE_MIN(temp, MLX5_SEND_MAX_INLINE_LEN);
858 : 0 : temp = RTE_MAX(temp, inlen_mode);
859 [ # # ]: 0 : if (temp != inlen_send) {
860 : 0 : DRV_LOG(INFO,
861 : : "port %u ordinary send inline setting"
862 : : " aligned from %u to %u",
863 : : PORT_ID(priv), inlen_send, temp);
864 : : inlen_send = temp;
865 : : }
866 : : /*
867 : : * Not aligned to cache lines, but to WQEs.
868 : : * First bytes of data (initial alignment)
869 : : * is going to be copied explicitly at the
870 : : * beginning of inlining buffer in Ethernet
871 : : * Segment.
872 : : */
873 : : MLX5_ASSERT(inlen_send >= MLX5_ESEG_MIN_INLINE_SIZE);
874 : : MLX5_ASSERT(inlen_send <= MLX5_WQE_SIZE_MAX +
875 : : MLX5_ESEG_MIN_INLINE_SIZE -
876 : : MLX5_WQE_CSEG_SIZE -
877 : : MLX5_WQE_ESEG_SIZE -
878 : : MLX5_WQE_DSEG_SIZE * 2);
879 [ # # ]: 0 : } else if (inlen_mode) {
880 : : /*
881 : : * If minimal inlining is requested we must
882 : : * enable inlining in general, despite the
883 : : * number of configured queues. Ignore the
884 : : * txq_inline_max devarg, this is not
885 : : * full-featured inline.
886 : : */
887 : : inlen_send = inlen_mode;
888 : : inlen_empw = 0;
889 [ # # ]: 0 : } else if (vlan_inline) {
890 : : /*
891 : : * Hardware does not report offload for
892 : : * VLAN insertion, we must enable data inline
893 : : * to implement feature by software.
894 : : */
895 : : inlen_send = MLX5_ESEG_MIN_INLINE_SIZE;
896 : : inlen_empw = 0;
897 : : } else {
898 : : inlen_send = 0;
899 : : inlen_empw = 0;
900 : : }
901 : 0 : txq_ctrl->txq.inlen_send = inlen_send;
902 : 0 : txq_ctrl->txq.inlen_mode = inlen_mode;
903 : 0 : txq_ctrl->txq.inlen_empw = 0;
904 [ # # # # ]: 0 : if (inlen_send && inlen_empw && priv->txqs_n >= txqs_inline) {
905 : : /*
906 : : * The data sent with MLX5_OPCODE_ENHANCED_MPSW
907 : : * may be inlined in Data Segment, align the
908 : : * length accordingly to fit entire WQEBBs.
909 : : */
910 : 0 : temp = RTE_MAX(inlen_empw,
911 : : MLX5_WQE_SIZE + MLX5_DSEG_MIN_INLINE_SIZE);
912 : : temp -= MLX5_DSEG_MIN_INLINE_SIZE;
913 : 0 : temp = RTE_ALIGN(temp, MLX5_WQE_SIZE);
914 : 0 : temp += MLX5_DSEG_MIN_INLINE_SIZE;
915 : 0 : temp = RTE_MIN(temp, MLX5_WQE_SIZE_MAX +
916 : : MLX5_DSEG_MIN_INLINE_SIZE -
917 : : MLX5_WQE_CSEG_SIZE -
918 : : MLX5_WQE_ESEG_SIZE -
919 : : MLX5_WQE_DSEG_SIZE);
920 : 0 : temp = RTE_MIN(temp, MLX5_EMPW_MAX_INLINE_LEN);
921 [ # # ]: 0 : if (temp != inlen_empw) {
922 : 0 : DRV_LOG(INFO,
923 : : "port %u enhanced empw inline setting"
924 : : " aligned from %u to %u",
925 : : PORT_ID(priv), inlen_empw, temp);
926 : : inlen_empw = temp;
927 : : }
928 : : MLX5_ASSERT(inlen_empw >= MLX5_ESEG_MIN_INLINE_SIZE);
929 : : MLX5_ASSERT(inlen_empw <= MLX5_WQE_SIZE_MAX +
930 : : MLX5_DSEG_MIN_INLINE_SIZE -
931 : : MLX5_WQE_CSEG_SIZE -
932 : : MLX5_WQE_ESEG_SIZE -
933 : : MLX5_WQE_DSEG_SIZE);
934 : 0 : txq_ctrl->txq.inlen_empw = inlen_empw;
935 : : }
936 : 0 : txq_ctrl->max_inline_data = RTE_MAX(inlen_send, inlen_empw);
937 [ # # ]: 0 : if (tso) {
938 : 0 : txq_ctrl->max_tso_header = MLX5_MAX_TSO_HEADER;
939 : 0 : txq_ctrl->max_inline_data = RTE_MAX(txq_ctrl->max_inline_data,
940 : : MLX5_MAX_TSO_HEADER);
941 : 0 : txq_ctrl->txq.tso_en = 1;
942 : : }
943 [ # # ]: 0 : if (((RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO & txq_ctrl->txq.offloads) &&
944 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_VXLAN_CAP)) |
945 [ # # ]: 0 : ((RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO & txq_ctrl->txq.offloads) &&
946 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_GRE_CAP)) |
947 [ # # ]: 0 : ((RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO & txq_ctrl->txq.offloads) &&
948 [ # # ]: 0 : (dev_cap->tunnel_en & MLX5_TUNNELED_OFFLOADS_GENEVE_CAP)) |
949 [ # # ]: 0 : (dev_cap->swp & MLX5_SW_PARSING_TSO_CAP))
950 : 0 : txq_ctrl->txq.tunnel_en = 1;
951 : 0 : txq_ctrl->txq.swp_en = (((RTE_ETH_TX_OFFLOAD_IP_TNL_TSO |
952 : 0 : RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO) &
953 [ # # # # ]: 0 : txq_ctrl->txq.offloads) && (dev_cap->swp &
954 : 0 : MLX5_SW_PARSING_TSO_CAP)) |
955 : 0 : ((RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM &
956 [ # # # # ]: 0 : txq_ctrl->txq.offloads) && (dev_cap->swp &
957 : : MLX5_SW_PARSING_CSUM_CAP));
958 : 0 : }
959 : :
960 : : /**
961 : : * Adjust Tx queue data inline parameters for large queue sizes.
962 : : * The data inline feature requires multiple WQEs to fit the packets,
963 : : * and if the large amount of Tx descriptors is requested by application
964 : : * the total WQE amount may exceed the hardware capabilities. If the
965 : : * default inline setting are used we can try to adjust these ones and
966 : : * meet the hardware requirements and not exceed the queue size.
967 : : *
968 : : * @param txq_ctrl
969 : : * Pointer to Tx queue control structure.
970 : : */
971 : : static void
972 : 0 : txq_adjust_params(struct mlx5_txq_ctrl *txq_ctrl)
973 : : {
974 : 0 : struct mlx5_priv *priv = txq_ctrl->priv;
975 : : struct mlx5_port_config *config = &priv->config;
976 : : unsigned int max_inline;
977 : :
978 : : max_inline = txq_calc_inline_max(txq_ctrl);
979 [ # # ]: 0 : if (!txq_ctrl->txq.inlen_send) {
980 : : /*
981 : : * Inline data feature is not engaged at all.
982 : : * There is nothing to adjust.
983 : : */
984 : : return;
985 : : }
986 [ # # ]: 0 : if (txq_ctrl->max_inline_data <= max_inline) {
987 : : /*
988 : : * The requested inline data length does not
989 : : * exceed queue capabilities.
990 : : */
991 : : return;
992 : : }
993 [ # # ]: 0 : if (txq_ctrl->txq.inlen_mode > max_inline) {
994 : 0 : DRV_LOG(WARNING,
995 : : "minimal data inline requirements (%u) are not satisfied (%u) on port %u",
996 : : txq_ctrl->txq.inlen_mode, max_inline, priv->dev_data->port_id);
997 : : }
998 [ # # ]: 0 : if (txq_ctrl->txq.inlen_send > max_inline &&
999 [ # # ]: 0 : config->txq_inline_max != MLX5_ARG_UNSET &&
1000 [ # # ]: 0 : config->txq_inline_max > (int)max_inline) {
1001 : 0 : DRV_LOG(WARNING,
1002 : : "txq_inline_max requirements (%u) are not satisfied (%u) on port %u",
1003 : : txq_ctrl->txq.inlen_send, max_inline, priv->dev_data->port_id);
1004 : : }
1005 [ # # ]: 0 : if (txq_ctrl->txq.inlen_empw > max_inline &&
1006 [ # # ]: 0 : config->txq_inline_mpw != MLX5_ARG_UNSET &&
1007 [ # # ]: 0 : config->txq_inline_mpw > (int)max_inline) {
1008 : 0 : DRV_LOG(WARNING,
1009 : : "txq_inline_mpw requirements (%u) are not satisfied (%u) on port %u",
1010 : : txq_ctrl->txq.inlen_empw, max_inline, priv->dev_data->port_id);
1011 : : }
1012 [ # # # # ]: 0 : if (txq_ctrl->txq.tso_en && max_inline < MLX5_MAX_TSO_HEADER) {
1013 : 0 : DRV_LOG(WARNING,
1014 : : "tso header inline requirements (%u) are not satisfied (%u) on port %u",
1015 : : MLX5_MAX_TSO_HEADER, max_inline, priv->dev_data->port_id);
1016 : : }
1017 [ # # ]: 0 : if (txq_ctrl->txq.inlen_send > max_inline) {
1018 : 0 : DRV_LOG(WARNING,
1019 : : "adjust txq_inline_max (%u->%u) due to large Tx queue on port %u",
1020 : : txq_ctrl->txq.inlen_send, max_inline, priv->dev_data->port_id);
1021 : 0 : txq_ctrl->txq.inlen_send = max_inline;
1022 : : }
1023 [ # # ]: 0 : if (txq_ctrl->txq.inlen_empw > max_inline) {
1024 : 0 : DRV_LOG(WARNING,
1025 : : "adjust txq_inline_mpw (%u->%u) due to large Tx queue on port %u",
1026 : : txq_ctrl->txq.inlen_empw, max_inline, priv->dev_data->port_id);
1027 : 0 : txq_ctrl->txq.inlen_empw = max_inline;
1028 : : }
1029 : 0 : txq_ctrl->max_inline_data = RTE_MAX(txq_ctrl->txq.inlen_send,
1030 : : txq_ctrl->txq.inlen_empw);
1031 : : MLX5_ASSERT(txq_ctrl->txq.inlen_mode <= txq_ctrl->txq.inlen_send);
1032 : : MLX5_ASSERT(txq_ctrl->txq.inlen_mode <= txq_ctrl->txq.inlen_empw ||
1033 : : !txq_ctrl->txq.inlen_empw);
1034 : : }
1035 : :
1036 : : /*
1037 : : * Calculate WQ memory length for a Tx queue.
1038 : : *
1039 : : * @param log_wqe_cnt
1040 : : * Logarithm value of WQE numbers.
1041 : : *
1042 : : * @return
1043 : : * memory length of this WQ.
1044 : : */
1045 : : static uint32_t mlx5_txq_wq_mem_length(uint32_t log_wqe_cnt)
1046 : : {
1047 : : uint32_t num_of_wqbbs = 1U << log_wqe_cnt;
1048 : : uint32_t umem_size;
1049 : :
1050 : 0 : umem_size = MLX5_WQE_SIZE * num_of_wqbbs;
1051 : : return umem_size;
1052 : : }
1053 : :
1054 : : /*
1055 : : * Calculate CQ memory length for a Tx queue.
1056 : : *
1057 : : * @param dev
1058 : : * Pointer to Ethernet device.
1059 : : * @param txq_ctrl
1060 : : * Pointer to the TxQ control structure of the CQ.
1061 : : *
1062 : : * @return
1063 : : * memory length of this CQ.
1064 : : */
1065 : : static uint32_t
1066 : 0 : mlx5_txq_cq_mem_length(struct rte_eth_dev *dev, struct mlx5_txq_ctrl *txq_ctrl)
1067 : : {
1068 : : uint32_t cqe_n, log_desc_n;
1069 : :
1070 : : if (__rte_trace_point_fp_is_enabled() &&
1071 : : txq_ctrl->txq.offloads & RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP)
1072 : : cqe_n = UINT16_MAX / 2 - 1;
1073 : : else
1074 : 0 : cqe_n = (1UL << txq_ctrl->txq.elts_n) / MLX5_TX_COMP_THRESH +
1075 : 0 : 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
1076 : : log_desc_n = log2above(cqe_n);
1077 : 0 : cqe_n = 1UL << log_desc_n;
1078 [ # # ]: 0 : if (cqe_n > UINT16_MAX) {
1079 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u requests to many CQEs %u.",
1080 : : dev->data->port_id, txq_ctrl->txq.idx, cqe_n);
1081 : 0 : rte_errno = EINVAL;
1082 : 0 : return 0;
1083 : : }
1084 : 0 : return sizeof(struct mlx5_cqe) * cqe_n;
1085 : : }
1086 : :
1087 : : /**
1088 : : * Create a DPDK Tx queue.
1089 : : *
1090 : : * @param dev
1091 : : * Pointer to Ethernet device.
1092 : : * @param idx
1093 : : * TX queue index.
1094 : : * @param desc
1095 : : * Number of descriptors to configure in queue.
1096 : : * @param socket
1097 : : * NUMA socket on which memory must be allocated.
1098 : : * @param[in] conf
1099 : : * Thresholds parameters.
1100 : : *
1101 : : * @return
1102 : : * A DPDK queue object on success, NULL otherwise and rte_errno is set.
1103 : : */
1104 : : struct mlx5_txq_ctrl *
1105 : 0 : mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1106 : : unsigned int socket, const struct rte_eth_txconf *conf)
1107 : : {
1108 : : int ret;
1109 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1110 : : struct mlx5_txq_ctrl *tmpl;
1111 : : uint16_t max_wqe;
1112 : : uint32_t wqebb_cnt, log_desc_n;
1113 : :
1114 [ # # ]: 0 : if (socket != (unsigned int)SOCKET_ID_ANY) {
1115 : 0 : tmpl = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl) +
1116 : : desc * sizeof(struct rte_mbuf *), 0, socket);
1117 : : } else {
1118 [ # # # # : 0 : tmpl = mlx5_malloc_numa_tolerant(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl) +
# # ]
1119 : : desc * sizeof(struct rte_mbuf *), 0,
1120 : : dev->device->numa_node);
1121 : : }
1122 [ # # ]: 0 : if (!tmpl) {
1123 : 0 : rte_errno = ENOMEM;
1124 : 0 : return NULL;
1125 : : }
1126 [ # # ]: 0 : if (socket != (unsigned int)SOCKET_ID_ANY) {
1127 [ # # ]: 0 : if (mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1128 : 0 : &priv->sh->cdev->mr_scache.dev_gen, socket))
1129 : : /* rte_errno is already set. */
1130 : 0 : goto error;
1131 : : } else {
1132 : 0 : ret = mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1133 : 0 : &priv->sh->cdev->mr_scache.dev_gen, dev->device->numa_node);
1134 [ # # ]: 0 : if (ret == -ENOMEM) {
1135 : 0 : ret = mlx5_mr_ctrl_init(&tmpl->txq.mr_ctrl,
1136 : 0 : &priv->sh->cdev->mr_scache.dev_gen, SOCKET_ID_ANY);
1137 : : }
1138 [ # # ]: 0 : if (ret)
1139 : : /* rte_errno is already set. */
1140 : 0 : goto error;
1141 : : }
1142 : : MLX5_ASSERT(desc > MLX5_TX_COMP_THRESH);
1143 : 0 : tmpl->txq.offloads = conf->offloads |
1144 : 0 : dev->data->dev_conf.txmode.offloads;
1145 : 0 : tmpl->priv = priv;
1146 : 0 : tmpl->socket = (socket == (unsigned int)SOCKET_ID_ANY ?
1147 [ # # ]: 0 : (unsigned int)dev->device->numa_node : socket);
1148 : 0 : tmpl->txq.elts_n = log2above(desc);
1149 : 0 : tmpl->txq.elts_s = desc;
1150 : 0 : tmpl->txq.elts_m = desc - 1;
1151 : 0 : tmpl->txq.port_id = dev->data->port_id;
1152 : 0 : tmpl->txq.idx = idx;
1153 : 0 : txq_set_params(tmpl);
1154 : 0 : txq_adjust_params(tmpl);
1155 : : wqebb_cnt = txq_calc_wqebb_cnt(tmpl);
1156 : 0 : max_wqe = mlx5_dev_get_max_wq_size(priv->sh);
1157 [ # # ]: 0 : if (wqebb_cnt > max_wqe) {
1158 : 0 : DRV_LOG(ERR,
1159 : : "port %u Tx WQEBB count (%d) exceeds the limit (%d),"
1160 : : " try smaller queue size",
1161 : : dev->data->port_id, wqebb_cnt, max_wqe);
1162 : 0 : rte_errno = ENOMEM;
1163 : 0 : goto error;
1164 : : }
1165 [ # # ]: 0 : if (priv->sh->config.txq_mem_algn != 0) {
1166 : : log_desc_n = log2above(wqebb_cnt);
1167 : 0 : tmpl->txq.sq_mem_len = mlx5_txq_wq_mem_length(log_desc_n);
1168 : 0 : tmpl->txq.cq_mem_len = mlx5_txq_cq_mem_length(dev, tmpl);
1169 : 0 : DRV_LOG(DEBUG, "Port %u TxQ %u WQ length %u, CQ length %u before align.",
1170 : : dev->data->port_id, idx, tmpl->txq.sq_mem_len, tmpl->txq.cq_mem_len);
1171 : 0 : priv->consec_tx_mem.sq_total_size += tmpl->txq.sq_mem_len;
1172 : 0 : priv->consec_tx_mem.cq_total_size += tmpl->txq.cq_mem_len;
1173 : : }
1174 : 0 : rte_atomic_fetch_add_explicit(&tmpl->refcnt, 1, rte_memory_order_relaxed);
1175 : 0 : tmpl->is_hairpin = false;
1176 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
1177 : 0 : return tmpl;
1178 : 0 : error:
1179 : 0 : mlx5_mr_btree_free(&tmpl->txq.mr_ctrl.cache_bh);
1180 : 0 : mlx5_free(tmpl);
1181 : 0 : return NULL;
1182 : : }
1183 : :
1184 : : /**
1185 : : * Create a DPDK Tx hairpin queue.
1186 : : *
1187 : : * @param dev
1188 : : * Pointer to Ethernet device.
1189 : : * @param idx
1190 : : * TX queue index.
1191 : : * @param desc
1192 : : * Number of descriptors to configure in queue.
1193 : : * @param hairpin_conf
1194 : : * The hairpin configuration.
1195 : : *
1196 : : * @return
1197 : : * A DPDK queue object on success, NULL otherwise and rte_errno is set.
1198 : : */
1199 : : struct mlx5_txq_ctrl *
1200 : 0 : mlx5_txq_hairpin_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
1201 : : const struct rte_eth_hairpin_conf *hairpin_conf)
1202 : : {
1203 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1204 : : struct mlx5_txq_ctrl *tmpl;
1205 : :
1206 : 0 : tmpl = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, sizeof(*tmpl), 0,
1207 : : SOCKET_ID_ANY);
1208 [ # # ]: 0 : if (!tmpl) {
1209 : 0 : rte_errno = ENOMEM;
1210 : 0 : return NULL;
1211 : : }
1212 : 0 : tmpl->priv = priv;
1213 : 0 : tmpl->socket = SOCKET_ID_ANY;
1214 : 0 : tmpl->txq.elts_n = log2above(desc);
1215 : 0 : tmpl->txq.port_id = dev->data->port_id;
1216 : 0 : tmpl->txq.idx = idx;
1217 : 0 : tmpl->hairpin_conf = *hairpin_conf;
1218 : 0 : tmpl->is_hairpin = true;
1219 : 0 : rte_atomic_fetch_add_explicit(&tmpl->refcnt, 1, rte_memory_order_relaxed);
1220 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->txqsctrl, tmpl, next);
1221 : 0 : return tmpl;
1222 : : }
1223 : :
1224 : : /**
1225 : : * Get a Tx queue.
1226 : : *
1227 : : * @param dev
1228 : : * Pointer to Ethernet device.
1229 : : * @param idx
1230 : : * TX queue index.
1231 : : *
1232 : : * @return
1233 : : * A pointer to the queue if it exists.
1234 : : */
1235 : : struct mlx5_txq_ctrl *
1236 : 0 : mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx)
1237 : : {
1238 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1239 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1240 : : struct mlx5_txq_ctrl *ctrl = NULL;
1241 : :
1242 [ # # ]: 0 : if (txq_data) {
1243 : 0 : ctrl = container_of(txq_data, struct mlx5_txq_ctrl, txq);
1244 : 0 : rte_atomic_fetch_add_explicit(&ctrl->refcnt, 1, rte_memory_order_relaxed);
1245 : : }
1246 : 0 : return ctrl;
1247 : : }
1248 : :
1249 : : /**
1250 : : * Get an external Tx queue.
1251 : : *
1252 : : * @param dev
1253 : : * Pointer to Ethernet device.
1254 : : * @param idx
1255 : : * External Tx queue index.
1256 : : *
1257 : : * @return
1258 : : * A pointer to the queue if it exists, NULL otherwise.
1259 : : */
1260 : : struct mlx5_external_q *
1261 : 0 : mlx5_ext_txq_get(struct rte_eth_dev *dev, uint16_t idx)
1262 : : {
1263 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1264 : :
1265 : : MLX5_ASSERT(mlx5_is_external_txq(dev, idx));
1266 : 0 : return &priv->ext_txqs[idx - MLX5_EXTERNAL_TX_QUEUE_ID_MIN];
1267 : : }
1268 : :
1269 : : /**
1270 : : * Verify the external Tx Queue list is empty.
1271 : : *
1272 : : * @param dev
1273 : : * Pointer to Ethernet device.
1274 : : *
1275 : : * @return
1276 : : * The number of object not released.
1277 : : */
1278 : : int
1279 : 0 : mlx5_ext_txq_verify(struct rte_eth_dev *dev)
1280 : : {
1281 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1282 : : struct mlx5_external_q *txq;
1283 : : uint32_t i;
1284 : : int ret = 0;
1285 : :
1286 [ # # ]: 0 : if (priv->ext_txqs == NULL)
1287 : : return 0;
1288 : :
1289 [ # # ]: 0 : for (i = MLX5_EXTERNAL_TX_QUEUE_ID_MIN; i <= UINT16_MAX ; ++i) {
1290 : 0 : txq = mlx5_ext_txq_get(dev, i);
1291 [ # # ]: 0 : if (txq->refcnt < 2)
1292 : 0 : continue;
1293 : 0 : DRV_LOG(DEBUG, "Port %u external TxQ %u still referenced.",
1294 : : dev->data->port_id, i);
1295 : 0 : ++ret;
1296 : : }
1297 : : return ret;
1298 : : }
1299 : :
1300 : : /**
1301 : : * Release a Tx queue.
1302 : : *
1303 : : * @param dev
1304 : : * Pointer to Ethernet device.
1305 : : * @param idx
1306 : : * TX queue index.
1307 : : *
1308 : : * @return
1309 : : * 1 while a reference on it exists, 0 when freed.
1310 : : */
1311 : : int
1312 : 0 : mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx)
1313 : : {
1314 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1315 : : struct mlx5_txq_ctrl *txq_ctrl;
1316 : :
1317 [ # # # # ]: 0 : if (priv->txqs == NULL || (*priv->txqs)[idx] == NULL)
1318 : : return 0;
1319 : 0 : txq_ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
1320 [ # # ]: 0 : if (rte_atomic_fetch_sub_explicit(&txq_ctrl->refcnt, 1, rte_memory_order_relaxed) - 1 > 1)
1321 : : return 1;
1322 [ # # ]: 0 : if (txq_ctrl->obj) {
1323 : 0 : priv->obj_ops.txq_obj_release(txq_ctrl->obj);
1324 [ # # ]: 0 : LIST_REMOVE(txq_ctrl->obj, next);
1325 : 0 : mlx5_free(txq_ctrl->obj);
1326 : 0 : txq_ctrl->obj = NULL;
1327 : : }
1328 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
1329 [ # # ]: 0 : if (txq_ctrl->txq.fcqs) {
1330 : 0 : mlx5_free(txq_ctrl->txq.fcqs);
1331 : 0 : txq_ctrl->txq.fcqs = NULL;
1332 : : }
1333 : 0 : txq_free_elts(txq_ctrl);
1334 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STOPPED;
1335 : : }
1336 [ # # ]: 0 : if (!rte_atomic_load_explicit(&txq_ctrl->refcnt, rte_memory_order_relaxed)) {
1337 [ # # ]: 0 : if (!txq_ctrl->is_hairpin)
1338 : 0 : mlx5_mr_btree_free(&txq_ctrl->txq.mr_ctrl.cache_bh);
1339 [ # # ]: 0 : LIST_REMOVE(txq_ctrl, next);
1340 : 0 : mlx5_free(txq_ctrl);
1341 : 0 : (*priv->txqs)[idx] = NULL;
1342 : : }
1343 : : return 0;
1344 : : }
1345 : :
1346 : : /**
1347 : : * Verify if the queue can be released.
1348 : : *
1349 : : * @param dev
1350 : : * Pointer to Ethernet device.
1351 : : * @param idx
1352 : : * TX queue index.
1353 : : *
1354 : : * @return
1355 : : * 1 if the queue can be released.
1356 : : */
1357 : : int
1358 : 0 : mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx)
1359 : : {
1360 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1361 : : struct mlx5_txq_ctrl *txq;
1362 : :
1363 [ # # ]: 0 : if (!(*priv->txqs)[idx])
1364 : : return -1;
1365 : 0 : txq = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq);
1366 : 0 : return (rte_atomic_load_explicit(&txq->refcnt, rte_memory_order_relaxed) == 1);
1367 : : }
1368 : :
1369 : : /**
1370 : : * Verify the Tx Queue list is empty
1371 : : *
1372 : : * @param dev
1373 : : * Pointer to Ethernet device.
1374 : : *
1375 : : * @return
1376 : : * The number of object not released.
1377 : : */
1378 : : int
1379 : 0 : mlx5_txq_verify(struct rte_eth_dev *dev)
1380 : : {
1381 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1382 : : struct mlx5_txq_ctrl *txq_ctrl;
1383 : : int ret = 0;
1384 : :
1385 [ # # ]: 0 : LIST_FOREACH(txq_ctrl, &priv->txqsctrl, next) {
1386 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %u still referenced",
1387 : : dev->data->port_id, txq_ctrl->txq.idx);
1388 : 0 : ++ret;
1389 : : }
1390 : 0 : return ret;
1391 : : }
1392 : :
1393 : : int
1394 : 0 : mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq)
1395 : : {
1396 [ # # ]: 0 : return txq->is_hairpin ? txq->obj->sq->id : txq->obj->sq_obj.sq->id;
1397 : : }
1398 : :
1399 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_sq_enable, 22.07)
1400 : : int
1401 : 0 : rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num)
1402 : : {
1403 : : struct rte_eth_dev *dev;
1404 : : struct mlx5_priv *priv;
1405 : : uint32_t flow;
1406 : :
1407 [ # # ]: 0 : if (rte_eth_dev_is_valid_port(port_id) < 0) {
1408 : 0 : DRV_LOG(ERR, "There is no Ethernet device for port %u.",
1409 : : port_id);
1410 : 0 : rte_errno = ENODEV;
1411 : 0 : return -rte_errno;
1412 : : }
1413 : 0 : dev = &rte_eth_devices[port_id];
1414 : 0 : priv = dev->data->dev_private;
1415 [ # # ]: 0 : if ((!priv->representor && !priv->master) ||
1416 [ # # ]: 0 : !priv->sh->config.dv_esw_en) {
1417 : 0 : DRV_LOG(ERR, "Port %u must be represetnor or master port in E-Switch mode.",
1418 : : port_id);
1419 : 0 : rte_errno = EINVAL;
1420 : 0 : return -rte_errno;
1421 : : }
1422 [ # # ]: 0 : if (sq_num == 0) {
1423 : 0 : DRV_LOG(ERR, "Invalid SQ number.");
1424 : 0 : rte_errno = EINVAL;
1425 : 0 : return -rte_errno;
1426 : : }
1427 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1428 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1429 : : bool sq_miss_created = false;
1430 : :
1431 [ # # ]: 0 : if (priv->sh->config.fdb_def_rule) {
1432 [ # # ]: 0 : if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, sq_num, true))
1433 : 0 : return -rte_errno;
1434 : : sq_miss_created = true;
1435 : : }
1436 : :
1437 [ # # # # ]: 0 : if (priv->sh->config.repr_matching &&
1438 : 0 : mlx5_flow_hw_tx_repr_matching_flow(dev, sq_num, true)) {
1439 [ # # ]: 0 : if (sq_miss_created)
1440 : 0 : mlx5_flow_hw_esw_destroy_sq_miss_flow(dev, sq_num);
1441 : 0 : return -rte_errno;
1442 : : }
1443 : 0 : return 0;
1444 : : }
1445 : : #endif
1446 : 0 : flow = mlx5_flow_create_devx_sq_miss_flow(dev, sq_num);
1447 [ # # ]: 0 : if (flow > 0)
1448 : : return 0;
1449 : 0 : DRV_LOG(ERR, "Port %u failed to create default miss flow for SQ %u.",
1450 : : port_id, sq_num);
1451 : 0 : return -rte_errno;
1452 : : }
1453 : :
1454 : : /**
1455 : : * Set the Tx queue dynamic timestamp (mask and offset)
1456 : : *
1457 : : * @param[in] dev
1458 : : * Pointer to the Ethernet device structure.
1459 : : */
1460 : : void
1461 : 0 : mlx5_txq_dynf_timestamp_set(struct rte_eth_dev *dev)
1462 : : {
1463 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1464 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1465 : : struct mlx5_txq_data *data;
1466 : : int off, nbit;
1467 : : unsigned int i;
1468 : : uint64_t mask = 0;
1469 : : uint64_t ts_mask;
1470 : :
1471 [ # # ]: 0 : if (sh->dev_cap.rt_timestamp ||
1472 [ # # ]: 0 : !sh->cdev->config.hca_attr.dev_freq_khz)
1473 : : ts_mask = MLX5_TS_MASK_SECS << 32;
1474 : : else
1475 : 0 : ts_mask = rte_align64pow2(MLX5_TS_MASK_SECS * 1000ull *
1476 : 0 : sh->cdev->config.hca_attr.dev_freq_khz);
1477 [ # # ]: 0 : ts_mask = rte_cpu_to_be_64(ts_mask - 1ull);
1478 : 0 : nbit = rte_mbuf_dynflag_lookup
1479 : : (RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, NULL);
1480 : 0 : off = rte_mbuf_dynfield_lookup
1481 : : (RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL);
1482 [ # # ]: 0 : if (nbit >= 0 && off >= 0 &&
1483 [ # # # # ]: 0 : (sh->txpp.refcnt || priv->sh->cdev->config.hca_attr.wait_on_time))
1484 : 0 : mask = 1ULL << nbit;
1485 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
1486 : 0 : data = (*priv->txqs)[i];
1487 [ # # ]: 0 : if (!data)
1488 : 0 : continue;
1489 : 0 : data->sh = sh;
1490 : 0 : data->ts_mask = mask;
1491 : 0 : data->ts_offset = off;
1492 : 0 : data->rt_timestamp = sh->dev_cap.rt_timestamp;
1493 : 0 : data->rt_timemask = (data->offloads &
1494 : : RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP) ?
1495 [ # # ]: 0 : ts_mask : 0;
1496 : : }
1497 : 0 : }
1498 : :
1499 : 0 : int mlx5_count_aggr_ports(struct rte_eth_dev *dev)
1500 : : {
1501 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1502 : :
1503 : 0 : return priv->sh->bond.n_port;
1504 : : }
1505 : :
1506 : 0 : int mlx5_map_aggr_tx_affinity(struct rte_eth_dev *dev, uint16_t tx_queue_id,
1507 : : uint8_t affinity)
1508 : : {
1509 : : struct mlx5_txq_ctrl *txq_ctrl;
1510 : : struct mlx5_txq_data *txq;
1511 : : struct mlx5_priv *priv;
1512 : :
1513 : 0 : priv = dev->data->dev_private;
1514 [ # # # # ]: 0 : if (!mlx5_devx_obj_ops_en(priv->sh)) {
1515 : 0 : DRV_LOG(ERR, "Tx affinity mapping isn't supported by Verbs API.");
1516 : 0 : rte_errno = ENOTSUP;
1517 : 0 : return -rte_errno;
1518 : : }
1519 : 0 : txq = (*priv->txqs)[tx_queue_id];
1520 [ # # ]: 0 : if (!txq)
1521 : : return -1;
1522 : 0 : txq_ctrl = container_of(txq, struct mlx5_txq_ctrl, txq);
1523 [ # # ]: 0 : if (tx_queue_id >= priv->txqs_n) {
1524 : 0 : DRV_LOG(ERR, "port %u Tx queue index out of range (%u >= %u)",
1525 : : dev->data->port_id, tx_queue_id, priv->txqs_n);
1526 : 0 : rte_errno = EOVERFLOW;
1527 : 0 : return -rte_errno;
1528 : : }
1529 [ # # ]: 0 : if (affinity > priv->num_lag_ports) {
1530 : 0 : DRV_LOG(ERR, "port %u unable to setup Tx queue index %u"
1531 : : " affinity is %u exceeds the maximum %u", dev->data->port_id,
1532 : : tx_queue_id, affinity, priv->num_lag_ports);
1533 : 0 : rte_errno = EINVAL;
1534 : 0 : return -rte_errno;
1535 : : }
1536 : 0 : DRV_LOG(DEBUG, "port %u configuring queue %u for aggregated affinity %u",
1537 : : dev->data->port_id, tx_queue_id, affinity);
1538 : 0 : txq_ctrl->txq.tx_aggr_affinity = affinity;
1539 : 0 : return 0;
1540 : : }
1541 : :
1542 : : /**
1543 : : * Validate given external TxQ rte_flow index, and get pointer to concurrent
1544 : : * external TxQ object to map/unmap.
1545 : : *
1546 : : * @param[in] port_id
1547 : : * The port identifier of the Ethernet device.
1548 : : * @param[in] dpdk_idx
1549 : : * Tx Queue index in rte_flow.
1550 : : *
1551 : : * @return
1552 : : * Pointer to concurrent external TxQ on success,
1553 : : * NULL otherwise and rte_errno is set.
1554 : : */
1555 : : static struct mlx5_external_q *
1556 : 0 : mlx5_external_tx_queue_get_validate(uint16_t port_id, uint16_t dpdk_idx)
1557 : : {
1558 : : struct rte_eth_dev *dev;
1559 : : struct mlx5_priv *priv;
1560 : : int ret;
1561 : :
1562 [ # # ]: 0 : if (dpdk_idx < MLX5_EXTERNAL_TX_QUEUE_ID_MIN) {
1563 : 0 : DRV_LOG(ERR, "Queue index %u should be in range: [%u, %u].",
1564 : : dpdk_idx, MLX5_EXTERNAL_TX_QUEUE_ID_MIN, UINT16_MAX);
1565 : 0 : rte_errno = EINVAL;
1566 : 0 : return NULL;
1567 : : }
1568 : 0 : ret = mlx5_devx_extq_port_validate(port_id);
1569 [ # # ]: 0 : if (unlikely(ret))
1570 : : return NULL;
1571 : : dev = &rte_eth_devices[port_id];
1572 : 0 : priv = dev->data->dev_private;
1573 : : /*
1574 : : * When user configures remote PD and CTX and device creates TxQ by
1575 : : * DevX, external TxQs array is allocated.
1576 : : */
1577 : : MLX5_ASSERT(priv->ext_txqs != NULL);
1578 : 0 : return &priv->ext_txqs[dpdk_idx - MLX5_EXTERNAL_TX_QUEUE_ID_MIN];
1579 : : }
1580 : :
1581 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_tx_queue_id_map, 24.07)
1582 : : int
1583 : 0 : rte_pmd_mlx5_external_tx_queue_id_map(uint16_t port_id, uint16_t dpdk_idx,
1584 : : uint32_t hw_idx)
1585 : : {
1586 : : struct mlx5_external_q *ext_txq;
1587 : : uint32_t unmapped = 0;
1588 : :
1589 : 0 : ext_txq = mlx5_external_tx_queue_get_validate(port_id, dpdk_idx);
1590 [ # # ]: 0 : if (ext_txq == NULL)
1591 : 0 : return -rte_errno;
1592 [ # # ]: 0 : if (!rte_atomic_compare_exchange_strong_explicit(&ext_txq->refcnt, &unmapped, 1,
1593 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
1594 [ # # ]: 0 : if (ext_txq->hw_id != hw_idx) {
1595 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u "
1596 : : "is already mapped to HW index (requesting is "
1597 : : "%u, existing is %u).",
1598 : : port_id, dpdk_idx, hw_idx, ext_txq->hw_id);
1599 : 0 : rte_errno = EEXIST;
1600 : 0 : return -rte_errno;
1601 : : }
1602 : 0 : DRV_LOG(WARNING, "Port %u external TxQ index %u "
1603 : : "is already mapped to the requested HW index (%u)",
1604 : : port_id, dpdk_idx, hw_idx);
1605 : :
1606 : : } else {
1607 : 0 : ext_txq->hw_id = hw_idx;
1608 : 0 : DRV_LOG(DEBUG, "Port %u external TxQ index %u "
1609 : : "is successfully mapped to the requested HW index (%u)",
1610 : : port_id, dpdk_idx, hw_idx);
1611 : : }
1612 : : return 0;
1613 : : }
1614 : :
1615 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_pmd_mlx5_external_tx_queue_id_unmap, 24.07)
1616 : : int
1617 : 0 : rte_pmd_mlx5_external_tx_queue_id_unmap(uint16_t port_id, uint16_t dpdk_idx)
1618 : : {
1619 : : struct mlx5_external_q *ext_txq;
1620 : : uint32_t mapped = 1;
1621 : :
1622 : 0 : ext_txq = mlx5_external_tx_queue_get_validate(port_id, dpdk_idx);
1623 [ # # ]: 0 : if (ext_txq == NULL)
1624 : 0 : return -rte_errno;
1625 [ # # ]: 0 : if (ext_txq->refcnt > 1) {
1626 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u still referenced.",
1627 : : port_id, dpdk_idx);
1628 : 0 : rte_errno = EINVAL;
1629 : 0 : return -rte_errno;
1630 : : }
1631 [ # # ]: 0 : if (!rte_atomic_compare_exchange_strong_explicit(&ext_txq->refcnt, &mapped, 0,
1632 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
1633 : 0 : DRV_LOG(ERR, "Port %u external TxQ index %u doesn't exist.",
1634 : : port_id, dpdk_idx);
1635 : 0 : rte_errno = EINVAL;
1636 : 0 : return -rte_errno;
1637 : : }
1638 : 0 : DRV_LOG(DEBUG,
1639 : : "Port %u external TxQ index %u is successfully unmapped.",
1640 : : port_id, dpdk_idx);
1641 : 0 : return 0;
1642 : : }
|