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