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 <unistd.h>
7 : :
8 : : #include <rte_ether.h>
9 : : #include <ethdev_driver.h>
10 : : #include <rte_interrupts.h>
11 : : #include <rte_alarm.h>
12 : : #include <rte_cycles.h>
13 : :
14 : : #include <mlx5_malloc.h>
15 : :
16 : : #include "mlx5.h"
17 : : #include "mlx5_flow.h"
18 : : #include "mlx5_rx.h"
19 : : #include "mlx5_tx.h"
20 : : #include "mlx5_utils.h"
21 : : #include "rte_pmd_mlx5.h"
22 : :
23 : : static void mlx5_traffic_disable_legacy(struct rte_eth_dev *dev);
24 : :
25 : : /**
26 : : * Stop traffic on Tx queues.
27 : : *
28 : : * @param dev
29 : : * Pointer to Ethernet device structure.
30 : : */
31 : : static void
32 : 0 : mlx5_txq_stop(struct rte_eth_dev *dev)
33 : : {
34 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
35 : : unsigned int i;
36 : :
37 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i)
38 : 0 : mlx5_txq_release(dev, i);
39 : 0 : }
40 : :
41 : : /**
42 : : * Start traffic on Tx queues.
43 : : *
44 : : * @param dev
45 : : * Pointer to Ethernet device structure.
46 : : *
47 : : * @return
48 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
49 : : */
50 : : static int
51 : 0 : mlx5_txq_start(struct rte_eth_dev *dev)
52 : : {
53 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
54 : 0 : uint32_t log_max_wqe = log2above(mlx5_dev_get_max_wq_size(priv->sh));
55 : : uint32_t flags = MLX5_MEM_RTE | MLX5_MEM_ZERO;
56 : : unsigned int i, cnt;
57 : : int ret;
58 : :
59 [ # # ]: 0 : for (cnt = log_max_wqe; cnt > 0; cnt -= 1) {
60 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
61 : 0 : struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
62 : : struct mlx5_txq_data *txq_data;
63 : :
64 [ # # ]: 0 : if (!txq_ctrl)
65 : 0 : continue;
66 : : txq_data = &txq_ctrl->txq;
67 [ # # ]: 0 : if (txq_data->elts_n != cnt) {
68 : 0 : mlx5_txq_release(dev, i);
69 : 0 : continue;
70 : : }
71 [ # # ]: 0 : if (!txq_ctrl->is_hairpin)
72 : 0 : mlx5_txq_alloc_elts(txq_ctrl);
73 : : MLX5_ASSERT(!txq_ctrl->obj);
74 [ # # # # : 0 : txq_ctrl->obj = mlx5_malloc_numa_tolerant(flags,
# # ]
75 : : sizeof(struct mlx5_txq_obj),
76 : : 0, txq_ctrl->socket);
77 [ # # ]: 0 : if (!txq_ctrl->obj) {
78 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u cannot allocate "
79 : : "memory resources.", dev->data->port_id,
80 : : txq_data->idx);
81 : 0 : rte_errno = ENOMEM;
82 : 0 : goto error;
83 : : }
84 : 0 : ret = priv->obj_ops.txq_obj_new(dev, i);
85 [ # # ]: 0 : if (ret < 0) {
86 : 0 : mlx5_free(txq_ctrl->obj);
87 : 0 : txq_ctrl->obj = NULL;
88 : 0 : goto error;
89 : : }
90 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
91 : 0 : size_t size = txq_data->cqe_s * sizeof(*txq_data->fcqs);
92 : :
93 [ # # # # : 0 : txq_data->fcqs = mlx5_malloc_numa_tolerant(flags, size,
# # ]
94 : : RTE_CACHE_LINE_SIZE,
95 : : txq_ctrl->socket);
96 [ # # ]: 0 : if (!txq_data->fcqs) {
97 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u cannot "
98 : : "allocate memory (FCQ).",
99 : : dev->data->port_id, i);
100 : 0 : priv->obj_ops.txq_obj_release(txq_ctrl->obj);
101 : 0 : mlx5_free(txq_ctrl->obj);
102 : 0 : txq_ctrl->obj = NULL;
103 : 0 : rte_errno = ENOMEM;
104 : 0 : goto error;
105 : : }
106 : : }
107 : 0 : DRV_LOG(DEBUG, "Port %u txq %u updated with %p.",
108 : : dev->data->port_id, i, (void *)&txq_ctrl->obj);
109 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->txqsobj, txq_ctrl->obj, next);
110 : : }
111 : : }
112 : : return 0;
113 : 0 : error:
114 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
115 : : do {
116 : 0 : mlx5_txq_release(dev, i);
117 [ # # ]: 0 : } while (i-- != 0);
118 : 0 : rte_errno = ret; /* Restore rte_errno. */
119 : 0 : return -rte_errno;
120 : : }
121 : :
122 : : static struct rte_mbuf *
123 : 0 : mlx5_alloc_null_mbuf(uint32_t data_len)
124 : : {
125 : 0 : size_t alloc_size = sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM +
126 : 0 : rte_align32pow2(data_len);
127 : : struct rte_mbuf *m;
128 : :
129 : 0 : m = mlx5_malloc(MLX5_MEM_ZERO, alloc_size, 0, SOCKET_ID_ANY);
130 [ # # ]: 0 : if (m == NULL)
131 : : return NULL;
132 : 0 : m->buf_addr = RTE_PTR_ADD(m, sizeof(*m));
133 : 0 : m->buf_len = alloc_size - sizeof(*m);
134 : 0 : rte_mbuf_iova_set(m, rte_mem_virt2iova(m->buf_addr));
135 : 0 : m->data_off = RTE_PKTMBUF_HEADROOM;
136 : 0 : m->refcnt = 1;
137 : 0 : m->nb_segs = 1;
138 : 0 : m->port = RTE_MBUF_PORT_INVALID;
139 : 0 : m->pool = NULL;
140 : 0 : return m;
141 : : }
142 : :
143 : : /**
144 : : * Register Rx queue mempools and fill the Rx queue cache.
145 : : * This function tolerates repeated mempool registration.
146 : : *
147 : : * @param[in] rxq_ctrl
148 : : * Rx queue control data.
149 : : *
150 : : * @return
151 : : * 0 on success, (-1) on failure and rte_errno is set.
152 : : */
153 : : static int
154 : 0 : mlx5_rxq_mempool_register(struct mlx5_rxq_ctrl *rxq_ctrl)
155 : : {
156 : : struct rte_mempool *mp;
157 : : struct mlx5_eth_rxseg *seg;
158 : : uint16_t s;
159 : : int ret = 0;
160 : :
161 : 0 : mlx5_mr_flush_local_cache(&rxq_ctrl->rxq.mr_ctrl);
162 : : /* MPRQ mempool is registered on creation, just fill the cache. */
163 [ # # ]: 0 : if (mlx5_rxq_mprq_enabled(&rxq_ctrl->rxq))
164 : 0 : return mlx5_mr_mempool_populate_cache(&rxq_ctrl->rxq.mr_ctrl,
165 : : rxq_ctrl->rxq.mprq_mp);
166 [ # # ]: 0 : for (s = 0; s < rxq_ctrl->rxq.rxseg_n; s++) {
167 : 0 : seg = &rxq_ctrl->rxq.rxseg[s];
168 : 0 : mp = seg->mp;
169 [ # # ]: 0 : if (mp) { /* Regular segment */
170 : 0 : bool is_extmem = (rte_pktmbuf_priv_flags(mp) &
171 : : RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) != 0;
172 : 0 : ret = mlx5_mr_mempool_register(rxq_ctrl->sh->cdev, mp, is_extmem);
173 [ # # # # ]: 0 : if (ret < 0 && rte_errno != EEXIST)
174 : 0 : goto error;
175 : 0 : ret = mlx5_mr_mempool_populate_cache(&rxq_ctrl->rxq.mr_ctrl, mp);
176 [ # # ]: 0 : if (ret < 0)
177 : 0 : goto error;
178 : : } else { /* NULL segment used in selective Rx */
179 : 0 : seg->null_mbuf = mlx5_alloc_null_mbuf(seg->length);
180 [ # # ]: 0 : if (seg->null_mbuf == NULL) {
181 : 0 : rte_errno = ENOMEM;
182 : : ret = -rte_errno;
183 : 0 : goto error;
184 : : }
185 : : }
186 : : }
187 : : return 0;
188 : :
189 : 0 : error:
190 [ # # ]: 0 : while (s-- > 0) {
191 : 0 : seg = &rxq_ctrl->rxq.rxseg[s];
192 : 0 : mlx5_free(seg->null_mbuf);
193 : 0 : seg->null_mbuf = NULL;
194 : : }
195 : : return ret;
196 : : }
197 : :
198 : : /**
199 : : * Stop traffic on Rx queues.
200 : : *
201 : : * @param dev
202 : : * Pointer to Ethernet device structure.
203 : : */
204 : : static void
205 : 0 : mlx5_rxq_stop(struct rte_eth_dev *dev)
206 : : {
207 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
208 : : unsigned int i;
209 : :
210 [ # # ]: 0 : for (i = 0; i != priv->rxqs_n; ++i)
211 : 0 : mlx5_rxq_release(dev, i);
212 : 0 : }
213 : :
214 : : static int
215 : 0 : mlx5_rxq_ctrl_prepare(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl,
216 : : unsigned int idx)
217 : : {
218 : : int ret = 0;
219 : :
220 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin) {
221 : : /*
222 : : * Pre-register the mempools. Regardless of whether
223 : : * the implicit registration is enabled or not,
224 : : * Rx mempool destruction is tracked to free MRs.
225 : : */
226 [ # # ]: 0 : if (mlx5_rxq_mempool_register(rxq_ctrl) < 0)
227 : 0 : return -rte_errno;
228 : 0 : ret = mlx5_rxq_alloc_elts(rxq_ctrl);
229 [ # # ]: 0 : if (ret)
230 : : return ret;
231 : : }
232 : : MLX5_ASSERT(!rxq_ctrl->obj);
233 [ # # # # : 0 : rxq_ctrl->obj = mlx5_malloc_numa_tolerant(MLX5_MEM_RTE | MLX5_MEM_ZERO,
# # ]
234 : : sizeof(*rxq_ctrl->obj), 0,
235 : : rxq_ctrl->socket);
236 [ # # ]: 0 : if (!rxq_ctrl->obj) {
237 : 0 : DRV_LOG(ERR, "Port %u Rx queue %u can't allocate resources.",
238 : : dev->data->port_id, idx);
239 : 0 : rte_errno = ENOMEM;
240 : 0 : return -rte_errno;
241 : : }
242 : 0 : DRV_LOG(DEBUG, "Port %u rxq %u updated with %p.", dev->data->port_id,
243 : : idx, (void *)&rxq_ctrl->obj);
244 : 0 : return 0;
245 : : }
246 : :
247 : : /**
248 : : * Start traffic on Rx queues.
249 : : *
250 : : * @param dev
251 : : * Pointer to Ethernet device structure.
252 : : *
253 : : * @return
254 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
255 : : */
256 : : static int
257 : 0 : mlx5_rxq_start(struct rte_eth_dev *dev)
258 : : {
259 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
260 : : unsigned int i;
261 : : int ret = 0;
262 : :
263 : : /* Allocate/reuse/resize mempool for Multi-Packet RQ. */
264 [ # # ]: 0 : if (mlx5_mprq_alloc_mp(dev)) {
265 : : /* Should not release Rx queues but return immediately. */
266 : 0 : return -rte_errno;
267 : : }
268 : 0 : DRV_LOG(DEBUG, "Port %u max work queue size is %d.",
269 : : dev->data->port_id, mlx5_dev_get_max_wq_size(priv->sh));
270 : 0 : DRV_LOG(DEBUG, "Port %u dev_cap.max_sge is %d.",
271 : : dev->data->port_id, priv->sh->dev_cap.max_sge);
272 [ # # ]: 0 : for (i = 0; i != priv->rxqs_n; ++i) {
273 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_ref(dev, i);
274 : : struct mlx5_rxq_ctrl *rxq_ctrl;
275 : :
276 [ # # ]: 0 : if (rxq == NULL)
277 : 0 : continue;
278 : 0 : rxq_ctrl = rxq->ctrl;
279 [ # # ]: 0 : if (!rxq_ctrl->started)
280 [ # # ]: 0 : if (mlx5_rxq_ctrl_prepare(dev, rxq_ctrl, i) < 0)
281 : 0 : goto error;
282 : 0 : ret = priv->obj_ops.rxq_obj_new(rxq);
283 [ # # ]: 0 : if (ret) {
284 : 0 : mlx5_free(rxq_ctrl->obj);
285 : 0 : rxq_ctrl->obj = NULL;
286 : 0 : goto error;
287 : : }
288 [ # # ]: 0 : if (!rxq_ctrl->started)
289 [ # # ]: 0 : LIST_INSERT_HEAD(&priv->rxqsobj, rxq_ctrl->obj, next);
290 : 0 : rxq_ctrl->started = true;
291 : : }
292 : : return 0;
293 : 0 : error:
294 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
295 : : do {
296 : 0 : mlx5_rxq_release(dev, i);
297 [ # # ]: 0 : } while (i-- != 0);
298 : 0 : rte_errno = ret; /* Restore rte_errno. */
299 : 0 : return -rte_errno;
300 : : }
301 : :
302 : : /**
303 : : * Binds Tx queues to Rx queues for hairpin.
304 : : *
305 : : * Binds Tx queues to the target Rx queues.
306 : : *
307 : : * @param dev
308 : : * Pointer to Ethernet device structure.
309 : : *
310 : : * @return
311 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
312 : : */
313 : : static int
314 : 0 : mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
315 : : {
316 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
317 : 0 : struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
318 : 0 : struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
319 : : struct mlx5_txq_ctrl *txq_ctrl;
320 : : struct mlx5_rxq_priv *rxq;
321 : : struct mlx5_rxq_ctrl *rxq_ctrl;
322 : : struct mlx5_devx_obj *sq;
323 : : struct mlx5_devx_obj *rq;
324 : : unsigned int i;
325 : : int ret = 0;
326 : : bool need_auto = false;
327 : 0 : uint16_t self_port = dev->data->port_id;
328 : :
329 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
330 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
331 [ # # ]: 0 : if (!txq_ctrl)
332 : 0 : continue;
333 [ # # ]: 0 : if (!txq_ctrl->is_hairpin ||
334 [ # # ]: 0 : txq_ctrl->hairpin_conf.peers[0].port != self_port) {
335 : 0 : mlx5_txq_release(dev, i);
336 : 0 : continue;
337 : : }
338 [ # # ]: 0 : if (txq_ctrl->hairpin_conf.manual_bind) {
339 : 0 : mlx5_txq_release(dev, i);
340 : 0 : return 0;
341 : : }
342 : : need_auto = true;
343 : 0 : mlx5_txq_release(dev, i);
344 : : }
345 [ # # ]: 0 : if (!need_auto)
346 : : return 0;
347 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
348 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
349 [ # # ]: 0 : if (!txq_ctrl)
350 : 0 : continue;
351 : : /* Skip hairpin queues with other peer ports. */
352 [ # # ]: 0 : if (!txq_ctrl->is_hairpin ||
353 [ # # ]: 0 : txq_ctrl->hairpin_conf.peers[0].port != self_port) {
354 : 0 : mlx5_txq_release(dev, i);
355 : 0 : continue;
356 : : }
357 [ # # ]: 0 : if (!txq_ctrl->obj) {
358 : 0 : rte_errno = ENOMEM;
359 : 0 : DRV_LOG(ERR, "port %u no txq object found: %d",
360 : : dev->data->port_id, i);
361 : 0 : mlx5_txq_release(dev, i);
362 : 0 : return -rte_errno;
363 : : }
364 : 0 : sq = txq_ctrl->obj->sq;
365 : 0 : rxq = mlx5_rxq_get(dev, txq_ctrl->hairpin_conf.peers[0].queue);
366 [ # # ]: 0 : if (rxq == NULL) {
367 : 0 : mlx5_txq_release(dev, i);
368 : 0 : rte_errno = EINVAL;
369 : 0 : DRV_LOG(ERR, "port %u no rxq object found: %d",
370 : : dev->data->port_id,
371 : : txq_ctrl->hairpin_conf.peers[0].queue);
372 : 0 : return -rte_errno;
373 : : }
374 : 0 : rxq_ctrl = rxq->ctrl;
375 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin ||
376 [ # # ]: 0 : rxq->hairpin_conf.peers[0].queue != i) {
377 : 0 : rte_errno = ENOMEM;
378 : 0 : DRV_LOG(ERR, "port %u Tx queue %d can't be binded to "
379 : : "Rx queue %d", dev->data->port_id,
380 : : i, txq_ctrl->hairpin_conf.peers[0].queue);
381 : 0 : goto error;
382 : : }
383 : 0 : rq = rxq_ctrl->obj->rq;
384 [ # # ]: 0 : if (!rq) {
385 : 0 : rte_errno = ENOMEM;
386 : 0 : DRV_LOG(ERR, "port %u hairpin no matching rxq: %d",
387 : : dev->data->port_id,
388 : : txq_ctrl->hairpin_conf.peers[0].queue);
389 : 0 : goto error;
390 : : }
391 : 0 : sq_attr.state = MLX5_SQC_STATE_RDY;
392 : 0 : sq_attr.sq_state = MLX5_SQC_STATE_RST;
393 : 0 : sq_attr.hairpin_peer_rq = rq->id;
394 : 0 : sq_attr.hairpin_peer_vhca =
395 : 0 : priv->sh->cdev->config.hca_attr.vhca_id;
396 : 0 : ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr);
397 [ # # ]: 0 : if (ret)
398 : 0 : goto error;
399 : 0 : rq_attr.state = MLX5_RQC_STATE_RDY;
400 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RST;
401 : 0 : rq_attr.hairpin_peer_sq = sq->id;
402 : 0 : rq_attr.hairpin_peer_vhca =
403 : 0 : priv->sh->cdev->config.hca_attr.vhca_id;
404 : 0 : ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
405 [ # # ]: 0 : if (ret)
406 : 0 : goto error;
407 : : /* Qs with auto-bind will be destroyed directly. */
408 : 0 : rxq->hairpin_status = 1;
409 : 0 : txq_ctrl->hairpin_status = 1;
410 : 0 : mlx5_txq_release(dev, i);
411 : : }
412 : : return 0;
413 : 0 : error:
414 : 0 : mlx5_txq_release(dev, i);
415 : 0 : return -rte_errno;
416 : : }
417 : :
418 : : /*
419 : : * Fetch the peer queue's SW & HW information.
420 : : *
421 : : * @param dev
422 : : * Pointer to Ethernet device structure.
423 : : * @param peer_queue
424 : : * Index of the queue to fetch the information.
425 : : * @param current_info
426 : : * Pointer to the input peer information, not used currently.
427 : : * @param peer_info
428 : : * Pointer to the structure to store the information, output.
429 : : * @param direction
430 : : * Positive to get the RxQ information, zero to get the TxQ information.
431 : : *
432 : : * @return
433 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
434 : : */
435 : : int
436 : 0 : mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue,
437 : : struct rte_hairpin_peer_info *current_info,
438 : : struct rte_hairpin_peer_info *peer_info,
439 : : uint32_t direction)
440 : : {
441 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
442 : : RTE_SET_USED(current_info);
443 : :
444 [ # # ]: 0 : if (dev->data->dev_started == 0) {
445 : 0 : rte_errno = EBUSY;
446 : 0 : DRV_LOG(ERR, "peer port %u is not started",
447 : : dev->data->port_id);
448 : 0 : return -rte_errno;
449 : : }
450 : : /*
451 : : * Peer port used as egress. In the current design, hairpin Tx queue
452 : : * will be bound to the peer Rx queue. Indeed, only the information of
453 : : * peer Rx queue needs to be fetched.
454 : : */
455 [ # # ]: 0 : if (direction == 0) {
456 : : struct mlx5_txq_ctrl *txq_ctrl;
457 : :
458 : 0 : txq_ctrl = mlx5_txq_get(dev, peer_queue);
459 [ # # ]: 0 : if (txq_ctrl == NULL) {
460 : 0 : rte_errno = EINVAL;
461 : 0 : DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
462 : : dev->data->port_id, peer_queue);
463 : 0 : return -rte_errno;
464 : : }
465 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
466 : 0 : rte_errno = EINVAL;
467 : 0 : DRV_LOG(ERR, "port %u queue %d is not a hairpin Txq",
468 : : dev->data->port_id, peer_queue);
469 : 0 : mlx5_txq_release(dev, peer_queue);
470 : 0 : return -rte_errno;
471 : : }
472 [ # # # # ]: 0 : if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
473 : 0 : rte_errno = ENOMEM;
474 : 0 : DRV_LOG(ERR, "port %u no Txq object found: %d",
475 : : dev->data->port_id, peer_queue);
476 : 0 : mlx5_txq_release(dev, peer_queue);
477 : 0 : return -rte_errno;
478 : : }
479 : 0 : peer_info->qp_id = mlx5_txq_get_sqn(txq_ctrl);
480 : 0 : peer_info->vhca_id = priv->sh->cdev->config.hca_attr.vhca_id;
481 : : /* 1-to-1 mapping, only the first one is used. */
482 : 0 : peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue;
483 : 0 : peer_info->tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
484 : 0 : peer_info->manual_bind = txq_ctrl->hairpin_conf.manual_bind;
485 : 0 : mlx5_txq_release(dev, peer_queue);
486 : : } else { /* Peer port used as ingress. */
487 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, peer_queue);
488 : : struct mlx5_rxq_ctrl *rxq_ctrl;
489 : :
490 [ # # ]: 0 : if (rxq == NULL) {
491 : 0 : rte_errno = EINVAL;
492 : 0 : DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
493 : : dev->data->port_id, peer_queue);
494 : 0 : return -rte_errno;
495 : : }
496 : 0 : rxq_ctrl = rxq->ctrl;
497 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin) {
498 : 0 : rte_errno = EINVAL;
499 : 0 : DRV_LOG(ERR, "port %u queue %d is not a hairpin Rxq",
500 : : dev->data->port_id, peer_queue);
501 : 0 : return -rte_errno;
502 : : }
503 [ # # # # ]: 0 : if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
504 : 0 : rte_errno = ENOMEM;
505 : 0 : DRV_LOG(ERR, "port %u no Rxq object found: %d",
506 : : dev->data->port_id, peer_queue);
507 : 0 : return -rte_errno;
508 : : }
509 : 0 : peer_info->qp_id = rxq_ctrl->obj->rq->id;
510 : 0 : peer_info->vhca_id = priv->sh->cdev->config.hca_attr.vhca_id;
511 : 0 : peer_info->peer_q = rxq->hairpin_conf.peers[0].queue;
512 : 0 : peer_info->tx_explicit = rxq->hairpin_conf.tx_explicit;
513 : 0 : peer_info->manual_bind = rxq->hairpin_conf.manual_bind;
514 : : }
515 : : return 0;
516 : : }
517 : :
518 : : /*
519 : : * Bind the hairpin queue with the peer HW information.
520 : : * This needs to be called twice both for Tx and Rx queues of a pair.
521 : : * If the queue is already bound, it is considered successful.
522 : : *
523 : : * @param dev
524 : : * Pointer to Ethernet device structure.
525 : : * @param cur_queue
526 : : * Index of the queue to change the HW configuration to bind.
527 : : * @param peer_info
528 : : * Pointer to information of the peer queue.
529 : : * @param direction
530 : : * Positive to configure the TxQ, zero to configure the RxQ.
531 : : *
532 : : * @return
533 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
534 : : */
535 : : int
536 : 0 : mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue,
537 : : struct rte_hairpin_peer_info *peer_info,
538 : : uint32_t direction)
539 : : {
540 : : int ret = 0;
541 : :
542 : : /*
543 : : * Consistency checking of the peer queue: opposite direction is used
544 : : * to get the peer queue info with ethdev port ID, no need to check.
545 : : */
546 [ # # ]: 0 : if (peer_info->peer_q != cur_queue) {
547 : 0 : rte_errno = EINVAL;
548 : 0 : DRV_LOG(ERR, "port %u queue %d and peer queue %d mismatch",
549 : : dev->data->port_id, cur_queue, peer_info->peer_q);
550 : 0 : return -rte_errno;
551 : : }
552 [ # # ]: 0 : if (direction != 0) {
553 : : struct mlx5_txq_ctrl *txq_ctrl;
554 : 0 : struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
555 : :
556 : 0 : txq_ctrl = mlx5_txq_get(dev, cur_queue);
557 [ # # ]: 0 : if (txq_ctrl == NULL) {
558 : 0 : rte_errno = EINVAL;
559 : 0 : DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
560 : : dev->data->port_id, cur_queue);
561 : 0 : return -rte_errno;
562 : : }
563 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
564 : 0 : rte_errno = EINVAL;
565 : 0 : DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
566 : : dev->data->port_id, cur_queue);
567 : 0 : mlx5_txq_release(dev, cur_queue);
568 : 0 : return -rte_errno;
569 : : }
570 [ # # # # ]: 0 : if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
571 : 0 : rte_errno = ENOMEM;
572 : 0 : DRV_LOG(ERR, "port %u no Txq object found: %d",
573 : : dev->data->port_id, cur_queue);
574 : 0 : mlx5_txq_release(dev, cur_queue);
575 : 0 : return -rte_errno;
576 : : }
577 [ # # ]: 0 : if (txq_ctrl->hairpin_status != 0) {
578 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %d is already bound",
579 : : dev->data->port_id, cur_queue);
580 : 0 : mlx5_txq_release(dev, cur_queue);
581 : 0 : return 0;
582 : : }
583 : : /*
584 : : * All queues' of one port consistency checking is done in the
585 : : * bind() function, and that is optional.
586 : : */
587 : 0 : if (peer_info->tx_explicit !=
588 [ # # ]: 0 : txq_ctrl->hairpin_conf.tx_explicit) {
589 : 0 : rte_errno = EINVAL;
590 : 0 : DRV_LOG(ERR, "port %u Tx queue %d and peer Tx rule mode"
591 : : " mismatch", dev->data->port_id, cur_queue);
592 : 0 : mlx5_txq_release(dev, cur_queue);
593 : 0 : return -rte_errno;
594 : : }
595 : 0 : if (peer_info->manual_bind !=
596 [ # # ]: 0 : txq_ctrl->hairpin_conf.manual_bind) {
597 : 0 : rte_errno = EINVAL;
598 : 0 : DRV_LOG(ERR, "port %u Tx queue %d and peer binding mode"
599 : : " mismatch", dev->data->port_id, cur_queue);
600 : 0 : mlx5_txq_release(dev, cur_queue);
601 : 0 : return -rte_errno;
602 : : }
603 : 0 : sq_attr.state = MLX5_SQC_STATE_RDY;
604 : 0 : sq_attr.sq_state = MLX5_SQC_STATE_RST;
605 : 0 : sq_attr.hairpin_peer_rq = peer_info->qp_id;
606 : 0 : sq_attr.hairpin_peer_vhca = peer_info->vhca_id;
607 : 0 : ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
608 [ # # ]: 0 : if (ret == 0)
609 : 0 : txq_ctrl->hairpin_status = 1;
610 : 0 : mlx5_txq_release(dev, cur_queue);
611 : : } else {
612 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, cur_queue);
613 : : struct mlx5_rxq_ctrl *rxq_ctrl;
614 : 0 : struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
615 : :
616 [ # # ]: 0 : if (rxq == NULL) {
617 : 0 : rte_errno = EINVAL;
618 : 0 : DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
619 : : dev->data->port_id, cur_queue);
620 : 0 : return -rte_errno;
621 : : }
622 : 0 : rxq_ctrl = rxq->ctrl;
623 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin) {
624 : 0 : rte_errno = EINVAL;
625 : 0 : DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
626 : : dev->data->port_id, cur_queue);
627 : 0 : return -rte_errno;
628 : : }
629 [ # # # # ]: 0 : if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
630 : 0 : rte_errno = ENOMEM;
631 : 0 : DRV_LOG(ERR, "port %u no Rxq object found: %d",
632 : : dev->data->port_id, cur_queue);
633 : 0 : return -rte_errno;
634 : : }
635 [ # # ]: 0 : if (rxq->hairpin_status != 0) {
636 : 0 : DRV_LOG(DEBUG, "port %u Rx queue %d is already bound",
637 : : dev->data->port_id, cur_queue);
638 : 0 : return 0;
639 : : }
640 : 0 : if (peer_info->tx_explicit !=
641 [ # # ]: 0 : rxq->hairpin_conf.tx_explicit) {
642 : 0 : rte_errno = EINVAL;
643 : 0 : DRV_LOG(ERR, "port %u Rx queue %d and peer Tx rule mode"
644 : : " mismatch", dev->data->port_id, cur_queue);
645 : 0 : return -rte_errno;
646 : : }
647 : 0 : if (peer_info->manual_bind !=
648 [ # # ]: 0 : rxq->hairpin_conf.manual_bind) {
649 : 0 : rte_errno = EINVAL;
650 : 0 : DRV_LOG(ERR, "port %u Rx queue %d and peer binding mode"
651 : : " mismatch", dev->data->port_id, cur_queue);
652 : 0 : return -rte_errno;
653 : : }
654 : 0 : rq_attr.state = MLX5_RQC_STATE_RDY;
655 : : rq_attr.rq_state = MLX5_RQC_STATE_RST;
656 : 0 : rq_attr.hairpin_peer_sq = peer_info->qp_id;
657 : 0 : rq_attr.hairpin_peer_vhca = peer_info->vhca_id;
658 : 0 : ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
659 [ # # ]: 0 : if (ret == 0)
660 : 0 : rxq->hairpin_status = 1;
661 : : }
662 : : return ret;
663 : : }
664 : :
665 : : /*
666 : : * Unbind the hairpin queue and reset its HW configuration.
667 : : * This needs to be called twice both for Tx and Rx queues of a pair.
668 : : * If the queue is already unbound, it is considered successful.
669 : : *
670 : : * @param dev
671 : : * Pointer to Ethernet device structure.
672 : : * @param cur_queue
673 : : * Index of the queue to change the HW configuration to unbind.
674 : : * @param direction
675 : : * Positive to reset the TxQ, zero to reset the RxQ.
676 : : *
677 : : * @return
678 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
679 : : */
680 : : int
681 : 0 : mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue,
682 : : uint32_t direction)
683 : : {
684 : : int ret = 0;
685 : :
686 [ # # ]: 0 : if (direction != 0) {
687 : : struct mlx5_txq_ctrl *txq_ctrl;
688 : 0 : struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
689 : :
690 : 0 : txq_ctrl = mlx5_txq_get(dev, cur_queue);
691 [ # # ]: 0 : if (txq_ctrl == NULL) {
692 : 0 : rte_errno = EINVAL;
693 : 0 : DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
694 : : dev->data->port_id, cur_queue);
695 : 0 : return -rte_errno;
696 : : }
697 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
698 : 0 : rte_errno = EINVAL;
699 : 0 : DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
700 : : dev->data->port_id, cur_queue);
701 : 0 : mlx5_txq_release(dev, cur_queue);
702 : 0 : return -rte_errno;
703 : : }
704 : : /* Already unbound, return success before obj checking. */
705 [ # # ]: 0 : if (txq_ctrl->hairpin_status == 0) {
706 : 0 : DRV_LOG(DEBUG, "port %u Tx queue %d is already unbound",
707 : : dev->data->port_id, cur_queue);
708 : 0 : mlx5_txq_release(dev, cur_queue);
709 : 0 : return 0;
710 : : }
711 [ # # # # ]: 0 : if (!txq_ctrl->obj || !txq_ctrl->obj->sq) {
712 : 0 : rte_errno = ENOMEM;
713 : 0 : DRV_LOG(ERR, "port %u no Txq object found: %d",
714 : : dev->data->port_id, cur_queue);
715 : 0 : mlx5_txq_release(dev, cur_queue);
716 : 0 : return -rte_errno;
717 : : }
718 : 0 : sq_attr.state = MLX5_SQC_STATE_RST;
719 : 0 : sq_attr.sq_state = MLX5_SQC_STATE_RDY;
720 : 0 : ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
721 [ # # ]: 0 : if (ret == 0)
722 : 0 : txq_ctrl->hairpin_status = 0;
723 : 0 : mlx5_txq_release(dev, cur_queue);
724 : : } else {
725 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, cur_queue);
726 : : struct mlx5_rxq_ctrl *rxq_ctrl;
727 : 0 : struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
728 : :
729 [ # # ]: 0 : if (rxq == NULL) {
730 : 0 : rte_errno = EINVAL;
731 : 0 : DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
732 : : dev->data->port_id, cur_queue);
733 : 0 : return -rte_errno;
734 : : }
735 : 0 : rxq_ctrl = rxq->ctrl;
736 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin) {
737 : 0 : rte_errno = EINVAL;
738 : 0 : DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
739 : : dev->data->port_id, cur_queue);
740 : 0 : return -rte_errno;
741 : : }
742 [ # # ]: 0 : if (rxq->hairpin_status == 0) {
743 : 0 : DRV_LOG(DEBUG, "port %u Rx queue %d is already unbound",
744 : : dev->data->port_id, cur_queue);
745 : 0 : return 0;
746 : : }
747 [ # # # # ]: 0 : if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
748 : 0 : rte_errno = ENOMEM;
749 : 0 : DRV_LOG(ERR, "port %u no Rxq object found: %d",
750 : : dev->data->port_id, cur_queue);
751 : 0 : return -rte_errno;
752 : : }
753 : : rq_attr.state = MLX5_RQC_STATE_RST;
754 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RDY;
755 : 0 : ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
756 [ # # ]: 0 : if (ret == 0)
757 : 0 : rxq->hairpin_status = 0;
758 : : }
759 : : return ret;
760 : : }
761 : :
762 : : /*
763 : : * Bind the hairpin port pairs, from the Tx to the peer Rx.
764 : : * This function only supports to bind the Tx to one Rx.
765 : : *
766 : : * @param dev
767 : : * Pointer to Ethernet device structure.
768 : : * @param rx_port
769 : : * Port identifier of the Rx port.
770 : : *
771 : : * @return
772 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
773 : : */
774 : : static int
775 : 0 : mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
776 : : {
777 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
778 : : int ret = 0;
779 : : struct mlx5_txq_ctrl *txq_ctrl;
780 : : uint32_t i;
781 : 0 : struct rte_hairpin_peer_info peer = {0xffffff};
782 : : struct rte_hairpin_peer_info cur;
783 : : const struct rte_eth_hairpin_conf *conf;
784 : : uint16_t num_q = 0;
785 : 0 : uint16_t local_port = priv->dev_data->port_id;
786 : : uint32_t manual;
787 : : uint32_t explicit;
788 : : uint16_t rx_queue;
789 : :
790 [ # # ]: 0 : if (mlx5_eth_find_next(rx_port, dev->device) != rx_port) {
791 : 0 : rte_errno = ENODEV;
792 : 0 : DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
793 : 0 : return -rte_errno;
794 : : }
795 : : /*
796 : : * Before binding TxQ to peer RxQ, first round loop will be used for
797 : : * checking the queues' configuration consistency. This would be a
798 : : * little time consuming but better than doing the rollback.
799 : : */
800 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; i++) {
801 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
802 [ # # ]: 0 : if (txq_ctrl == NULL)
803 : 0 : continue;
804 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
805 : 0 : mlx5_txq_release(dev, i);
806 : 0 : continue;
807 : : }
808 : : /*
809 : : * All hairpin Tx queues of a single port that connected to the
810 : : * same peer Rx port should have the same "auto binding" and
811 : : * "implicit Tx flow" modes.
812 : : * Peer consistency checking will be done in per queue binding.
813 : : */
814 : : conf = &txq_ctrl->hairpin_conf;
815 [ # # ]: 0 : if (conf->peers[0].port == rx_port) {
816 [ # # ]: 0 : if (num_q == 0) {
817 : 0 : manual = conf->manual_bind;
818 : 0 : explicit = conf->tx_explicit;
819 : : } else {
820 [ # # ]: 0 : if (manual != conf->manual_bind ||
821 [ # # ]: 0 : explicit != conf->tx_explicit) {
822 : 0 : rte_errno = EINVAL;
823 : 0 : DRV_LOG(ERR, "port %u queue %d mode"
824 : : " mismatch: %u %u, %u %u",
825 : : local_port, i, manual,
826 : : conf->manual_bind, explicit,
827 : : conf->tx_explicit);
828 : 0 : mlx5_txq_release(dev, i);
829 : 0 : return -rte_errno;
830 : : }
831 : : }
832 : 0 : num_q++;
833 : : }
834 : 0 : mlx5_txq_release(dev, i);
835 : : }
836 : : /* Once no queue is configured, success is returned directly. */
837 [ # # ]: 0 : if (num_q == 0)
838 : : return ret;
839 : : /* All the hairpin TX queues need to be traversed again. */
840 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; i++) {
841 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
842 [ # # ]: 0 : if (txq_ctrl == NULL)
843 : 0 : continue;
844 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
845 : 0 : mlx5_txq_release(dev, i);
846 : 0 : continue;
847 : : }
848 [ # # ]: 0 : if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
849 : 0 : mlx5_txq_release(dev, i);
850 : 0 : continue;
851 : : }
852 : 0 : rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
853 : : /*
854 : : * Fetch peer RxQ's information.
855 : : * No need to pass the information of the current queue.
856 : : */
857 : 0 : ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue,
858 : : NULL, &peer, 1);
859 [ # # ]: 0 : if (ret != 0) {
860 : 0 : mlx5_txq_release(dev, i);
861 : 0 : goto error;
862 : : }
863 : : /* Accessing its own device, inside mlx5 PMD. */
864 : 0 : ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1);
865 [ # # ]: 0 : if (ret != 0) {
866 : 0 : mlx5_txq_release(dev, i);
867 : 0 : goto error;
868 : : }
869 : : /* Pass TxQ's information to peer RxQ and try binding. */
870 : 0 : cur.peer_q = rx_queue;
871 : 0 : cur.qp_id = mlx5_txq_get_sqn(txq_ctrl);
872 : 0 : cur.vhca_id = priv->sh->cdev->config.hca_attr.vhca_id;
873 : 0 : cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
874 : 0 : cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
875 : : /*
876 : : * In order to access another device in a proper way, RTE level
877 : : * private function is needed.
878 : : */
879 : 0 : ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue,
880 : : &cur, 0);
881 [ # # ]: 0 : if (ret != 0) {
882 : 0 : mlx5_txq_release(dev, i);
883 : 0 : goto error;
884 : : }
885 : 0 : mlx5_txq_release(dev, i);
886 : : }
887 : : return 0;
888 : 0 : error:
889 : : /*
890 : : * Do roll-back process for the queues already bound.
891 : : * No need to check the return value of the queue unbind function.
892 : : */
893 : : do {
894 : : /* No validation is needed here. */
895 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
896 [ # # ]: 0 : if (txq_ctrl == NULL)
897 : 0 : continue;
898 [ # # ]: 0 : if (!txq_ctrl->is_hairpin ||
899 [ # # ]: 0 : txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
900 : 0 : mlx5_txq_release(dev, i);
901 : 0 : continue;
902 : : }
903 : 0 : rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
904 : 0 : rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
905 : 0 : mlx5_hairpin_queue_peer_unbind(dev, i, 1);
906 : 0 : mlx5_txq_release(dev, i);
907 [ # # ]: 0 : } while (i--);
908 : : return ret;
909 : : }
910 : :
911 : : /*
912 : : * Unbind the hairpin port pair, HW configuration of both devices will be clear
913 : : * and status will be reset for all the queues used between them.
914 : : * This function only supports to unbind the Tx from one Rx.
915 : : *
916 : : * @param dev
917 : : * Pointer to Ethernet device structure.
918 : : * @param rx_port
919 : : * Port identifier of the Rx port.
920 : : *
921 : : * @return
922 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
923 : : */
924 : : static int
925 : 0 : mlx5_hairpin_unbind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
926 : : {
927 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
928 : : struct mlx5_txq_ctrl *txq_ctrl;
929 : : uint32_t i;
930 : : int ret;
931 : 0 : uint16_t cur_port = priv->dev_data->port_id;
932 : :
933 [ # # ]: 0 : if (mlx5_eth_find_next(rx_port, dev->device) != rx_port) {
934 : 0 : rte_errno = ENODEV;
935 : 0 : DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
936 : 0 : return -rte_errno;
937 : : }
938 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; i++) {
939 : : uint16_t rx_queue;
940 : :
941 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
942 [ # # ]: 0 : if (txq_ctrl == NULL)
943 : 0 : continue;
944 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
945 : 0 : mlx5_txq_release(dev, i);
946 : 0 : continue;
947 : : }
948 [ # # ]: 0 : if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
949 : 0 : mlx5_txq_release(dev, i);
950 : 0 : continue;
951 : : }
952 : : /* Indeed, only the first used queue needs to be checked. */
953 [ # # ]: 0 : if (txq_ctrl->hairpin_conf.manual_bind == 0) {
954 : 0 : mlx5_txq_release(dev, i);
955 [ # # ]: 0 : if (cur_port != rx_port) {
956 : 0 : rte_errno = EINVAL;
957 : 0 : DRV_LOG(ERR, "port %u and port %u are in"
958 : : " auto-bind mode", cur_port, rx_port);
959 : 0 : return -rte_errno;
960 : : } else {
961 : : return 0;
962 : : }
963 : : }
964 : 0 : rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
965 : 0 : mlx5_txq_release(dev, i);
966 : 0 : ret = rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
967 [ # # ]: 0 : if (ret) {
968 : 0 : DRV_LOG(ERR, "port %u Rx queue %d unbind - failure",
969 : : rx_port, rx_queue);
970 : 0 : return ret;
971 : : }
972 : 0 : ret = mlx5_hairpin_queue_peer_unbind(dev, i, 1);
973 [ # # ]: 0 : if (ret) {
974 : 0 : DRV_LOG(ERR, "port %u Tx queue %d unbind - failure",
975 : : cur_port, i);
976 : 0 : return ret;
977 : : }
978 : : }
979 : : return 0;
980 : : }
981 : :
982 : : /*
983 : : * Bind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
984 : : * @see mlx5_hairpin_bind_single_port()
985 : : */
986 : : int
987 : 0 : mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port)
988 : : {
989 : : int ret = 0;
990 : : uint16_t p, pp;
991 : :
992 : : /*
993 : : * If the Rx port has no hairpin configuration with the current port,
994 : : * the binding will be skipped in the called function of single port.
995 : : * Device started status will be checked only before the queue
996 : : * information updating.
997 : : */
998 [ # # ]: 0 : if (rx_port == RTE_MAX_ETHPORTS) {
999 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(p, dev->device) {
1000 : 0 : ret = mlx5_hairpin_bind_single_port(dev, p);
1001 [ # # ]: 0 : if (ret != 0)
1002 : 0 : goto unbind;
1003 : : }
1004 : : return ret;
1005 : : } else {
1006 : 0 : return mlx5_hairpin_bind_single_port(dev, rx_port);
1007 : : }
1008 : : unbind:
1009 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(pp, dev->device)
1010 [ # # ]: 0 : if (pp < p)
1011 : 0 : mlx5_hairpin_unbind_single_port(dev, pp);
1012 : : return ret;
1013 : : }
1014 : :
1015 : : /*
1016 : : * Unbind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
1017 : : * @see mlx5_hairpin_unbind_single_port()
1018 : : */
1019 : : int
1020 : 0 : mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port)
1021 : : {
1022 : : int ret = 0;
1023 : : uint16_t p;
1024 : :
1025 [ # # ]: 0 : if (rx_port == RTE_MAX_ETHPORTS)
1026 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(p, dev->device) {
1027 : 0 : ret = mlx5_hairpin_unbind_single_port(dev, p);
1028 [ # # ]: 0 : if (ret != 0)
1029 : 0 : return ret;
1030 : : }
1031 : : else
1032 : 0 : ret = mlx5_hairpin_unbind_single_port(dev, rx_port);
1033 : : return ret;
1034 : : }
1035 : :
1036 : : /*
1037 : : * DPDK callback to get the hairpin peer ports list.
1038 : : * This will return the actual number of peer ports and save the identifiers
1039 : : * into the array (sorted, may be different from that when setting up the
1040 : : * hairpin peer queues).
1041 : : * The peer port ID could be the same as the port ID of the current device.
1042 : : *
1043 : : * @param dev
1044 : : * Pointer to Ethernet device structure.
1045 : : * @param peer_ports
1046 : : * Pointer to array to save the port identifiers.
1047 : : * @param len
1048 : : * The length of the array.
1049 : : * @param direction
1050 : : * Current port to peer port direction.
1051 : : * positive - current used as Tx to get all peer Rx ports.
1052 : : * zero - current used as Rx to get all peer Tx ports.
1053 : : *
1054 : : * @return
1055 : : * 0 or positive value on success, actual number of peer ports.
1056 : : * a negative errno value otherwise and rte_errno is set.
1057 : : */
1058 : : int
1059 : 0 : mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports,
1060 : : size_t len, uint32_t direction)
1061 : : {
1062 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1063 : : struct mlx5_txq_ctrl *txq_ctrl;
1064 : : uint32_t i;
1065 : : uint16_t pp;
1066 : : uint32_t bits[(RTE_MAX_ETHPORTS + 31) / 32] = {0};
1067 : : int ret = 0;
1068 : :
1069 [ # # ]: 0 : if (direction) {
1070 [ # # ]: 0 : for (i = 0; i < priv->txqs_n; i++) {
1071 : 0 : txq_ctrl = mlx5_txq_get(dev, i);
1072 [ # # ]: 0 : if (!txq_ctrl)
1073 : 0 : continue;
1074 [ # # ]: 0 : if (!txq_ctrl->is_hairpin) {
1075 : 0 : mlx5_txq_release(dev, i);
1076 : 0 : continue;
1077 : : }
1078 : 0 : pp = txq_ctrl->hairpin_conf.peers[0].port;
1079 [ # # ]: 0 : if (pp >= RTE_MAX_ETHPORTS) {
1080 : 0 : rte_errno = ERANGE;
1081 : 0 : mlx5_txq_release(dev, i);
1082 : 0 : DRV_LOG(ERR, "port %hu queue %u peer port "
1083 : : "out of range %hu",
1084 : : priv->dev_data->port_id, i, pp);
1085 : 0 : return -rte_errno;
1086 : : }
1087 : 0 : bits[pp / 32] |= 1 << (pp % 32);
1088 : 0 : mlx5_txq_release(dev, i);
1089 : : }
1090 : : } else {
1091 [ # # ]: 0 : for (i = 0; i < priv->rxqs_n; i++) {
1092 : 0 : struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, i);
1093 : : struct mlx5_rxq_ctrl *rxq_ctrl;
1094 : :
1095 [ # # ]: 0 : if (rxq == NULL)
1096 : 0 : continue;
1097 : 0 : rxq_ctrl = rxq->ctrl;
1098 [ # # ]: 0 : if (!rxq_ctrl->is_hairpin)
1099 : 0 : continue;
1100 : 0 : pp = rxq->hairpin_conf.peers[0].port;
1101 [ # # ]: 0 : if (pp >= RTE_MAX_ETHPORTS) {
1102 : 0 : rte_errno = ERANGE;
1103 : 0 : DRV_LOG(ERR, "port %hu queue %u peer port "
1104 : : "out of range %hu",
1105 : : priv->dev_data->port_id, i, pp);
1106 : 0 : return -rte_errno;
1107 : : }
1108 : 0 : bits[pp / 32] |= 1 << (pp % 32);
1109 : : }
1110 : : }
1111 [ # # ]: 0 : for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
1112 [ # # ]: 0 : if (bits[i / 32] & (1 << (i % 32))) {
1113 [ # # ]: 0 : if ((size_t)ret >= len) {
1114 : 0 : rte_errno = E2BIG;
1115 : 0 : return -rte_errno;
1116 : : }
1117 : 0 : peer_ports[ret++] = i;
1118 : : }
1119 : : }
1120 : : return ret;
1121 : : }
1122 : :
1123 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1124 : :
1125 : : /**
1126 : : * Check if starting representor port is allowed.
1127 : : *
1128 : : * If transfer proxy port is configured for HWS, then starting representor port
1129 : : * is allowed if and only if transfer proxy port is started as well.
1130 : : *
1131 : : * @param dev
1132 : : * Pointer to Ethernet device structure.
1133 : : *
1134 : : * @return
1135 : : * If stopping representor port is allowed, then 0 is returned.
1136 : : * Otherwise rte_errno is set, and negative errno value is returned.
1137 : : */
1138 : : static int
1139 : 0 : mlx5_hw_representor_port_allowed_start(struct rte_eth_dev *dev)
1140 : : {
1141 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1142 : : struct rte_eth_dev *proxy_dev;
1143 : : struct mlx5_priv *proxy_priv;
1144 : 0 : uint16_t proxy_port_id = UINT16_MAX;
1145 : : int ret;
1146 : :
1147 : : MLX5_ASSERT(priv->sh->config.dv_flow_en == 2);
1148 : : MLX5_ASSERT(priv->sh->config.dv_esw_en);
1149 : : MLX5_ASSERT(priv->representor);
1150 : 0 : ret = rte_flow_pick_transfer_proxy(dev->data->port_id, &proxy_port_id, NULL);
1151 [ # # ]: 0 : if (ret) {
1152 [ # # ]: 0 : if (ret == -ENODEV)
1153 : 0 : DRV_LOG(ERR, "Starting representor port %u is not allowed. Transfer "
1154 : : "proxy port is not available.", dev->data->port_id);
1155 : : else
1156 : 0 : DRV_LOG(ERR, "Failed to pick transfer proxy for port %u (ret = %d)",
1157 : : dev->data->port_id, ret);
1158 : 0 : return ret;
1159 : : }
1160 : 0 : proxy_dev = &rte_eth_devices[proxy_port_id];
1161 : 0 : proxy_priv = proxy_dev->data->dev_private;
1162 [ # # ]: 0 : if (proxy_priv->dr_ctx == NULL) {
1163 : 0 : DRV_LOG(DEBUG, "Starting representor port %u is allowed, but default traffic flows"
1164 : : " will not be created. Transfer proxy port must be configured"
1165 : : " for HWS and started.",
1166 : : dev->data->port_id);
1167 : 0 : return 0;
1168 : : }
1169 [ # # ]: 0 : if (!proxy_dev->data->dev_started) {
1170 : 0 : DRV_LOG(ERR, "Failed to start port %u: transfer proxy (port %u) must be started",
1171 : : dev->data->port_id, proxy_port_id);
1172 : 0 : rte_errno = EAGAIN;
1173 : 0 : return -rte_errno;
1174 : : }
1175 [ # # ]: 0 : if (priv->dr_ctx == NULL) {
1176 : 0 : DRV_LOG(ERR, "Failed to start port %u: port must be configured for HWS",
1177 : : dev->data->port_id);
1178 : 0 : rte_errno = EINVAL;
1179 : 0 : return -rte_errno;
1180 : : }
1181 : : return 0;
1182 : : }
1183 : :
1184 : : #endif
1185 : :
1186 : : /*
1187 : : * Allocate TxQs unique umem and register its MR.
1188 : : *
1189 : : * @param dev
1190 : : * Pointer to Ethernet device structure.
1191 : : *
1192 : : * @return
1193 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1194 : : */
1195 : 0 : static int mlx5_dev_allocate_consec_tx_mem(struct rte_eth_dev *dev)
1196 : : {
1197 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1198 : : size_t alignment;
1199 : : uint32_t total_size;
1200 : : struct mlx5dv_devx_umem *umem_obj = NULL;
1201 : : void *umem_buf = NULL;
1202 : :
1203 : : /* Legacy per queue allocation, do nothing here. */
1204 [ # # ]: 0 : if (priv->sh->config.txq_mem_algn == 0)
1205 : : return 0;
1206 : 0 : alignment = (size_t)1 << priv->sh->config.txq_mem_algn;
1207 : 0 : total_size = priv->consec_tx_mem.sq_total_size + priv->consec_tx_mem.cq_total_size;
1208 : : /*
1209 : : * Hairpin queues can be skipped later
1210 : : * queue size alignment is bigger than doorbell alignment, no need to align or
1211 : : * round-up again. One queue have two DBs (for CQ + WQ).
1212 : : */
1213 : 0 : total_size += MLX5_DBR_SIZE * priv->txqs_n * 2;
1214 [ # # # # : 0 : umem_buf = mlx5_malloc_numa_tolerant(MLX5_MEM_RTE | MLX5_MEM_ZERO, total_size,
# # ]
1215 : : alignment, priv->sh->numa_node);
1216 [ # # ]: 0 : if (!umem_buf) {
1217 : 0 : DRV_LOG(ERR, "Failed to allocate consecutive memory for TxQs.");
1218 : 0 : rte_errno = ENOMEM;
1219 : 0 : return -rte_errno;
1220 : : }
1221 : 0 : umem_obj = mlx5_os_umem_reg(priv->sh->cdev->ctx, (void *)(uintptr_t)umem_buf,
1222 : : total_size, IBV_ACCESS_LOCAL_WRITE);
1223 [ # # ]: 0 : if (!umem_obj) {
1224 : 0 : DRV_LOG(ERR, "Failed to register unique umem for all SQs.");
1225 : 0 : rte_errno = errno;
1226 : : if (umem_buf)
1227 : 0 : mlx5_free(umem_buf);
1228 : 0 : return -rte_errno;
1229 : : }
1230 : 0 : priv->consec_tx_mem.umem = umem_buf;
1231 : 0 : priv->consec_tx_mem.sq_cur_off = 0;
1232 : 0 : priv->consec_tx_mem.cq_cur_off = priv->consec_tx_mem.sq_total_size;
1233 : 0 : priv->consec_tx_mem.umem_obj = umem_obj;
1234 : 0 : DRV_LOG(DEBUG, "Allocated umem %p with size %u for %u queues with sq_len %u,"
1235 : : " cq_len %u and registered object %p on port %u",
1236 : : umem_buf, total_size, priv->txqs_n, priv->consec_tx_mem.sq_total_size,
1237 : : priv->consec_tx_mem.cq_total_size, (void *)umem_obj, dev->data->port_id);
1238 : 0 : return 0;
1239 : : }
1240 : :
1241 : : /*
1242 : : * Release TxQs unique umem and register its MR.
1243 : : *
1244 : : * @param dev
1245 : : * Pointer to Ethernet device structure.
1246 : : * @param on_stop
1247 : : * If this is on device stop stage.
1248 : : */
1249 : 0 : static void mlx5_dev_free_consec_tx_mem(struct rte_eth_dev *dev, bool on_stop)
1250 : : {
1251 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1252 : :
1253 [ # # ]: 0 : if (priv->consec_tx_mem.umem_obj) {
1254 : : mlx5_os_umem_dereg(priv->consec_tx_mem.umem_obj);
1255 : 0 : priv->consec_tx_mem.umem_obj = NULL;
1256 : : }
1257 [ # # ]: 0 : if (priv->consec_tx_mem.umem) {
1258 : 0 : mlx5_free(priv->consec_tx_mem.umem);
1259 : 0 : priv->consec_tx_mem.umem = NULL;
1260 : : }
1261 : : /* Queues information will not be reset. */
1262 [ # # ]: 0 : if (on_stop) {
1263 : : /* Reset to 0s for re-setting up queues. */
1264 : 0 : priv->consec_tx_mem.sq_cur_off = 0;
1265 : 0 : priv->consec_tx_mem.cq_cur_off = 0;
1266 : : }
1267 : 0 : }
1268 : :
1269 : : #define SAVE_RTE_ERRNO_AND_STOP(ret, dev) do { \
1270 : : ret = rte_errno; \
1271 : : (dev)->data->dev_started = 0; \
1272 : : } while (0)
1273 : :
1274 : : /**
1275 : : * DPDK callback to start the device.
1276 : : *
1277 : : * Simulate device start by attaching all configured flows.
1278 : : *
1279 : : * @param dev
1280 : : * Pointer to Ethernet device structure.
1281 : : *
1282 : : * @return
1283 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1284 : : * The following error values are defined:
1285 : : *
1286 : : * - -EAGAIN: If port representor cannot be started,
1287 : : * because transfer proxy port is not started.
1288 : : */
1289 : : int
1290 : 0 : mlx5_dev_start(struct rte_eth_dev *dev)
1291 : : {
1292 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1293 : : int ret;
1294 : : int fine_inline;
1295 : :
1296 : 0 : DRV_LOG(DEBUG, "port %u starting device", dev->data->port_id);
1297 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1298 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1299 : 0 : struct rte_flow_error error = { 0, };
1300 : :
1301 : : /*
1302 : : * If steering is disabled, then:
1303 : : * - There are no limitations regarding port start ordering,
1304 : : * since no flow rules need to be created as part of port start.
1305 : : * - Non template API initialization will be skipped.
1306 : : */
1307 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1308 : 0 : goto continue_dev_start;
1309 : : /*If previous configuration does not exist. */
1310 [ # # ]: 0 : if (!(priv->dr_ctx)) {
1311 : 0 : ret = mlx5_flow_hw_init(dev, &error);
1312 [ # # ]: 0 : if (ret) {
1313 : 0 : DRV_LOG(ERR, "Failed to start port %u %s: %s",
1314 : : dev->data->port_id, dev->data->name,
1315 : : error.message);
1316 : 0 : return ret;
1317 : : }
1318 : : }
1319 : : /* If there is no E-Switch, then there are no start/stop order limitations. */
1320 [ # # ]: 0 : if (!priv->sh->config.dv_esw_en)
1321 : 0 : goto continue_dev_start;
1322 : : /* If master is being started, then it is always allowed. */
1323 [ # # ]: 0 : if (priv->master)
1324 : 0 : goto continue_dev_start;
1325 [ # # ]: 0 : if (mlx5_hw_representor_port_allowed_start(dev))
1326 : 0 : return -rte_errno;
1327 : : }
1328 : 0 : continue_dev_start:
1329 : : #endif
1330 : 0 : fine_inline = rte_mbuf_dynflag_lookup
1331 : : (RTE_PMD_MLX5_FINE_GRANULARITY_INLINE, NULL);
1332 [ # # ]: 0 : if (fine_inline >= 0)
1333 : 0 : rte_net_mlx5_dynf_inline_mask = RTE_BIT64(fine_inline);
1334 : : else
1335 : 0 : rte_net_mlx5_dynf_inline_mask = 0;
1336 [ # # ]: 0 : if (dev->data->nb_rx_queues > 0) {
1337 : 0 : uint32_t max_lro_msg_size = priv->max_lro_msg_size;
1338 : :
1339 [ # # ]: 0 : if (max_lro_msg_size < MLX5_LRO_SEG_CHUNK_SIZE) {
1340 : : uint32_t i;
1341 : : struct mlx5_rxq_priv *rxq;
1342 : :
1343 [ # # ]: 0 : for (i = 0; i != priv->rxqs_n; ++i) {
1344 : 0 : rxq = mlx5_rxq_get(dev, i);
1345 [ # # # # : 0 : if (rxq && rxq->ctrl && rxq->ctrl->rxq.lro) {
# # ]
1346 : 0 : DRV_LOG(ERR, "port %u invalid max LRO size",
1347 : : dev->data->port_id);
1348 : 0 : rte_errno = EINVAL;
1349 : 0 : return -rte_errno;
1350 : : }
1351 : : }
1352 : : }
1353 : 0 : ret = mlx5_dev_configure_rss_reta(dev);
1354 [ # # ]: 0 : if (ret) {
1355 : 0 : DRV_LOG(ERR, "port %u reta config failed: %s",
1356 : : dev->data->port_id, strerror(rte_errno));
1357 : 0 : return -rte_errno;
1358 : : }
1359 : : }
1360 : 0 : ret = mlx5_txpp_start(dev);
1361 [ # # ]: 0 : if (ret) {
1362 : 0 : DRV_LOG(ERR, "port %u Tx packet pacing init failed: %s",
1363 : : dev->data->port_id, strerror(rte_errno));
1364 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1365 : 0 : goto error;
1366 : : }
1367 [ # # # # ]: 0 : if (mlx5_devx_obj_ops_en(priv->sh) &&
1368 [ # # ]: 0 : priv->obj_ops.lb_dummy_queue_create) {
1369 : 0 : ret = priv->obj_ops.lb_dummy_queue_create(dev);
1370 [ # # ]: 0 : if (ret) {
1371 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1372 : 0 : goto txpp_stop;
1373 : : }
1374 : : }
1375 : 0 : ret = mlx5_dev_allocate_consec_tx_mem(dev);
1376 [ # # ]: 0 : if (ret) {
1377 : 0 : DRV_LOG(ERR, "port %u Tx queues memory allocation failed: %s",
1378 : : dev->data->port_id, strerror(rte_errno));
1379 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1380 : 0 : goto lb_dummy_queue_release;
1381 : : }
1382 : 0 : ret = mlx5_txq_start(dev);
1383 [ # # ]: 0 : if (ret) {
1384 : 0 : DRV_LOG(ERR, "port %u Tx queue allocation failed: %s",
1385 : : dev->data->port_id, strerror(rte_errno));
1386 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1387 : 0 : goto free_consec_tx_mem;
1388 : : }
1389 [ # # ]: 0 : if (priv->config.std_delay_drop || priv->config.hp_delay_drop) {
1390 [ # # ]: 0 : if (!priv->sh->dev_cap.vf && !priv->sh->dev_cap.sf &&
1391 [ # # ]: 0 : !priv->representor) {
1392 : 0 : ret = mlx5_get_flag_dropless_rq(dev);
1393 [ # # ]: 0 : if (ret < 0)
1394 : 0 : DRV_LOG(WARNING,
1395 : : "port %u cannot query dropless flag",
1396 : : dev->data->port_id);
1397 [ # # ]: 0 : else if (!ret)
1398 : 0 : DRV_LOG(WARNING,
1399 : : "port %u dropless_rq OFF, no rearming",
1400 : : dev->data->port_id);
1401 : : } else {
1402 : 0 : DRV_LOG(DEBUG,
1403 : : "port %u doesn't support dropless_rq flag",
1404 : : dev->data->port_id);
1405 : : }
1406 : : }
1407 : 0 : ret = mlx5_rxq_start(dev);
1408 [ # # ]: 0 : if (ret) {
1409 : 0 : DRV_LOG(ERR, "port %u Rx queue allocation failed: %s",
1410 : : dev->data->port_id, strerror(rte_errno));
1411 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1412 : 0 : goto txq_stop;
1413 : : }
1414 : : /*
1415 : : * Such step will be skipped if there is no hairpin TX queue configured
1416 : : * with RX peer queue from the same device.
1417 : : */
1418 : 0 : ret = mlx5_hairpin_auto_bind(dev);
1419 [ # # ]: 0 : if (ret) {
1420 : 0 : DRV_LOG(ERR, "port %u hairpin auto binding failed: %s",
1421 : : dev->data->port_id, strerror(rte_errno));
1422 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1423 : 0 : goto rxq_stop;
1424 : : }
1425 : : /* Set started flag here for the following steps like control flow. */
1426 : 0 : dev->data->dev_started = 1;
1427 : 0 : ret = mlx5_rx_intr_vec_enable(dev);
1428 [ # # ]: 0 : if (ret) {
1429 : 0 : DRV_LOG(ERR, "port %u Rx interrupt vector creation failed",
1430 : : dev->data->port_id);
1431 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1432 : 0 : goto rxq_stop;
1433 : : }
1434 : 0 : mlx5_os_stats_init(dev);
1435 : : /*
1436 : : * Attach indirection table objects detached on port stop.
1437 : : * They may be needed to create RSS in non-isolated mode.
1438 : : */
1439 : 0 : ret = mlx5_action_handle_attach(dev);
1440 [ # # ]: 0 : if (ret) {
1441 : 0 : DRV_LOG(ERR,
1442 : : "port %u failed to attach indirect actions: %s",
1443 : : dev->data->port_id, rte_strerror(rte_errno));
1444 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1445 : 0 : goto rx_intr_vec_disable;
1446 : : }
1447 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1448 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1449 : 0 : ret = mlx5_flow_hw_table_update(dev, NULL);
1450 [ # # ]: 0 : if (ret) {
1451 : 0 : DRV_LOG(ERR, "port %u failed to update HWS tables",
1452 : : dev->data->port_id);
1453 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1454 : 0 : goto action_handle_detach;
1455 : : }
1456 : : }
1457 : : #endif
1458 : 0 : ret = mlx5_traffic_enable(dev);
1459 [ # # ]: 0 : if (ret) {
1460 : 0 : DRV_LOG(ERR, "port %u failed to set defaults flows",
1461 : : dev->data->port_id);
1462 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1463 : 0 : goto action_handle_detach;
1464 : : }
1465 : : /* Set dynamic fields and flags into Rx queues. */
1466 : 0 : mlx5_flow_rxq_dynf_set(dev);
1467 : : /* Set flags and context to convert Rx timestamps. */
1468 : 0 : mlx5_rxq_timestamp_set(dev);
1469 : : /* Set a mask and offset of scheduling on timestamp into Tx queues. */
1470 : 0 : mlx5_txq_dynf_timestamp_set(dev);
1471 : : /*
1472 : : * In non-cached mode, it only needs to start the default mreg copy
1473 : : * action and no flow created by application exists anymore.
1474 : : * But it is worth wrapping the interface for further usage.
1475 : : */
1476 : 0 : ret = mlx5_flow_start_default(dev);
1477 [ # # ]: 0 : if (ret) {
1478 : 0 : DRV_LOG(DEBUG, "port %u failed to start default actions: %s",
1479 : : dev->data->port_id, strerror(rte_errno));
1480 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1481 : 0 : goto traffic_disable;
1482 : : }
1483 [ # # ]: 0 : if (mlx5_dev_ctx_shared_mempool_subscribe(dev) != 0) {
1484 : 0 : DRV_LOG(ERR, "port %u failed to subscribe for mempool life cycle: %s",
1485 : : dev->data->port_id, rte_strerror(rte_errno));
1486 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1487 : 0 : goto stop_default;
1488 : : }
1489 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1490 : 0 : mlx5_flow_rxq_mark_flag_set(dev);
1491 : : rte_wmb();
1492 : 0 : dev->tx_pkt_burst = mlx5_select_tx_function(dev);
1493 : 0 : dev->rx_pkt_burst = mlx5_select_rx_function(dev);
1494 : : /* Enable datapath on secondary process. */
1495 : 0 : mlx5_mp_os_req_start_rxtx(dev);
1496 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle) >= 0) {
1497 : 0 : priv->sh->port[priv->dev_port - 1].ih_port_id =
1498 : 0 : (uint32_t)dev->data->port_id;
1499 : : } else {
1500 : 0 : DRV_LOG(INFO, "port %u starts without RMV interrupts.",
1501 : : dev->data->port_id);
1502 : 0 : dev->data->dev_conf.intr_conf.rmv = 0;
1503 : : }
1504 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle_nl) >= 0) {
1505 : 0 : priv->sh->port[priv->dev_port - 1].nl_ih_port_id =
1506 : 0 : (uint32_t)dev->data->port_id;
1507 : : } else {
1508 : 0 : DRV_LOG(INFO, "port %u starts without LSC interrupts.",
1509 : : dev->data->port_id);
1510 : 0 : dev->data->dev_conf.intr_conf.lsc = 0;
1511 : : }
1512 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle_devx) >= 0)
1513 : 0 : priv->sh->port[priv->dev_port - 1].devx_ih_port_id =
1514 : 0 : (uint32_t)dev->data->port_id;
1515 : : return 0;
1516 : : stop_default:
1517 : 0 : mlx5_flow_stop_default(dev);
1518 : 0 : traffic_disable:
1519 : 0 : mlx5_traffic_disable(dev);
1520 : 0 : action_handle_detach:
1521 : 0 : mlx5_action_handle_detach(dev);
1522 : 0 : rx_intr_vec_disable:
1523 : 0 : mlx5_rx_intr_vec_disable(dev);
1524 : 0 : rxq_stop:
1525 : 0 : mlx5_rxq_stop(dev);
1526 : 0 : txq_stop:
1527 : 0 : mlx5_txq_stop(dev);
1528 : 0 : free_consec_tx_mem:
1529 : 0 : mlx5_dev_free_consec_tx_mem(dev, false);
1530 : 0 : lb_dummy_queue_release:
1531 [ # # ]: 0 : if (priv->obj_ops.lb_dummy_queue_release)
1532 : 0 : priv->obj_ops.lb_dummy_queue_release(dev);
1533 : 0 : txpp_stop:
1534 : 0 : mlx5_txpp_stop(dev);
1535 : 0 : error:
1536 : 0 : rte_errno = ret;
1537 : 0 : return -rte_errno;
1538 : : }
1539 : :
1540 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1541 : : /**
1542 : : * Check if stopping transfer proxy port is allowed.
1543 : : *
1544 : : * If transfer proxy port is configured for HWS, then it is allowed to stop it
1545 : : * if and only if all other representor ports are stopped.
1546 : : *
1547 : : * @param dev
1548 : : * Pointer to Ethernet device structure.
1549 : : *
1550 : : * @return
1551 : : * If stopping transfer proxy port is allowed, then 0 is returned.
1552 : : * Otherwise rte_errno is set, and negative errno value is returned.
1553 : : */
1554 : : static int
1555 : 0 : mlx5_hw_proxy_port_allowed_stop(struct rte_eth_dev *dev)
1556 : : {
1557 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1558 : : bool representor_started = false;
1559 : : uint16_t port_id;
1560 : :
1561 : : MLX5_ASSERT(priv->sh->config.dv_flow_en == 2);
1562 : : MLX5_ASSERT(priv->sh->config.dv_esw_en);
1563 : : MLX5_ASSERT(priv->master);
1564 : : /* If transfer proxy port was not configured for HWS, then stopping it is allowed. */
1565 [ # # ]: 0 : if (!priv->dr_ctx)
1566 : : return 0;
1567 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
1568 : 0 : const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id];
1569 : 0 : const struct mlx5_priv *port_priv = port_dev->data->dev_private;
1570 : :
1571 [ # # ]: 0 : if (port_id != dev->data->port_id &&
1572 [ # # # # ]: 0 : port_priv->domain_id == priv->domain_id &&
1573 : : port_dev->data->dev_started)
1574 : : representor_started = true;
1575 : : }
1576 [ # # ]: 0 : if (representor_started) {
1577 : 0 : DRV_LOG(ERR, "Failed to stop port %u: attached representor ports"
1578 : : " must be stopped before stopping transfer proxy port",
1579 : : dev->data->port_id);
1580 : 0 : rte_errno = EBUSY;
1581 : 0 : return -rte_errno;
1582 : : }
1583 : : return 0;
1584 : : }
1585 : : #endif
1586 : :
1587 : : /**
1588 : : * DPDK callback to stop the device.
1589 : : *
1590 : : * Simulate device stop by detaching all configured flows.
1591 : : *
1592 : : * @param dev
1593 : : * Pointer to Ethernet device structure.
1594 : : *
1595 : : * @return
1596 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1597 : : * The following error values are defined:
1598 : : *
1599 : : * - -EBUSY: If transfer proxy port cannot be stopped,
1600 : : * because other port representors are still running.
1601 : : */
1602 : : int
1603 : 0 : mlx5_dev_stop(struct rte_eth_dev *dev)
1604 : : {
1605 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1606 : :
1607 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1608 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1609 : : /*
1610 : : * If steering is disabled,
1611 : : * then there are no limitations regarding port stop ordering,
1612 : : * since no flow rules need to be destroyed as part of port stop.
1613 : : */
1614 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1615 : 0 : goto continue_dev_stop;
1616 : : /* If there is no E-Switch, then there are no start/stop order limitations. */
1617 [ # # ]: 0 : if (!priv->sh->config.dv_esw_en)
1618 : 0 : goto continue_dev_stop;
1619 : : /* If representor is being stopped, then it is always allowed. */
1620 [ # # ]: 0 : if (priv->representor)
1621 : 0 : goto continue_dev_stop;
1622 [ # # ]: 0 : if (mlx5_hw_proxy_port_allowed_stop(dev)) {
1623 : 0 : dev->data->dev_started = 1;
1624 : 0 : return -rte_errno;
1625 : : }
1626 : : }
1627 : 0 : continue_dev_stop:
1628 : : #endif
1629 : 0 : dev->data->dev_started = 0;
1630 : : /* Prevent crashes when queues are still in use. */
1631 : 0 : dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
1632 : 0 : dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
1633 : : rte_wmb();
1634 : : /* Disable datapath on secondary process. */
1635 : 0 : mlx5_mp_os_req_stop_rxtx(dev);
1636 : 0 : rte_delay_us_sleep(1000 * priv->rxqs_n);
1637 : 0 : DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id);
1638 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1639 : 0 : mlx5_flow_rxq_flags_clear(dev);
1640 : 0 : mlx5_flow_stop_default(dev);
1641 : : /* Control flows for default traffic can be removed firstly. */
1642 : 0 : mlx5_traffic_disable(dev);
1643 : : /* All RX queue flags will be cleared in the flush interface. */
1644 : 0 : mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_GEN, true);
1645 : 0 : mlx5_flow_meter_rxq_flush(dev);
1646 : 0 : mlx5_action_handle_detach(dev);
1647 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1648 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_templates(dev);
1649 : : #endif
1650 : 0 : mlx5_rx_intr_vec_disable(dev);
1651 : 0 : priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
1652 : 0 : priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
1653 : 0 : priv->sh->port[priv->dev_port - 1].nl_ih_port_id = RTE_MAX_ETHPORTS;
1654 : 0 : mlx5_txq_stop(dev);
1655 : 0 : mlx5_rxq_stop(dev);
1656 : 0 : mlx5_dev_free_consec_tx_mem(dev, true);
1657 [ # # ]: 0 : if (priv->obj_ops.lb_dummy_queue_release)
1658 : 0 : priv->obj_ops.lb_dummy_queue_release(dev);
1659 : 0 : mlx5_txpp_stop(dev);
1660 : :
1661 : 0 : return 0;
1662 : : }
1663 : :
1664 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1665 : :
1666 : : static int
1667 : 0 : mlx5_traffic_enable_hws(struct rte_eth_dev *dev)
1668 : : {
1669 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1670 : 0 : struct mlx5_sh_config *config = &priv->sh->config;
1671 : : uint64_t flags = 0;
1672 : : unsigned int i;
1673 : : int ret = 0;
1674 : :
1675 [ # # ]: 0 : for (i = 0; i < priv->txqs_n; ++i) {
1676 : 0 : struct mlx5_txq_ctrl *txq = mlx5_txq_get(dev, i);
1677 : : uint32_t queue;
1678 : :
1679 [ # # ]: 0 : if (!txq)
1680 : 0 : continue;
1681 : 0 : queue = mlx5_txq_get_sqn(txq);
1682 [ # # ]: 0 : if ((priv->representor || priv->master) &&
1683 [ # # ]: 0 : config->dv_esw_en &&
1684 : : config->fdb_def_rule) {
1685 [ # # ]: 0 : if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue, false)) {
1686 : 0 : mlx5_txq_release(dev, i);
1687 : 0 : goto error;
1688 : : }
1689 : : }
1690 [ # # ]: 0 : if (config->dv_esw_en) {
1691 [ # # ]: 0 : if (mlx5_flow_hw_create_tx_repr_matching_flow(dev, queue, false)) {
1692 : 0 : mlx5_txq_release(dev, i);
1693 : 0 : goto error;
1694 : : }
1695 : : }
1696 [ # # ]: 0 : if (mlx5_vport_tx_metadata_passing_enabled(priv->sh)) {
1697 [ # # ]: 0 : if (mlx5_flow_hw_create_nic_tx_default_mreg_copy_flow(dev, queue)) {
1698 : 0 : mlx5_txq_release(dev, i);
1699 : 0 : goto error;
1700 : : }
1701 : : }
1702 : 0 : mlx5_txq_release(dev, i);
1703 : : }
1704 [ # # ]: 0 : if (config->fdb_def_rule) {
1705 [ # # # # ]: 0 : if ((priv->master || priv->representor) && config->dv_esw_en) {
1706 [ # # ]: 0 : if (!mlx5_flow_hw_esw_create_default_jump_flow(dev))
1707 : 0 : priv->fdb_def_rule = 1;
1708 : : else
1709 : 0 : goto error;
1710 : : }
1711 : : } else {
1712 : 0 : DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id);
1713 : : }
1714 [ # # # # ]: 0 : if (mlx5_flow_lacp_miss_needed(dev) && mlx5_flow_hw_lacp_rx_flow(dev) != 0)
1715 : 0 : goto error;
1716 [ # # ]: 0 : if (priv->isolated)
1717 : : return 0;
1718 : 0 : ret = mlx5_flow_hw_create_ctrl_rx_tables(dev);
1719 [ # # ]: 0 : if (ret) {
1720 : 0 : DRV_LOG(ERR, "Failed to set up Rx control flow templates for port %u, %d",
1721 : : dev->data->port_id, -ret);
1722 : 0 : goto error;
1723 : : }
1724 [ # # ]: 0 : if (dev->data->promiscuous) {
1725 : : flags |= MLX5_CTRL_PROMISCUOUS;
1726 : : } else {
1727 [ # # ]: 0 : if (dev->data->all_multicast)
1728 : : flags |= MLX5_CTRL_ALL_MULTICAST;
1729 : : else
1730 : : flags |= (MLX5_CTRL_BROADCAST |
1731 : : MLX5_CTRL_IPV4_MULTICAST |
1732 : : MLX5_CTRL_IPV6_MULTICAST);
1733 : 0 : flags |= MLX5_CTRL_DMAC;
1734 : : }
1735 [ # # ]: 0 : if (priv->vlan_filter_n)
1736 : 0 : flags |= MLX5_CTRL_VLAN_FILTER;
1737 : 0 : return mlx5_flow_hw_ctrl_flows(dev, flags);
1738 : 0 : error:
1739 : 0 : ret = rte_errno;
1740 : 0 : mlx5_flow_hw_flush_ctrl_flows(dev);
1741 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_tables(dev);
1742 : 0 : rte_errno = ret;
1743 : 0 : return -rte_errno;
1744 : : }
1745 : :
1746 : : #endif
1747 : :
1748 : : /**
1749 : : * Enable traffic flows configured by control plane
1750 : : *
1751 : : * @param dev
1752 : : * Pointer to Ethernet device structure.
1753 : : *
1754 : : * @return
1755 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1756 : : */
1757 : : int
1758 : 0 : mlx5_traffic_enable(struct rte_eth_dev *dev)
1759 : : {
1760 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1761 : 0 : struct rte_flow_item_eth bcast = {
1762 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
1763 : : };
1764 : 0 : struct rte_flow_item_eth ipv6_multi_spec = {
1765 : : .hdr.dst_addr.addr_bytes = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 },
1766 : : };
1767 : 0 : struct rte_flow_item_eth ipv6_multi_mask = {
1768 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
1769 : : };
1770 : 0 : struct rte_flow_item_eth unicast = {
1771 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1772 : : };
1773 : 0 : struct rte_flow_item_eth unicast_mask = {
1774 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
1775 : : };
1776 : 0 : const unsigned int vlan_filter_n = priv->vlan_filter_n;
1777 : 0 : const struct rte_ether_addr cmp = {
1778 : : .addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1779 : : };
1780 : : unsigned int i;
1781 : : unsigned int j;
1782 : : int ret;
1783 : :
1784 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1785 : : return 0;
1786 : :
1787 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1788 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
1789 : 0 : return mlx5_traffic_enable_hws(dev);
1790 : : #endif
1791 : : /*
1792 : : * Hairpin txq default flow should be created no matter if it is
1793 : : * isolation mode. Or else all the packets to be sent will be sent
1794 : : * out directly without the TX flow actions, e.g. encapsulation.
1795 : : */
1796 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
1797 : 0 : struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
1798 [ # # ]: 0 : if (!txq_ctrl)
1799 : 0 : continue;
1800 : : /* Only Tx implicit mode requires the default Tx flow. */
1801 [ # # ]: 0 : if (txq_ctrl->is_hairpin &&
1802 [ # # ]: 0 : txq_ctrl->hairpin_conf.tx_explicit == 0 &&
1803 : 0 : txq_ctrl->hairpin_conf.peers[0].port ==
1804 [ # # ]: 0 : priv->dev_data->port_id) {
1805 : 0 : ret = mlx5_ctrl_flow_source_queue(dev,
1806 : 0 : mlx5_txq_get_sqn(txq_ctrl));
1807 [ # # ]: 0 : if (ret) {
1808 : 0 : mlx5_txq_release(dev, i);
1809 : 0 : goto error;
1810 : : }
1811 : : }
1812 [ # # ]: 0 : if (priv->sh->config.dv_esw_en) {
1813 : 0 : uint32_t q = mlx5_txq_get_sqn(txq_ctrl);
1814 : :
1815 [ # # ]: 0 : if (mlx5_flow_create_devx_sq_miss_flow(dev, q) == 0) {
1816 : 0 : mlx5_txq_release(dev, i);
1817 : 0 : DRV_LOG(ERR,
1818 : : "Port %u Tx queue %u SQ create representor devx default miss rule failed.",
1819 : : dev->data->port_id, i);
1820 : 0 : goto error;
1821 : : }
1822 : : }
1823 : 0 : mlx5_txq_release(dev, i);
1824 : : }
1825 [ # # ]: 0 : if (priv->sh->config.fdb_def_rule) {
1826 [ # # ]: 0 : if (priv->sh->config.dv_esw_en) {
1827 [ # # ]: 0 : if (mlx5_flow_create_esw_table_zero_flow(dev))
1828 : 0 : priv->fdb_def_rule = 1;
1829 : : else
1830 : 0 : DRV_LOG(INFO, "port %u FDB default rule cannot be configured - only Eswitch group 0 flows are supported.",
1831 : : dev->data->port_id);
1832 : : }
1833 : : } else {
1834 : 0 : DRV_LOG(INFO, "port %u FDB default rule is disabled",
1835 : : dev->data->port_id);
1836 : : }
1837 [ # # ]: 0 : if (mlx5_flow_lacp_miss_needed(dev)) {
1838 : 0 : ret = mlx5_flow_lacp_miss(dev);
1839 [ # # ]: 0 : if (ret)
1840 : 0 : DRV_LOG(INFO, "port %u LACP rule cannot be created - "
1841 : : "forward LACP to kernel.", dev->data->port_id);
1842 : : else
1843 : 0 : DRV_LOG(INFO, "LACP traffic will be missed in port %u.",
1844 : : dev->data->port_id);
1845 : : }
1846 [ # # ]: 0 : if (priv->isolated)
1847 : : return 0;
1848 [ # # ]: 0 : if (dev->data->promiscuous) {
1849 : 0 : struct rte_flow_item_eth promisc = {
1850 : : .hdr.dst_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1851 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1852 : : .hdr.ether_type = 0,
1853 : : };
1854 : :
1855 : 0 : ret = mlx5_ctrl_flow(dev, &promisc, &promisc);
1856 [ # # ]: 0 : if (ret)
1857 : 0 : goto error;
1858 : : }
1859 [ # # ]: 0 : if (dev->data->all_multicast) {
1860 : 0 : struct rte_flow_item_eth multicast = {
1861 : : .hdr.dst_addr.addr_bytes = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
1862 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1863 : : .hdr.ether_type = 0,
1864 : : };
1865 : :
1866 : 0 : ret = mlx5_ctrl_flow(dev, &multicast, &multicast);
1867 [ # # ]: 0 : if (ret)
1868 : 0 : goto error;
1869 : : } else {
1870 : : /* Add broadcast/multicast flows. */
1871 [ # # ]: 0 : for (i = 0; i != vlan_filter_n; ++i) {
1872 : 0 : uint16_t vlan = priv->vlan_filter[i];
1873 : :
1874 : 0 : struct rte_flow_item_vlan vlan_spec = {
1875 [ # # ]: 0 : .hdr.vlan_tci = rte_cpu_to_be_16(vlan),
1876 : : };
1877 : 0 : struct rte_flow_item_vlan vlan_mask =
1878 : : rte_flow_item_vlan_mask;
1879 : :
1880 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast,
1881 : : &vlan_spec, &vlan_mask);
1882 [ # # ]: 0 : if (ret)
1883 : 0 : goto error;
1884 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec,
1885 : : &ipv6_multi_mask,
1886 : : &vlan_spec, &vlan_mask);
1887 [ # # ]: 0 : if (ret)
1888 : 0 : goto error;
1889 : : }
1890 [ # # ]: 0 : if (!vlan_filter_n) {
1891 : 0 : ret = mlx5_ctrl_flow(dev, &bcast, &bcast);
1892 [ # # ]: 0 : if (ret)
1893 : 0 : goto error;
1894 : 0 : ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec,
1895 : : &ipv6_multi_mask);
1896 [ # # ]: 0 : if (ret) {
1897 : : /* Do not fail on IPv6 broadcast creation failure. */
1898 : 0 : DRV_LOG(WARNING,
1899 : : "IPv6 broadcast is not supported");
1900 : : ret = 0;
1901 : : }
1902 : : }
1903 : : }
1904 : : /* Add MAC address flows. */
1905 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
1906 : 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
1907 : :
1908 : : /* Add flows for unicast and multicast mac addresses added by API. */
1909 [ # # ]: 0 : if (!memcmp(mac, &cmp, sizeof(*mac)) ||
1910 [ # # ]: 0 : !BITFIELD_ISSET(priv->mac_own, i) ||
1911 [ # # # # ]: 0 : (dev->data->all_multicast && rte_is_multicast_ether_addr(mac)))
1912 : 0 : continue;
1913 : : memcpy(&unicast.hdr.dst_addr.addr_bytes,
1914 : : mac->addr_bytes,
1915 : : RTE_ETHER_ADDR_LEN);
1916 [ # # ]: 0 : for (j = 0; j != vlan_filter_n; ++j) {
1917 : 0 : uint16_t vlan = priv->vlan_filter[j];
1918 : :
1919 : 0 : struct rte_flow_item_vlan vlan_spec = {
1920 [ # # ]: 0 : .hdr.vlan_tci = rte_cpu_to_be_16(vlan),
1921 : : };
1922 : 0 : struct rte_flow_item_vlan vlan_mask =
1923 : : rte_flow_item_vlan_mask;
1924 : :
1925 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &unicast,
1926 : : &unicast_mask,
1927 : : &vlan_spec,
1928 : : &vlan_mask);
1929 [ # # ]: 0 : if (ret)
1930 : 0 : goto error;
1931 : : }
1932 [ # # ]: 0 : if (!vlan_filter_n) {
1933 : 0 : ret = mlx5_ctrl_flow(dev, &unicast, &unicast_mask);
1934 [ # # ]: 0 : if (ret)
1935 : 0 : goto error;
1936 : : }
1937 : : }
1938 : : return 0;
1939 : 0 : error:
1940 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
1941 : 0 : mlx5_traffic_disable_legacy(dev);
1942 : 0 : rte_errno = ret; /* Restore rte_errno. */
1943 : 0 : return -rte_errno;
1944 : : }
1945 : :
1946 : : static void
1947 : 0 : mlx5_traffic_disable_legacy(struct rte_eth_dev *dev)
1948 : : {
1949 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1950 : : struct mlx5_ctrl_flow_entry *entry;
1951 : : struct mlx5_ctrl_flow_entry *tmp;
1952 : :
1953 : : /*
1954 : : * Free registered control flow rules first,
1955 : : * to free the memory allocated for list entries
1956 : : */
1957 : 0 : entry = LIST_FIRST(&priv->hw_ctrl_flows);
1958 [ # # ]: 0 : while (entry != NULL) {
1959 : 0 : tmp = LIST_NEXT(entry, next);
1960 : 0 : mlx5_legacy_ctrl_flow_destroy(dev, entry);
1961 : : entry = tmp;
1962 : : }
1963 : :
1964 : 0 : mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false);
1965 : 0 : }
1966 : :
1967 : : /**
1968 : : * Disable traffic flows configured by control plane
1969 : : *
1970 : : * @param dev
1971 : : * Pointer to Ethernet device private data.
1972 : : */
1973 : : void
1974 : 0 : mlx5_traffic_disable(struct rte_eth_dev *dev)
1975 : : {
1976 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1977 : : return;
1978 : :
1979 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1980 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1981 : :
1982 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1983 : : /* Device started flag was cleared before, this is used to derefer the Rx queues. */
1984 : 0 : priv->hws_rule_flushing = true;
1985 : 0 : mlx5_flow_hw_flush_ctrl_flows(dev);
1986 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_tables(dev);
1987 : 0 : priv->hws_rule_flushing = false;
1988 : : }
1989 : : else
1990 : : #endif
1991 : 0 : mlx5_traffic_disable_legacy(dev);
1992 : : }
1993 : :
1994 : : /**
1995 : : * Restart traffic flows configured by control plane
1996 : : *
1997 : : * @param dev
1998 : : * Pointer to Ethernet device private data.
1999 : : *
2000 : : * @return
2001 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
2002 : : */
2003 : : int
2004 : 0 : mlx5_traffic_restart(struct rte_eth_dev *dev)
2005 : : {
2006 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
2007 : : return 0;
2008 : :
2009 [ # # ]: 0 : if (dev->data->dev_started) {
2010 : 0 : mlx5_traffic_disable(dev);
2011 : : #ifdef HAVE_MLX5_HWS_SUPPORT
2012 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_templates(dev);
2013 : : #endif
2014 : 0 : return mlx5_traffic_enable(dev);
2015 : : }
2016 : : return 0;
2017 : : }
2018 : :
2019 : : static bool
2020 : 0 : mac_flows_update_needed(struct rte_eth_dev *dev)
2021 : : {
2022 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2023 : :
2024 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
2025 : : return false;
2026 [ # # ]: 0 : if (!dev->data->dev_started)
2027 : : return false;
2028 [ # # ]: 0 : if (dev->data->promiscuous)
2029 : : return false;
2030 [ # # ]: 0 : if (priv->isolated)
2031 : 0 : return false;
2032 : :
2033 : : return true;
2034 : : }
2035 : :
2036 : : static int
2037 : 0 : traffic_dmac_create(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2038 : : {
2039 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2040 : :
2041 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2042 : 0 : return mlx5_flow_hw_ctrl_flow_dmac(dev, addr);
2043 : : else
2044 : 0 : return mlx5_legacy_dmac_flow_create(dev, addr);
2045 : : }
2046 : :
2047 : : static int
2048 : 0 : traffic_dmac_destroy(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2049 : : {
2050 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2051 : :
2052 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2053 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_destroy(dev, addr);
2054 : : else
2055 : 0 : return mlx5_legacy_dmac_flow_destroy(dev, addr);
2056 : : }
2057 : :
2058 : : static int
2059 : 0 : traffic_dmac_vlan_create(struct rte_eth_dev *dev,
2060 : : const struct rte_ether_addr *addr,
2061 : : const uint16_t vid)
2062 : : {
2063 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2064 : :
2065 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2066 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_vlan(dev, addr, vid);
2067 : : else
2068 : 0 : return mlx5_legacy_dmac_vlan_flow_create(dev, addr, vid);
2069 : : }
2070 : :
2071 : : static int
2072 : 0 : traffic_dmac_vlan_destroy(struct rte_eth_dev *dev,
2073 : : const struct rte_ether_addr *addr,
2074 : : const uint16_t vid)
2075 : : {
2076 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2077 : :
2078 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2079 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_vlan_destroy(dev, addr, vid);
2080 : : else
2081 : 0 : return mlx5_legacy_dmac_vlan_flow_destroy(dev, addr, vid);
2082 : : }
2083 : :
2084 : : /**
2085 : : * Adjust Rx control flow rules to allow traffic on provided MAC address.
2086 : : */
2087 : : int
2088 : 0 : mlx5_traffic_mac_add(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2089 : : {
2090 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2091 : :
2092 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2093 : : return 0;
2094 : :
2095 [ # # ]: 0 : if (priv->vlan_filter_n > 0) {
2096 : : unsigned int i;
2097 : :
2098 [ # # ]: 0 : for (i = 0; i < priv->vlan_filter_n; ++i) {
2099 : 0 : uint16_t vlan = priv->vlan_filter[i];
2100 : : int ret;
2101 : :
2102 [ # # ]: 0 : if (mlx5_ctrl_flow_uc_dmac_vlan_exists(dev, addr, vlan))
2103 : 0 : continue;
2104 : :
2105 : 0 : ret = traffic_dmac_vlan_create(dev, addr, vlan);
2106 [ # # ]: 0 : if (ret != 0)
2107 : 0 : return ret;
2108 : : }
2109 : :
2110 : : return 0;
2111 : : }
2112 : :
2113 [ # # ]: 0 : if (mlx5_ctrl_flow_uc_dmac_exists(dev, addr))
2114 : : return 0;
2115 : :
2116 : 0 : return traffic_dmac_create(dev, addr);
2117 : : }
2118 : :
2119 : : /**
2120 : : * Adjust Rx control flow rules to disallow traffic with removed MAC address.
2121 : : */
2122 : : int
2123 : 0 : mlx5_traffic_mac_remove(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2124 : : {
2125 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2126 : :
2127 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2128 : : return 0;
2129 : :
2130 [ # # ]: 0 : if (priv->vlan_filter_n > 0) {
2131 : : unsigned int i;
2132 : :
2133 [ # # ]: 0 : for (i = 0; i < priv->vlan_filter_n; ++i) {
2134 : 0 : uint16_t vlan = priv->vlan_filter[i];
2135 : : int ret;
2136 : :
2137 [ # # ]: 0 : if (!mlx5_ctrl_flow_uc_dmac_vlan_exists(dev, addr, vlan))
2138 : 0 : continue;
2139 : :
2140 : 0 : ret = traffic_dmac_vlan_destroy(dev, addr, vlan);
2141 [ # # ]: 0 : if (ret != 0)
2142 : 0 : return ret;
2143 : : }
2144 : :
2145 : : return 0;
2146 : : }
2147 : :
2148 [ # # ]: 0 : if (!mlx5_ctrl_flow_uc_dmac_exists(dev, addr))
2149 : : return 0;
2150 : :
2151 : 0 : return traffic_dmac_destroy(dev, addr);
2152 : : }
2153 : :
2154 : : /**
2155 : : * Adjust Rx control flow rules to allow traffic on provided VLAN.
2156 : : *
2157 : : * Assumptions:
2158 : : * - Called when VLAN is added.
2159 : : * - At least one VLAN is enabled before function call.
2160 : : *
2161 : : * This functions assumes that VLAN is new and was not included in
2162 : : * Rx control flow rules set up before calling it.
2163 : : */
2164 : : int
2165 : 0 : mlx5_traffic_vlan_add(struct rte_eth_dev *dev, const uint16_t vid)
2166 : : {
2167 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2168 : : unsigned int i;
2169 : : int ret;
2170 : :
2171 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2172 : : return 0;
2173 : :
2174 : : /* Add all unicast DMAC flow rules with new VLAN attached. */
2175 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2176 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2177 : :
2178 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2179 : 0 : continue;
2180 : :
2181 : 0 : ret = traffic_dmac_vlan_create(dev, mac, vid);
2182 [ # # ]: 0 : if (ret != 0)
2183 : 0 : return ret;
2184 : : }
2185 : :
2186 [ # # ]: 0 : if (priv->vlan_filter_n == 1) {
2187 : : /*
2188 : : * Adding first VLAN. Need to remove unicast DMAC rules before adding new rules.
2189 : : * Removing after creating VLAN rules so that traffic "gap" is not introduced.
2190 : : */
2191 : :
2192 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2193 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2194 : :
2195 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2196 : 0 : continue;
2197 : :
2198 : 0 : ret = traffic_dmac_destroy(dev, mac);
2199 [ # # ]: 0 : if (ret != 0)
2200 : 0 : return ret;
2201 : : }
2202 : : }
2203 : :
2204 : : return 0;
2205 : : }
2206 : :
2207 : : /**
2208 : : * Adjust Rx control flow rules to disallow traffic with removed VLAN.
2209 : : *
2210 : : * Assumptions:
2211 : : *
2212 : : * - VLAN was really removed.
2213 : : */
2214 : : int
2215 : 0 : mlx5_traffic_vlan_remove(struct rte_eth_dev *dev, const uint16_t vid)
2216 : : {
2217 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2218 : : unsigned int i;
2219 : : int ret;
2220 : :
2221 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2222 : : return 0;
2223 : :
2224 [ # # ]: 0 : if (priv->vlan_filter_n == 0) {
2225 : : /*
2226 : : * If there are no VLANs as a result, unicast DMAC flow rules must be recreated.
2227 : : * Recreating first to ensure no traffic "gap".
2228 : : */
2229 : :
2230 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2231 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2232 : :
2233 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2234 : 0 : continue;
2235 : :
2236 : 0 : ret = traffic_dmac_create(dev, mac);
2237 [ # # ]: 0 : if (ret != 0)
2238 : 0 : return ret;
2239 : : }
2240 : : }
2241 : :
2242 : : /* Remove all unicast DMAC flow rules with this VLAN. */
2243 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2244 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2245 : :
2246 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2247 : 0 : continue;
2248 : :
2249 : 0 : ret = traffic_dmac_vlan_destroy(dev, mac, vid);
2250 [ # # ]: 0 : if (ret != 0)
2251 : 0 : return ret;
2252 : : }
2253 : :
2254 : : return 0;
2255 : : }
|