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 : if (priv->sh->dev_cap.vf || priv->sh->dev_cap.sf) {
1459 [ # # ]: 0 : if (mlx5_os_get_promisc(dev) != dev->data->promiscuous) {
1460 [ # # ]: 0 : DRV_LOG(INFO, "port %u forcing promiscuous mode to %s",
1461 : : dev->data->port_id,
1462 : : dev->data->promiscuous ? "enabled" : "disabled");
1463 : 0 : mlx5_os_set_promisc(dev, dev->data->promiscuous);
1464 : : }
1465 [ # # ]: 0 : if (mlx5_os_get_allmulti(dev) != dev->data->all_multicast) {
1466 [ # # ]: 0 : DRV_LOG(INFO, "port %u forcing all multicast mode to %s",
1467 : : dev->data->port_id,
1468 : : dev->data->all_multicast ? "enabled" : "disabled");
1469 : 0 : mlx5_os_set_allmulti(dev, dev->data->all_multicast);
1470 : : }
1471 : : }
1472 : 0 : ret = mlx5_traffic_enable(dev);
1473 [ # # ]: 0 : if (ret) {
1474 : 0 : DRV_LOG(ERR, "port %u failed to set defaults flows",
1475 : : dev->data->port_id);
1476 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1477 : 0 : goto action_handle_detach;
1478 : : }
1479 : : /* Set dynamic fields and flags into Rx queues. */
1480 : 0 : mlx5_flow_rxq_dynf_set(dev);
1481 : : /* Set flags and context to convert Rx timestamps. */
1482 : 0 : mlx5_rxq_timestamp_set(dev);
1483 : : /* Set a mask and offset of scheduling on timestamp into Tx queues. */
1484 : 0 : mlx5_txq_dynf_timestamp_set(dev);
1485 : : /*
1486 : : * In non-cached mode, it only needs to start the default mreg copy
1487 : : * action and no flow created by application exists anymore.
1488 : : * But it is worth wrapping the interface for further usage.
1489 : : */
1490 : 0 : ret = mlx5_flow_start_default(dev);
1491 [ # # ]: 0 : if (ret) {
1492 : 0 : DRV_LOG(DEBUG, "port %u failed to start default actions: %s",
1493 : : dev->data->port_id, strerror(rte_errno));
1494 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1495 : 0 : goto traffic_disable;
1496 : : }
1497 [ # # ]: 0 : if (mlx5_dev_ctx_shared_mempool_subscribe(dev) != 0) {
1498 : 0 : DRV_LOG(ERR, "port %u failed to subscribe for mempool life cycle: %s",
1499 : : dev->data->port_id, rte_strerror(rte_errno));
1500 : 0 : SAVE_RTE_ERRNO_AND_STOP(ret, dev);
1501 : 0 : goto stop_default;
1502 : : }
1503 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1504 : 0 : mlx5_flow_rxq_mark_flag_set(dev);
1505 : : rte_wmb();
1506 : 0 : dev->tx_pkt_burst = mlx5_select_tx_function(dev);
1507 : 0 : dev->rx_pkt_burst = mlx5_select_rx_function(dev);
1508 : : /* Enable datapath on secondary process. */
1509 : 0 : mlx5_mp_os_req_start_rxtx(dev);
1510 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle) >= 0) {
1511 : 0 : priv->sh->port[priv->dev_port - 1].ih_port_id =
1512 : 0 : (uint32_t)dev->data->port_id;
1513 : : } else {
1514 : 0 : DRV_LOG(INFO, "port %u starts without RMV interrupts.",
1515 : : dev->data->port_id);
1516 : 0 : dev->data->dev_conf.intr_conf.rmv = 0;
1517 : : }
1518 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle_nl) >= 0) {
1519 : 0 : priv->sh->port[priv->dev_port - 1].nl_ih_port_id =
1520 : 0 : (uint32_t)dev->data->port_id;
1521 : : } else {
1522 : 0 : DRV_LOG(INFO, "port %u starts without LSC interrupts.",
1523 : : dev->data->port_id);
1524 : 0 : dev->data->dev_conf.intr_conf.lsc = 0;
1525 : : }
1526 [ # # ]: 0 : if (rte_intr_fd_get(priv->sh->intr_handle_devx) >= 0)
1527 : 0 : priv->sh->port[priv->dev_port - 1].devx_ih_port_id =
1528 : 0 : (uint32_t)dev->data->port_id;
1529 : : return 0;
1530 : : stop_default:
1531 : 0 : mlx5_flow_stop_default(dev);
1532 : 0 : traffic_disable:
1533 : 0 : mlx5_traffic_disable(dev);
1534 : 0 : action_handle_detach:
1535 : 0 : mlx5_action_handle_detach(dev);
1536 : 0 : rx_intr_vec_disable:
1537 : 0 : mlx5_rx_intr_vec_disable(dev);
1538 : 0 : rxq_stop:
1539 : 0 : mlx5_rxq_stop(dev);
1540 : 0 : txq_stop:
1541 : 0 : mlx5_txq_stop(dev);
1542 : 0 : free_consec_tx_mem:
1543 : 0 : mlx5_dev_free_consec_tx_mem(dev, false);
1544 : 0 : lb_dummy_queue_release:
1545 [ # # ]: 0 : if (priv->obj_ops.lb_dummy_queue_release)
1546 : 0 : priv->obj_ops.lb_dummy_queue_release(dev);
1547 : 0 : txpp_stop:
1548 : 0 : mlx5_txpp_stop(dev);
1549 : 0 : error:
1550 : 0 : rte_errno = ret;
1551 : 0 : return -rte_errno;
1552 : : }
1553 : :
1554 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1555 : : /**
1556 : : * Check if stopping transfer proxy port is allowed.
1557 : : *
1558 : : * If transfer proxy port is configured for HWS, then it is allowed to stop it
1559 : : * if and only if all other representor ports are stopped.
1560 : : *
1561 : : * @param dev
1562 : : * Pointer to Ethernet device structure.
1563 : : *
1564 : : * @return
1565 : : * If stopping transfer proxy port is allowed, then 0 is returned.
1566 : : * Otherwise rte_errno is set, and negative errno value is returned.
1567 : : */
1568 : : static int
1569 : 0 : mlx5_hw_proxy_port_allowed_stop(struct rte_eth_dev *dev)
1570 : : {
1571 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1572 : : bool representor_started = false;
1573 : : uint16_t port_id;
1574 : :
1575 : : MLX5_ASSERT(priv->sh->config.dv_flow_en == 2);
1576 : : MLX5_ASSERT(priv->sh->config.dv_esw_en);
1577 : : MLX5_ASSERT(priv->master);
1578 : : /* If transfer proxy port was not configured for HWS, then stopping it is allowed. */
1579 [ # # ]: 0 : if (!priv->dr_ctx)
1580 : : return 0;
1581 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
1582 : 0 : const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id];
1583 : 0 : const struct mlx5_priv *port_priv = port_dev->data->dev_private;
1584 : :
1585 [ # # ]: 0 : if (port_id != dev->data->port_id &&
1586 [ # # # # ]: 0 : port_priv->domain_id == priv->domain_id &&
1587 : : port_dev->data->dev_started)
1588 : : representor_started = true;
1589 : : }
1590 [ # # ]: 0 : if (representor_started) {
1591 : 0 : DRV_LOG(ERR, "Failed to stop port %u: attached representor ports"
1592 : : " must be stopped before stopping transfer proxy port",
1593 : : dev->data->port_id);
1594 : 0 : rte_errno = EBUSY;
1595 : 0 : return -rte_errno;
1596 : : }
1597 : : return 0;
1598 : : }
1599 : : #endif
1600 : :
1601 : : /**
1602 : : * DPDK callback to stop the device.
1603 : : *
1604 : : * Simulate device stop by detaching all configured flows.
1605 : : *
1606 : : * @param dev
1607 : : * Pointer to Ethernet device structure.
1608 : : *
1609 : : * @return
1610 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1611 : : * The following error values are defined:
1612 : : *
1613 : : * - -EBUSY: If transfer proxy port cannot be stopped,
1614 : : * because other port representors are still running.
1615 : : */
1616 : : int
1617 : 0 : mlx5_dev_stop(struct rte_eth_dev *dev)
1618 : : {
1619 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1620 : :
1621 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1622 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1623 : : /*
1624 : : * If steering is disabled,
1625 : : * then there are no limitations regarding port stop ordering,
1626 : : * since no flow rules need to be destroyed as part of port stop.
1627 : : */
1628 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1629 : 0 : goto continue_dev_stop;
1630 : : /* If there is no E-Switch, then there are no start/stop order limitations. */
1631 [ # # ]: 0 : if (!priv->sh->config.dv_esw_en)
1632 : 0 : goto continue_dev_stop;
1633 : : /* If representor is being stopped, then it is always allowed. */
1634 [ # # ]: 0 : if (priv->representor)
1635 : 0 : goto continue_dev_stop;
1636 [ # # ]: 0 : if (mlx5_hw_proxy_port_allowed_stop(dev)) {
1637 : 0 : dev->data->dev_started = 1;
1638 : 0 : return -rte_errno;
1639 : : }
1640 : : }
1641 : 0 : continue_dev_stop:
1642 : : #endif
1643 : 0 : dev->data->dev_started = 0;
1644 : : /* Prevent crashes when queues are still in use. */
1645 : 0 : dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
1646 : 0 : dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
1647 : : rte_wmb();
1648 : : /* Disable datapath on secondary process. */
1649 : 0 : mlx5_mp_os_req_stop_rxtx(dev);
1650 : 0 : rte_delay_us_sleep(1000 * priv->rxqs_n);
1651 : 0 : DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id);
1652 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1653 : 0 : mlx5_flow_rxq_flags_clear(dev);
1654 : 0 : mlx5_flow_stop_default(dev);
1655 : : /* Control flows for default traffic can be removed firstly. */
1656 : 0 : mlx5_traffic_disable(dev);
1657 : : /* All RX queue flags will be cleared in the flush interface. */
1658 : 0 : mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_GEN, true);
1659 : 0 : mlx5_flow_meter_rxq_flush(dev);
1660 : 0 : mlx5_action_handle_detach(dev);
1661 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1662 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_templates(dev);
1663 : : #endif
1664 : 0 : mlx5_rx_intr_vec_disable(dev);
1665 : 0 : priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
1666 : 0 : priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
1667 : 0 : priv->sh->port[priv->dev_port - 1].nl_ih_port_id = RTE_MAX_ETHPORTS;
1668 : 0 : mlx5_txq_stop(dev);
1669 : 0 : mlx5_rxq_stop(dev);
1670 : 0 : mlx5_dev_free_consec_tx_mem(dev, true);
1671 [ # # ]: 0 : if (priv->obj_ops.lb_dummy_queue_release)
1672 : 0 : priv->obj_ops.lb_dummy_queue_release(dev);
1673 : 0 : mlx5_txpp_stop(dev);
1674 : :
1675 : 0 : return 0;
1676 : : }
1677 : :
1678 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1679 : :
1680 : : static int
1681 : 0 : mlx5_traffic_enable_hws(struct rte_eth_dev *dev)
1682 : : {
1683 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1684 : 0 : struct mlx5_sh_config *config = &priv->sh->config;
1685 : : uint64_t flags = 0;
1686 : : unsigned int i;
1687 : : int ret = 0;
1688 : :
1689 [ # # ]: 0 : for (i = 0; i < priv->txqs_n; ++i) {
1690 : 0 : struct mlx5_txq_ctrl *txq = mlx5_txq_get(dev, i);
1691 : : uint32_t queue;
1692 : :
1693 [ # # ]: 0 : if (!txq)
1694 : 0 : continue;
1695 : 0 : queue = mlx5_txq_get_sqn(txq);
1696 [ # # ]: 0 : if ((priv->representor || priv->master) &&
1697 [ # # ]: 0 : config->dv_esw_en &&
1698 : : config->fdb_def_rule) {
1699 [ # # ]: 0 : if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue, false)) {
1700 : 0 : mlx5_txq_release(dev, i);
1701 : 0 : goto error;
1702 : : }
1703 : : }
1704 [ # # ]: 0 : if (config->dv_esw_en) {
1705 [ # # ]: 0 : if (mlx5_flow_hw_create_tx_repr_matching_flow(dev, queue, false)) {
1706 : 0 : mlx5_txq_release(dev, i);
1707 : 0 : goto error;
1708 : : }
1709 : : }
1710 [ # # ]: 0 : if (mlx5_vport_tx_metadata_passing_enabled(priv->sh)) {
1711 [ # # ]: 0 : if (mlx5_flow_hw_create_nic_tx_default_mreg_copy_flow(dev, queue)) {
1712 : 0 : mlx5_txq_release(dev, i);
1713 : 0 : goto error;
1714 : : }
1715 : : }
1716 : 0 : mlx5_txq_release(dev, i);
1717 : : }
1718 [ # # ]: 0 : if (config->fdb_def_rule) {
1719 [ # # # # ]: 0 : if ((priv->master || priv->representor) && config->dv_esw_en) {
1720 [ # # ]: 0 : if (!mlx5_flow_hw_esw_create_default_jump_flow(dev))
1721 : 0 : priv->fdb_def_rule = 1;
1722 : : else
1723 : 0 : goto error;
1724 : : }
1725 : : } else {
1726 : 0 : DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id);
1727 : : }
1728 [ # # # # ]: 0 : if (mlx5_flow_lacp_miss_needed(dev) && mlx5_flow_hw_lacp_rx_flow(dev) != 0)
1729 : 0 : goto error;
1730 [ # # ]: 0 : if (priv->isolated)
1731 : : return 0;
1732 : 0 : ret = mlx5_flow_hw_create_ctrl_rx_tables(dev);
1733 [ # # ]: 0 : if (ret) {
1734 : 0 : DRV_LOG(ERR, "Failed to set up Rx control flow templates for port %u, %d",
1735 : : dev->data->port_id, -ret);
1736 : 0 : goto error;
1737 : : }
1738 [ # # ]: 0 : if (dev->data->promiscuous) {
1739 : : flags |= MLX5_CTRL_PROMISCUOUS;
1740 : : } else {
1741 [ # # ]: 0 : if (dev->data->all_multicast)
1742 : : flags |= MLX5_CTRL_ALL_MULTICAST;
1743 : : else
1744 : : flags |= (MLX5_CTRL_BROADCAST |
1745 : : MLX5_CTRL_IPV4_MULTICAST |
1746 : : MLX5_CTRL_IPV6_MULTICAST);
1747 : 0 : flags |= MLX5_CTRL_DMAC;
1748 : : }
1749 [ # # ]: 0 : if (priv->vlan_filter_n)
1750 : 0 : flags |= MLX5_CTRL_VLAN_FILTER;
1751 : 0 : return mlx5_flow_hw_ctrl_flows(dev, flags);
1752 : 0 : error:
1753 : 0 : ret = rte_errno;
1754 : 0 : mlx5_flow_hw_flush_ctrl_flows(dev);
1755 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_tables(dev);
1756 : 0 : rte_errno = ret;
1757 : 0 : return -rte_errno;
1758 : : }
1759 : :
1760 : : #endif
1761 : :
1762 : : /**
1763 : : * Enable traffic flows configured by control plane
1764 : : *
1765 : : * @param dev
1766 : : * Pointer to Ethernet device structure.
1767 : : *
1768 : : * @return
1769 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1770 : : */
1771 : : int
1772 : 0 : mlx5_traffic_enable(struct rte_eth_dev *dev)
1773 : : {
1774 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1775 : 0 : struct rte_flow_item_eth bcast = {
1776 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
1777 : : };
1778 : 0 : struct rte_flow_item_eth ipv6_multi_spec = {
1779 : : .hdr.dst_addr.addr_bytes = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 },
1780 : : };
1781 : 0 : struct rte_flow_item_eth ipv6_multi_mask = {
1782 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 },
1783 : : };
1784 : 0 : struct rte_flow_item_eth unicast = {
1785 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1786 : : };
1787 : 0 : struct rte_flow_item_eth unicast_mask = {
1788 : : .hdr.dst_addr.addr_bytes = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
1789 : : };
1790 : 0 : const unsigned int vlan_filter_n = priv->vlan_filter_n;
1791 : 0 : const struct rte_ether_addr cmp = {
1792 : : .addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1793 : : };
1794 : : unsigned int i;
1795 : : unsigned int j;
1796 : : int ret;
1797 : :
1798 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1799 : : return 0;
1800 : :
1801 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1802 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
1803 : 0 : return mlx5_traffic_enable_hws(dev);
1804 : : #endif
1805 : : /*
1806 : : * Hairpin txq default flow should be created no matter if it is
1807 : : * isolation mode. Or else all the packets to be sent will be sent
1808 : : * out directly without the TX flow actions, e.g. encapsulation.
1809 : : */
1810 [ # # ]: 0 : for (i = 0; i != priv->txqs_n; ++i) {
1811 : 0 : struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
1812 [ # # ]: 0 : if (!txq_ctrl)
1813 : 0 : continue;
1814 : : /* Only Tx implicit mode requires the default Tx flow. */
1815 [ # # ]: 0 : if (txq_ctrl->is_hairpin &&
1816 [ # # ]: 0 : txq_ctrl->hairpin_conf.tx_explicit == 0 &&
1817 : 0 : txq_ctrl->hairpin_conf.peers[0].port ==
1818 [ # # ]: 0 : priv->dev_data->port_id) {
1819 : 0 : ret = mlx5_ctrl_flow_source_queue(dev,
1820 : 0 : mlx5_txq_get_sqn(txq_ctrl));
1821 [ # # ]: 0 : if (ret) {
1822 : 0 : mlx5_txq_release(dev, i);
1823 : 0 : goto error;
1824 : : }
1825 : : }
1826 [ # # ]: 0 : if (priv->sh->config.dv_esw_en) {
1827 : 0 : uint32_t q = mlx5_txq_get_sqn(txq_ctrl);
1828 : :
1829 [ # # ]: 0 : if (mlx5_flow_create_devx_sq_miss_flow(dev, q) == 0) {
1830 : 0 : mlx5_txq_release(dev, i);
1831 : 0 : DRV_LOG(ERR,
1832 : : "Port %u Tx queue %u SQ create representor devx default miss rule failed.",
1833 : : dev->data->port_id, i);
1834 : 0 : goto error;
1835 : : }
1836 : : }
1837 : 0 : mlx5_txq_release(dev, i);
1838 : : }
1839 [ # # ]: 0 : if (priv->sh->config.fdb_def_rule) {
1840 [ # # ]: 0 : if (priv->sh->config.dv_esw_en) {
1841 [ # # ]: 0 : if (mlx5_flow_create_esw_table_zero_flow(dev))
1842 : 0 : priv->fdb_def_rule = 1;
1843 : : else
1844 : 0 : DRV_LOG(INFO, "port %u FDB default rule cannot be configured - only Eswitch group 0 flows are supported.",
1845 : : dev->data->port_id);
1846 : : }
1847 : : } else {
1848 : 0 : DRV_LOG(INFO, "port %u FDB default rule is disabled",
1849 : : dev->data->port_id);
1850 : : }
1851 [ # # ]: 0 : if (mlx5_flow_lacp_miss_needed(dev)) {
1852 : 0 : ret = mlx5_flow_lacp_miss(dev);
1853 [ # # ]: 0 : if (ret)
1854 : 0 : DRV_LOG(INFO, "port %u LACP rule cannot be created - "
1855 : : "forward LACP to kernel.", dev->data->port_id);
1856 : : else
1857 : 0 : DRV_LOG(INFO, "LACP traffic will be missed in port %u.",
1858 : : dev->data->port_id);
1859 : : }
1860 [ # # ]: 0 : if (priv->isolated)
1861 : : return 0;
1862 [ # # ]: 0 : if (dev->data->promiscuous) {
1863 : 0 : struct rte_flow_item_eth promisc = {
1864 : : .hdr.dst_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1865 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1866 : : .hdr.ether_type = 0,
1867 : : };
1868 : :
1869 : 0 : ret = mlx5_ctrl_flow(dev, &promisc, &promisc);
1870 [ # # ]: 0 : if (ret)
1871 : 0 : goto error;
1872 : : }
1873 [ # # ]: 0 : if (dev->data->all_multicast) {
1874 : 0 : struct rte_flow_item_eth multicast = {
1875 : : .hdr.dst_addr.addr_bytes = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 },
1876 : : .hdr.src_addr.addr_bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
1877 : : .hdr.ether_type = 0,
1878 : : };
1879 : :
1880 : 0 : ret = mlx5_ctrl_flow(dev, &multicast, &multicast);
1881 [ # # ]: 0 : if (ret)
1882 : 0 : goto error;
1883 : : } else {
1884 : : /* Add broadcast/multicast flows. */
1885 [ # # ]: 0 : for (i = 0; i != vlan_filter_n; ++i) {
1886 : 0 : uint16_t vlan = priv->vlan_filter[i];
1887 : :
1888 : 0 : struct rte_flow_item_vlan vlan_spec = {
1889 [ # # ]: 0 : .hdr.vlan_tci = rte_cpu_to_be_16(vlan),
1890 : : };
1891 : 0 : struct rte_flow_item_vlan vlan_mask =
1892 : : rte_flow_item_vlan_mask;
1893 : :
1894 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast,
1895 : : &vlan_spec, &vlan_mask);
1896 [ # # ]: 0 : if (ret)
1897 : 0 : goto error;
1898 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec,
1899 : : &ipv6_multi_mask,
1900 : : &vlan_spec, &vlan_mask);
1901 [ # # ]: 0 : if (ret)
1902 : 0 : goto error;
1903 : : }
1904 [ # # ]: 0 : if (!vlan_filter_n) {
1905 : 0 : ret = mlx5_ctrl_flow(dev, &bcast, &bcast);
1906 [ # # ]: 0 : if (ret)
1907 : 0 : goto error;
1908 : 0 : ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec,
1909 : : &ipv6_multi_mask);
1910 [ # # ]: 0 : if (ret) {
1911 : : /* Do not fail on IPv6 broadcast creation failure. */
1912 : 0 : DRV_LOG(WARNING,
1913 : : "IPv6 broadcast is not supported");
1914 : : ret = 0;
1915 : : }
1916 : : }
1917 : : }
1918 : : /* Add MAC address flows. */
1919 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
1920 : 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
1921 : :
1922 : : /* Add flows for unicast and multicast mac addresses added by API. */
1923 [ # # ]: 0 : if (!memcmp(mac, &cmp, sizeof(*mac)) ||
1924 [ # # ]: 0 : !BITFIELD_ISSET(priv->mac_own, i) ||
1925 [ # # # # ]: 0 : (dev->data->all_multicast && rte_is_multicast_ether_addr(mac)))
1926 : 0 : continue;
1927 : : memcpy(&unicast.hdr.dst_addr.addr_bytes,
1928 : : mac->addr_bytes,
1929 : : RTE_ETHER_ADDR_LEN);
1930 [ # # ]: 0 : for (j = 0; j != vlan_filter_n; ++j) {
1931 : 0 : uint16_t vlan = priv->vlan_filter[j];
1932 : :
1933 : 0 : struct rte_flow_item_vlan vlan_spec = {
1934 [ # # ]: 0 : .hdr.vlan_tci = rte_cpu_to_be_16(vlan),
1935 : : };
1936 : 0 : struct rte_flow_item_vlan vlan_mask =
1937 : : rte_flow_item_vlan_mask;
1938 : :
1939 : 0 : ret = mlx5_ctrl_flow_vlan(dev, &unicast,
1940 : : &unicast_mask,
1941 : : &vlan_spec,
1942 : : &vlan_mask);
1943 [ # # ]: 0 : if (ret)
1944 : 0 : goto error;
1945 : : }
1946 [ # # ]: 0 : if (!vlan_filter_n) {
1947 : 0 : ret = mlx5_ctrl_flow(dev, &unicast, &unicast_mask);
1948 [ # # ]: 0 : if (ret)
1949 : 0 : goto error;
1950 : : }
1951 : : }
1952 : : return 0;
1953 : 0 : error:
1954 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
1955 : 0 : mlx5_traffic_disable_legacy(dev);
1956 : 0 : rte_errno = ret; /* Restore rte_errno. */
1957 : 0 : return -rte_errno;
1958 : : }
1959 : :
1960 : : static void
1961 : 0 : mlx5_traffic_disable_legacy(struct rte_eth_dev *dev)
1962 : : {
1963 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1964 : : struct mlx5_ctrl_flow_entry *entry;
1965 : : struct mlx5_ctrl_flow_entry *tmp;
1966 : :
1967 : : /*
1968 : : * Free registered control flow rules first,
1969 : : * to free the memory allocated for list entries
1970 : : */
1971 : 0 : entry = LIST_FIRST(&priv->hw_ctrl_flows);
1972 [ # # ]: 0 : while (entry != NULL) {
1973 : 0 : tmp = LIST_NEXT(entry, next);
1974 : 0 : mlx5_legacy_ctrl_flow_destroy(dev, entry);
1975 : : entry = tmp;
1976 : : }
1977 : :
1978 : 0 : mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false);
1979 : 0 : }
1980 : :
1981 : : /**
1982 : : * Disable traffic flows configured by control plane
1983 : : *
1984 : : * @param dev
1985 : : * Pointer to Ethernet device private data.
1986 : : */
1987 : : void
1988 : 0 : mlx5_traffic_disable(struct rte_eth_dev *dev)
1989 : : {
1990 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
1991 : : return;
1992 : :
1993 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1994 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1995 : :
1996 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2) {
1997 : : /* Device started flag was cleared before, this is used to derefer the Rx queues. */
1998 : 0 : priv->hws_rule_flushing = true;
1999 : 0 : mlx5_flow_hw_flush_ctrl_flows(dev);
2000 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_tables(dev);
2001 : 0 : priv->hws_rule_flushing = false;
2002 : : }
2003 : : else
2004 : : #endif
2005 : 0 : mlx5_traffic_disable_legacy(dev);
2006 : : }
2007 : :
2008 : : /**
2009 : : * Restart traffic flows configured by control plane
2010 : : *
2011 : : * @param dev
2012 : : * Pointer to Ethernet device private data.
2013 : : *
2014 : : * @return
2015 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
2016 : : */
2017 : : int
2018 : 0 : mlx5_traffic_restart(struct rte_eth_dev *dev)
2019 : : {
2020 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
2021 : : return 0;
2022 : :
2023 [ # # ]: 0 : if (dev->data->dev_started) {
2024 : 0 : mlx5_traffic_disable(dev);
2025 : : #ifdef HAVE_MLX5_HWS_SUPPORT
2026 : 0 : mlx5_flow_hw_cleanup_ctrl_rx_templates(dev);
2027 : : #endif
2028 : 0 : return mlx5_traffic_enable(dev);
2029 : : }
2030 : : return 0;
2031 : : }
2032 : :
2033 : : static bool
2034 : 0 : mac_flows_update_needed(struct rte_eth_dev *dev)
2035 : : {
2036 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2037 : :
2038 [ # # ]: 0 : if (mlx5_flow_is_steering_disabled())
2039 : : return false;
2040 [ # # ]: 0 : if (!dev->data->dev_started)
2041 : : return false;
2042 [ # # ]: 0 : if (dev->data->promiscuous)
2043 : : return false;
2044 [ # # ]: 0 : if (priv->isolated)
2045 : 0 : return false;
2046 : :
2047 : : return true;
2048 : : }
2049 : :
2050 : : static int
2051 : 0 : traffic_dmac_create(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2052 : : {
2053 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2054 : :
2055 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2056 : 0 : return mlx5_flow_hw_ctrl_flow_dmac(dev, addr);
2057 : : else
2058 : 0 : return mlx5_legacy_dmac_flow_create(dev, addr);
2059 : : }
2060 : :
2061 : : static int
2062 : 0 : traffic_dmac_destroy(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2063 : : {
2064 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2065 : :
2066 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2067 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_destroy(dev, addr);
2068 : : else
2069 : 0 : return mlx5_legacy_dmac_flow_destroy(dev, addr);
2070 : : }
2071 : :
2072 : : static int
2073 : 0 : traffic_dmac_vlan_create(struct rte_eth_dev *dev,
2074 : : const struct rte_ether_addr *addr,
2075 : : const uint16_t vid)
2076 : : {
2077 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2078 : :
2079 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2080 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_vlan(dev, addr, vid);
2081 : : else
2082 : 0 : return mlx5_legacy_dmac_vlan_flow_create(dev, addr, vid);
2083 : : }
2084 : :
2085 : : static int
2086 : 0 : traffic_dmac_vlan_destroy(struct rte_eth_dev *dev,
2087 : : const struct rte_ether_addr *addr,
2088 : : const uint16_t vid)
2089 : : {
2090 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2091 : :
2092 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
2093 : 0 : return mlx5_flow_hw_ctrl_flow_dmac_vlan_destroy(dev, addr, vid);
2094 : : else
2095 : 0 : return mlx5_legacy_dmac_vlan_flow_destroy(dev, addr, vid);
2096 : : }
2097 : :
2098 : : /**
2099 : : * Adjust Rx control flow rules to allow traffic on provided MAC address.
2100 : : */
2101 : : int
2102 : 0 : mlx5_traffic_mac_add(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2103 : : {
2104 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2105 : :
2106 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2107 : : return 0;
2108 : :
2109 [ # # ]: 0 : if (priv->vlan_filter_n > 0) {
2110 : : unsigned int i;
2111 : :
2112 [ # # ]: 0 : for (i = 0; i < priv->vlan_filter_n; ++i) {
2113 : 0 : uint16_t vlan = priv->vlan_filter[i];
2114 : : int ret;
2115 : :
2116 [ # # ]: 0 : if (mlx5_ctrl_flow_uc_dmac_vlan_exists(dev, addr, vlan))
2117 : 0 : continue;
2118 : :
2119 : 0 : ret = traffic_dmac_vlan_create(dev, addr, vlan);
2120 [ # # ]: 0 : if (ret != 0)
2121 : 0 : return ret;
2122 : : }
2123 : :
2124 : : return 0;
2125 : : }
2126 : :
2127 [ # # ]: 0 : if (mlx5_ctrl_flow_uc_dmac_exists(dev, addr))
2128 : : return 0;
2129 : :
2130 : 0 : return traffic_dmac_create(dev, addr);
2131 : : }
2132 : :
2133 : : /**
2134 : : * Adjust Rx control flow rules to disallow traffic with removed MAC address.
2135 : : */
2136 : : int
2137 : 0 : mlx5_traffic_mac_remove(struct rte_eth_dev *dev, const struct rte_ether_addr *addr)
2138 : : {
2139 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2140 : :
2141 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2142 : : return 0;
2143 : :
2144 [ # # ]: 0 : if (priv->vlan_filter_n > 0) {
2145 : : unsigned int i;
2146 : :
2147 [ # # ]: 0 : for (i = 0; i < priv->vlan_filter_n; ++i) {
2148 : 0 : uint16_t vlan = priv->vlan_filter[i];
2149 : : int ret;
2150 : :
2151 [ # # ]: 0 : if (!mlx5_ctrl_flow_uc_dmac_vlan_exists(dev, addr, vlan))
2152 : 0 : continue;
2153 : :
2154 : 0 : ret = traffic_dmac_vlan_destroy(dev, addr, vlan);
2155 [ # # ]: 0 : if (ret != 0)
2156 : 0 : return ret;
2157 : : }
2158 : :
2159 : : return 0;
2160 : : }
2161 : :
2162 [ # # ]: 0 : if (!mlx5_ctrl_flow_uc_dmac_exists(dev, addr))
2163 : : return 0;
2164 : :
2165 : 0 : return traffic_dmac_destroy(dev, addr);
2166 : : }
2167 : :
2168 : : /**
2169 : : * Adjust Rx control flow rules to allow traffic on provided VLAN.
2170 : : *
2171 : : * Assumptions:
2172 : : * - Called when VLAN is added.
2173 : : * - At least one VLAN is enabled before function call.
2174 : : *
2175 : : * This functions assumes that VLAN is new and was not included in
2176 : : * Rx control flow rules set up before calling it.
2177 : : */
2178 : : int
2179 : 0 : mlx5_traffic_vlan_add(struct rte_eth_dev *dev, const uint16_t vid)
2180 : : {
2181 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2182 : : unsigned int i;
2183 : : int ret;
2184 : :
2185 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2186 : : return 0;
2187 : :
2188 : : /* Add all unicast DMAC flow rules with new VLAN attached. */
2189 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2190 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2191 : :
2192 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2193 : 0 : continue;
2194 : :
2195 : 0 : ret = traffic_dmac_vlan_create(dev, mac, vid);
2196 [ # # ]: 0 : if (ret != 0)
2197 : 0 : return ret;
2198 : : }
2199 : :
2200 [ # # ]: 0 : if (priv->vlan_filter_n == 1) {
2201 : : /*
2202 : : * Adding first VLAN. Need to remove unicast DMAC rules before adding new rules.
2203 : : * Removing after creating VLAN rules so that traffic "gap" is not introduced.
2204 : : */
2205 : :
2206 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2207 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2208 : :
2209 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2210 : 0 : continue;
2211 : :
2212 : 0 : ret = traffic_dmac_destroy(dev, mac);
2213 [ # # ]: 0 : if (ret != 0)
2214 : 0 : return ret;
2215 : : }
2216 : : }
2217 : :
2218 : : return 0;
2219 : : }
2220 : :
2221 : : /**
2222 : : * Adjust Rx control flow rules to disallow traffic with removed VLAN.
2223 : : *
2224 : : * Assumptions:
2225 : : *
2226 : : * - VLAN was really removed.
2227 : : */
2228 : : int
2229 : 0 : mlx5_traffic_vlan_remove(struct rte_eth_dev *dev, const uint16_t vid)
2230 : : {
2231 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
2232 : : unsigned int i;
2233 : : int ret;
2234 : :
2235 [ # # ]: 0 : if (!mac_flows_update_needed(dev))
2236 : : return 0;
2237 : :
2238 [ # # ]: 0 : if (priv->vlan_filter_n == 0) {
2239 : : /*
2240 : : * If there are no VLANs as a result, unicast DMAC flow rules must be recreated.
2241 : : * Recreating first to ensure no traffic "gap".
2242 : : */
2243 : :
2244 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2245 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2246 : :
2247 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2248 : 0 : continue;
2249 : :
2250 : 0 : ret = traffic_dmac_create(dev, mac);
2251 [ # # ]: 0 : if (ret != 0)
2252 : 0 : return ret;
2253 : : }
2254 : : }
2255 : :
2256 : : /* Remove all unicast DMAC flow rules with this VLAN. */
2257 [ # # ]: 0 : for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
2258 [ # # ]: 0 : struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
2259 : :
2260 [ # # ]: 0 : if (rte_is_zero_ether_addr(mac))
2261 : 0 : continue;
2262 : :
2263 : 0 : ret = traffic_dmac_vlan_destroy(dev, mac, vid);
2264 [ # # ]: 0 : if (ret != 0)
2265 : 0 : return ret;
2266 : : }
2267 : :
2268 : : return 0;
2269 : : }
|