xref: /f-stack/dpdk/drivers/net/mlx5/mlx5_trigger.c (revision 2d9fd380)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2a9643ea8Slogwang  * Copyright 2015 6WIND S.A.
3d30ea906Sjfb8856606  * Copyright 2015 Mellanox Technologies, Ltd
4a9643ea8Slogwang  */
5d30ea906Sjfb8856606 
62bfe3f2eSlogwang #include <unistd.h>
7a9643ea8Slogwang 
8a9643ea8Slogwang #include <rte_ether.h>
9d30ea906Sjfb8856606 #include <rte_ethdev_driver.h>
10a9643ea8Slogwang #include <rte_interrupts.h>
11a9643ea8Slogwang #include <rte_alarm.h>
12a9643ea8Slogwang 
13*2d9fd380Sjfb8856606 #include <mlx5_malloc.h>
14*2d9fd380Sjfb8856606 
15a9643ea8Slogwang #include "mlx5.h"
16*2d9fd380Sjfb8856606 #include "mlx5_mr.h"
17a9643ea8Slogwang #include "mlx5_rxtx.h"
18a9643ea8Slogwang #include "mlx5_utils.h"
19*2d9fd380Sjfb8856606 #include "rte_pmd_mlx5.h"
20a9643ea8Slogwang 
21579bf1e2Sjfb8856606 /**
22579bf1e2Sjfb8856606  * Stop traffic on Tx queues.
23579bf1e2Sjfb8856606  *
24579bf1e2Sjfb8856606  * @param dev
25579bf1e2Sjfb8856606  *   Pointer to Ethernet device structure.
26579bf1e2Sjfb8856606  */
272bfe3f2eSlogwang static void
mlx5_txq_stop(struct rte_eth_dev * dev)28579bf1e2Sjfb8856606 mlx5_txq_stop(struct rte_eth_dev *dev)
292bfe3f2eSlogwang {
301646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
312bfe3f2eSlogwang 	unsigned int i;
322bfe3f2eSlogwang 
332bfe3f2eSlogwang 	for (i = 0; i != priv->txqs_n; ++i)
34579bf1e2Sjfb8856606 		mlx5_txq_release(dev, i);
352bfe3f2eSlogwang }
362bfe3f2eSlogwang 
37579bf1e2Sjfb8856606 /**
38579bf1e2Sjfb8856606  * Start traffic on Tx queues.
39579bf1e2Sjfb8856606  *
40579bf1e2Sjfb8856606  * @param dev
41579bf1e2Sjfb8856606  *   Pointer to Ethernet device structure.
42579bf1e2Sjfb8856606  *
43579bf1e2Sjfb8856606  * @return
44579bf1e2Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
45579bf1e2Sjfb8856606  */
462bfe3f2eSlogwang static int
mlx5_txq_start(struct rte_eth_dev * dev)47579bf1e2Sjfb8856606 mlx5_txq_start(struct rte_eth_dev *dev)
482bfe3f2eSlogwang {
491646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
502bfe3f2eSlogwang 	unsigned int i;
51579bf1e2Sjfb8856606 	int ret;
522bfe3f2eSlogwang 
532bfe3f2eSlogwang 	for (i = 0; i != priv->txqs_n; ++i) {
54579bf1e2Sjfb8856606 		struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
55*2d9fd380Sjfb8856606 		struct mlx5_txq_data *txq_data = &txq_ctrl->txq;
56*2d9fd380Sjfb8856606 		uint32_t flags = MLX5_MEM_RTE | MLX5_MEM_ZERO;
572bfe3f2eSlogwang 
582bfe3f2eSlogwang 		if (!txq_ctrl)
592bfe3f2eSlogwang 			continue;
60*2d9fd380Sjfb8856606 		if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD)
612bfe3f2eSlogwang 			txq_alloc_elts(txq_ctrl);
62*2d9fd380Sjfb8856606 		MLX5_ASSERT(!txq_ctrl->obj);
63*2d9fd380Sjfb8856606 		txq_ctrl->obj = mlx5_malloc(flags, sizeof(struct mlx5_txq_obj),
64*2d9fd380Sjfb8856606 					    0, txq_ctrl->socket);
654418919fSjohnjiang 		if (!txq_ctrl->obj) {
66*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Port %u Tx queue %u cannot allocate "
67*2d9fd380Sjfb8856606 				"memory resources.", dev->data->port_id,
68*2d9fd380Sjfb8856606 				txq_data->idx);
69579bf1e2Sjfb8856606 			rte_errno = ENOMEM;
702bfe3f2eSlogwang 			goto error;
712bfe3f2eSlogwang 		}
72*2d9fd380Sjfb8856606 		ret = priv->obj_ops.txq_obj_new(dev, i);
73*2d9fd380Sjfb8856606 		if (ret < 0) {
74*2d9fd380Sjfb8856606 			mlx5_free(txq_ctrl->obj);
75*2d9fd380Sjfb8856606 			txq_ctrl->obj = NULL;
76*2d9fd380Sjfb8856606 			goto error;
77*2d9fd380Sjfb8856606 		}
78*2d9fd380Sjfb8856606 		if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD) {
79*2d9fd380Sjfb8856606 			size_t size = txq_data->cqe_s * sizeof(*txq_data->fcqs);
80*2d9fd380Sjfb8856606 
81*2d9fd380Sjfb8856606 			txq_data->fcqs = mlx5_malloc(flags, size,
82*2d9fd380Sjfb8856606 						     RTE_CACHE_LINE_SIZE,
83*2d9fd380Sjfb8856606 						     txq_ctrl->socket);
84*2d9fd380Sjfb8856606 			if (!txq_data->fcqs) {
85*2d9fd380Sjfb8856606 				DRV_LOG(ERR, "Port %u Tx queue %u cannot "
86*2d9fd380Sjfb8856606 					"allocate memory (FCQ).",
87*2d9fd380Sjfb8856606 					dev->data->port_id, i);
88*2d9fd380Sjfb8856606 				rte_errno = ENOMEM;
89*2d9fd380Sjfb8856606 				goto error;
90*2d9fd380Sjfb8856606 			}
91*2d9fd380Sjfb8856606 		}
92*2d9fd380Sjfb8856606 		DRV_LOG(DEBUG, "Port %u txq %u updated with %p.",
93*2d9fd380Sjfb8856606 			dev->data->port_id, i, (void *)&txq_ctrl->obj);
94*2d9fd380Sjfb8856606 		LIST_INSERT_HEAD(&priv->txqsobj, txq_ctrl->obj, next);
952bfe3f2eSlogwang 	}
96579bf1e2Sjfb8856606 	return 0;
972bfe3f2eSlogwang error:
98579bf1e2Sjfb8856606 	ret = rte_errno; /* Save rte_errno before cleanup. */
99579bf1e2Sjfb8856606 	do {
100579bf1e2Sjfb8856606 		mlx5_txq_release(dev, i);
101579bf1e2Sjfb8856606 	} while (i-- != 0);
102579bf1e2Sjfb8856606 	rte_errno = ret; /* Restore rte_errno. */
103579bf1e2Sjfb8856606 	return -rte_errno;
1042bfe3f2eSlogwang }
1052bfe3f2eSlogwang 
106579bf1e2Sjfb8856606 /**
107579bf1e2Sjfb8856606  * Stop traffic on Rx queues.
108579bf1e2Sjfb8856606  *
109579bf1e2Sjfb8856606  * @param dev
110579bf1e2Sjfb8856606  *   Pointer to Ethernet device structure.
111579bf1e2Sjfb8856606  */
1122bfe3f2eSlogwang static void
mlx5_rxq_stop(struct rte_eth_dev * dev)113579bf1e2Sjfb8856606 mlx5_rxq_stop(struct rte_eth_dev *dev)
1142bfe3f2eSlogwang {
1151646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
1162bfe3f2eSlogwang 	unsigned int i;
1172bfe3f2eSlogwang 
1182bfe3f2eSlogwang 	for (i = 0; i != priv->rxqs_n; ++i)
119579bf1e2Sjfb8856606 		mlx5_rxq_release(dev, i);
1202bfe3f2eSlogwang }
1212bfe3f2eSlogwang 
122579bf1e2Sjfb8856606 /**
123579bf1e2Sjfb8856606  * Start traffic on Rx queues.
124579bf1e2Sjfb8856606  *
125579bf1e2Sjfb8856606  * @param dev
126579bf1e2Sjfb8856606  *   Pointer to Ethernet device structure.
127579bf1e2Sjfb8856606  *
128579bf1e2Sjfb8856606  * @return
129579bf1e2Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
130579bf1e2Sjfb8856606  */
1312bfe3f2eSlogwang static int
mlx5_rxq_start(struct rte_eth_dev * dev)132579bf1e2Sjfb8856606 mlx5_rxq_start(struct rte_eth_dev *dev)
1332bfe3f2eSlogwang {
1341646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
1352bfe3f2eSlogwang 	unsigned int i;
1362bfe3f2eSlogwang 	int ret = 0;
1372bfe3f2eSlogwang 
138d30ea906Sjfb8856606 	/* Allocate/reuse/resize mempool for Multi-Packet RQ. */
139d30ea906Sjfb8856606 	if (mlx5_mprq_alloc_mp(dev)) {
140d30ea906Sjfb8856606 		/* Should not release Rx queues but return immediately. */
141d30ea906Sjfb8856606 		return -rte_errno;
142d30ea906Sjfb8856606 	}
143*2d9fd380Sjfb8856606 	DRV_LOG(DEBUG, "Port %u device_attr.max_qp_wr is %d.",
144*2d9fd380Sjfb8856606 		dev->data->port_id, priv->sh->device_attr.max_qp_wr);
145*2d9fd380Sjfb8856606 	DRV_LOG(DEBUG, "Port %u device_attr.max_sge is %d.",
146*2d9fd380Sjfb8856606 		dev->data->port_id, priv->sh->device_attr.max_sge);
1472bfe3f2eSlogwang 	for (i = 0; i != priv->rxqs_n; ++i) {
148579bf1e2Sjfb8856606 		struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_get(dev, i);
1492bfe3f2eSlogwang 
1502bfe3f2eSlogwang 		if (!rxq_ctrl)
1512bfe3f2eSlogwang 			continue;
152*2d9fd380Sjfb8856606 		if (rxq_ctrl->type == MLX5_RXQ_TYPE_STANDARD) {
153*2d9fd380Sjfb8856606 			/* Pre-register Rx mempools. */
154*2d9fd380Sjfb8856606 			if (mlx5_rxq_mprq_enabled(&rxq_ctrl->rxq)) {
155*2d9fd380Sjfb8856606 				mlx5_mr_update_mp(dev, &rxq_ctrl->rxq.mr_ctrl,
156*2d9fd380Sjfb8856606 						  rxq_ctrl->rxq.mprq_mp);
157*2d9fd380Sjfb8856606 			} else {
158*2d9fd380Sjfb8856606 				uint32_t s;
159*2d9fd380Sjfb8856606 
160*2d9fd380Sjfb8856606 				for (s = 0; s < rxq_ctrl->rxq.rxseg_n; s++)
161*2d9fd380Sjfb8856606 					mlx5_mr_update_mp
162*2d9fd380Sjfb8856606 						(dev, &rxq_ctrl->rxq.mr_ctrl,
163*2d9fd380Sjfb8856606 						rxq_ctrl->rxq.rxseg[s].mp);
1644418919fSjohnjiang 			}
1652bfe3f2eSlogwang 			ret = rxq_alloc_elts(rxq_ctrl);
1662bfe3f2eSlogwang 			if (ret)
1672bfe3f2eSlogwang 				goto error;
168*2d9fd380Sjfb8856606 		}
169*2d9fd380Sjfb8856606 		MLX5_ASSERT(!rxq_ctrl->obj);
170*2d9fd380Sjfb8856606 		rxq_ctrl->obj = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
171*2d9fd380Sjfb8856606 					    sizeof(*rxq_ctrl->obj), 0,
172*2d9fd380Sjfb8856606 					    rxq_ctrl->socket);
173*2d9fd380Sjfb8856606 		if (!rxq_ctrl->obj) {
174*2d9fd380Sjfb8856606 			DRV_LOG(ERR,
175*2d9fd380Sjfb8856606 				"Port %u Rx queue %u can't allocate resources.",
176*2d9fd380Sjfb8856606 				dev->data->port_id, (*priv->rxqs)[i]->idx);
177*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
1782bfe3f2eSlogwang 			goto error;
179*2d9fd380Sjfb8856606 		}
180*2d9fd380Sjfb8856606 		ret = priv->obj_ops.rxq_obj_new(dev, i);
181*2d9fd380Sjfb8856606 		if (ret) {
182*2d9fd380Sjfb8856606 			mlx5_free(rxq_ctrl->obj);
183*2d9fd380Sjfb8856606 			goto error;
184*2d9fd380Sjfb8856606 		}
185*2d9fd380Sjfb8856606 		DRV_LOG(DEBUG, "Port %u rxq %u updated with %p.",
186*2d9fd380Sjfb8856606 			dev->data->port_id, i, (void *)&rxq_ctrl->obj);
187*2d9fd380Sjfb8856606 		LIST_INSERT_HEAD(&priv->rxqsobj, rxq_ctrl->obj, next);
1882bfe3f2eSlogwang 	}
189579bf1e2Sjfb8856606 	return 0;
1902bfe3f2eSlogwang error:
191579bf1e2Sjfb8856606 	ret = rte_errno; /* Save rte_errno before cleanup. */
192579bf1e2Sjfb8856606 	do {
193579bf1e2Sjfb8856606 		mlx5_rxq_release(dev, i);
194579bf1e2Sjfb8856606 	} while (i-- != 0);
195579bf1e2Sjfb8856606 	rte_errno = ret; /* Restore rte_errno. */
196579bf1e2Sjfb8856606 	return -rte_errno;
1972bfe3f2eSlogwang }
1982bfe3f2eSlogwang 
199a9643ea8Slogwang /**
2004418919fSjohnjiang  * Binds Tx queues to Rx queues for hairpin.
2014418919fSjohnjiang  *
2024418919fSjohnjiang  * Binds Tx queues to the target Rx queues.
2034418919fSjohnjiang  *
2044418919fSjohnjiang  * @param dev
2054418919fSjohnjiang  *   Pointer to Ethernet device structure.
2064418919fSjohnjiang  *
2074418919fSjohnjiang  * @return
2084418919fSjohnjiang  *   0 on success, a negative errno value otherwise and rte_errno is set.
2094418919fSjohnjiang  */
2104418919fSjohnjiang static int
mlx5_hairpin_auto_bind(struct rte_eth_dev * dev)211*2d9fd380Sjfb8856606 mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
2124418919fSjohnjiang {
2134418919fSjohnjiang 	struct mlx5_priv *priv = dev->data->dev_private;
2144418919fSjohnjiang 	struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
2154418919fSjohnjiang 	struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
2164418919fSjohnjiang 	struct mlx5_txq_ctrl *txq_ctrl;
2174418919fSjohnjiang 	struct mlx5_rxq_ctrl *rxq_ctrl;
2184418919fSjohnjiang 	struct mlx5_devx_obj *sq;
2194418919fSjohnjiang 	struct mlx5_devx_obj *rq;
2204418919fSjohnjiang 	unsigned int i;
2214418919fSjohnjiang 	int ret = 0;
222*2d9fd380Sjfb8856606 	bool need_auto = false;
223*2d9fd380Sjfb8856606 	uint16_t self_port = dev->data->port_id;
2244418919fSjohnjiang 
2254418919fSjohnjiang 	for (i = 0; i != priv->txqs_n; ++i) {
2264418919fSjohnjiang 		txq_ctrl = mlx5_txq_get(dev, i);
2274418919fSjohnjiang 		if (!txq_ctrl)
2284418919fSjohnjiang 			continue;
2294418919fSjohnjiang 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
2304418919fSjohnjiang 			mlx5_txq_release(dev, i);
2314418919fSjohnjiang 			continue;
2324418919fSjohnjiang 		}
233*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.peers[0].port != self_port)
234*2d9fd380Sjfb8856606 			continue;
235*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.manual_bind) {
236*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
237*2d9fd380Sjfb8856606 			return 0;
238*2d9fd380Sjfb8856606 		}
239*2d9fd380Sjfb8856606 		need_auto = true;
240*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, i);
241*2d9fd380Sjfb8856606 	}
242*2d9fd380Sjfb8856606 	if (!need_auto)
243*2d9fd380Sjfb8856606 		return 0;
244*2d9fd380Sjfb8856606 	for (i = 0; i != priv->txqs_n; ++i) {
245*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, i);
246*2d9fd380Sjfb8856606 		if (!txq_ctrl)
247*2d9fd380Sjfb8856606 			continue;
248*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
249*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
250*2d9fd380Sjfb8856606 			continue;
251*2d9fd380Sjfb8856606 		}
252*2d9fd380Sjfb8856606 		/* Skip hairpin queues with other peer ports. */
253*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.peers[0].port != self_port)
254*2d9fd380Sjfb8856606 			continue;
2554418919fSjohnjiang 		if (!txq_ctrl->obj) {
2564418919fSjohnjiang 			rte_errno = ENOMEM;
2574418919fSjohnjiang 			DRV_LOG(ERR, "port %u no txq object found: %d",
2584418919fSjohnjiang 				dev->data->port_id, i);
2594418919fSjohnjiang 			mlx5_txq_release(dev, i);
2604418919fSjohnjiang 			return -rte_errno;
2614418919fSjohnjiang 		}
2624418919fSjohnjiang 		sq = txq_ctrl->obj->sq;
2634418919fSjohnjiang 		rxq_ctrl = mlx5_rxq_get(dev,
2644418919fSjohnjiang 					txq_ctrl->hairpin_conf.peers[0].queue);
2654418919fSjohnjiang 		if (!rxq_ctrl) {
2664418919fSjohnjiang 			mlx5_txq_release(dev, i);
2674418919fSjohnjiang 			rte_errno = EINVAL;
2684418919fSjohnjiang 			DRV_LOG(ERR, "port %u no rxq object found: %d",
2694418919fSjohnjiang 				dev->data->port_id,
2704418919fSjohnjiang 				txq_ctrl->hairpin_conf.peers[0].queue);
2714418919fSjohnjiang 			return -rte_errno;
2724418919fSjohnjiang 		}
2734418919fSjohnjiang 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN ||
2744418919fSjohnjiang 		    rxq_ctrl->hairpin_conf.peers[0].queue != i) {
2754418919fSjohnjiang 			rte_errno = ENOMEM;
2764418919fSjohnjiang 			DRV_LOG(ERR, "port %u Tx queue %d can't be binded to "
2774418919fSjohnjiang 				"Rx queue %d", dev->data->port_id,
2784418919fSjohnjiang 				i, txq_ctrl->hairpin_conf.peers[0].queue);
2794418919fSjohnjiang 			goto error;
2804418919fSjohnjiang 		}
2814418919fSjohnjiang 		rq = rxq_ctrl->obj->rq;
2824418919fSjohnjiang 		if (!rq) {
2834418919fSjohnjiang 			rte_errno = ENOMEM;
2844418919fSjohnjiang 			DRV_LOG(ERR, "port %u hairpin no matching rxq: %d",
2854418919fSjohnjiang 				dev->data->port_id,
2864418919fSjohnjiang 				txq_ctrl->hairpin_conf.peers[0].queue);
2874418919fSjohnjiang 			goto error;
2884418919fSjohnjiang 		}
2894418919fSjohnjiang 		sq_attr.state = MLX5_SQC_STATE_RDY;
2904418919fSjohnjiang 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
2914418919fSjohnjiang 		sq_attr.hairpin_peer_rq = rq->id;
2924418919fSjohnjiang 		sq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
2934418919fSjohnjiang 		ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr);
2944418919fSjohnjiang 		if (ret)
2954418919fSjohnjiang 			goto error;
2964418919fSjohnjiang 		rq_attr.state = MLX5_SQC_STATE_RDY;
2974418919fSjohnjiang 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
2984418919fSjohnjiang 		rq_attr.hairpin_peer_sq = sq->id;
2994418919fSjohnjiang 		rq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
3004418919fSjohnjiang 		ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
3014418919fSjohnjiang 		if (ret)
3024418919fSjohnjiang 			goto error;
303*2d9fd380Sjfb8856606 		/* Qs with auto-bind will be destroyed directly. */
304*2d9fd380Sjfb8856606 		rxq_ctrl->hairpin_status = 1;
305*2d9fd380Sjfb8856606 		txq_ctrl->hairpin_status = 1;
3064418919fSjohnjiang 		mlx5_txq_release(dev, i);
3074418919fSjohnjiang 		mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
3084418919fSjohnjiang 	}
3094418919fSjohnjiang 	return 0;
3104418919fSjohnjiang error:
3114418919fSjohnjiang 	mlx5_txq_release(dev, i);
3124418919fSjohnjiang 	mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
3134418919fSjohnjiang 	return -rte_errno;
3144418919fSjohnjiang }
3154418919fSjohnjiang 
316*2d9fd380Sjfb8856606 /*
317*2d9fd380Sjfb8856606  * Fetch the peer queue's SW & HW information.
318*2d9fd380Sjfb8856606  *
319*2d9fd380Sjfb8856606  * @param dev
320*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
321*2d9fd380Sjfb8856606  * @param peer_queue
322*2d9fd380Sjfb8856606  *   Index of the queue to fetch the information.
323*2d9fd380Sjfb8856606  * @param current_info
324*2d9fd380Sjfb8856606  *   Pointer to the input peer information, not used currently.
325*2d9fd380Sjfb8856606  * @param peer_info
326*2d9fd380Sjfb8856606  *   Pointer to the structure to store the information, output.
327*2d9fd380Sjfb8856606  * @param direction
328*2d9fd380Sjfb8856606  *   Positive to get the RxQ information, zero to get the TxQ information.
329*2d9fd380Sjfb8856606  *
330*2d9fd380Sjfb8856606  * @return
331*2d9fd380Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
332*2d9fd380Sjfb8856606  */
333*2d9fd380Sjfb8856606 int
mlx5_hairpin_queue_peer_update(struct rte_eth_dev * dev,uint16_t peer_queue,struct rte_hairpin_peer_info * current_info,struct rte_hairpin_peer_info * peer_info,uint32_t direction)334*2d9fd380Sjfb8856606 mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue,
335*2d9fd380Sjfb8856606 			       struct rte_hairpin_peer_info *current_info,
336*2d9fd380Sjfb8856606 			       struct rte_hairpin_peer_info *peer_info,
337*2d9fd380Sjfb8856606 			       uint32_t direction)
338*2d9fd380Sjfb8856606 {
339*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
340*2d9fd380Sjfb8856606 	RTE_SET_USED(current_info);
341*2d9fd380Sjfb8856606 
342*2d9fd380Sjfb8856606 	if (dev->data->dev_started == 0) {
343*2d9fd380Sjfb8856606 		rte_errno = EBUSY;
344*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "peer port %u is not started",
345*2d9fd380Sjfb8856606 			dev->data->port_id);
346*2d9fd380Sjfb8856606 		return -rte_errno;
347*2d9fd380Sjfb8856606 	}
348*2d9fd380Sjfb8856606 	/*
349*2d9fd380Sjfb8856606 	 * Peer port used as egress. In the current design, hairpin Tx queue
350*2d9fd380Sjfb8856606 	 * will be bound to the peer Rx queue. Indeed, only the information of
351*2d9fd380Sjfb8856606 	 * peer Rx queue needs to be fetched.
352*2d9fd380Sjfb8856606 	 */
353*2d9fd380Sjfb8856606 	if (direction == 0) {
354*2d9fd380Sjfb8856606 		struct mlx5_txq_ctrl *txq_ctrl;
355*2d9fd380Sjfb8856606 
356*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, peer_queue);
357*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL) {
358*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
359*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
360*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
361*2d9fd380Sjfb8856606 			return -rte_errno;
362*2d9fd380Sjfb8856606 		}
363*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
364*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
365*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d is not a hairpin Txq",
366*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
367*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, peer_queue);
368*2d9fd380Sjfb8856606 			return -rte_errno;
369*2d9fd380Sjfb8856606 		}
370*2d9fd380Sjfb8856606 		if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
371*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
372*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Txq object found: %d",
373*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
374*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, peer_queue);
375*2d9fd380Sjfb8856606 			return -rte_errno;
376*2d9fd380Sjfb8856606 		}
377*2d9fd380Sjfb8856606 		peer_info->qp_id = txq_ctrl->obj->sq->id;
378*2d9fd380Sjfb8856606 		peer_info->vhca_id = priv->config.hca_attr.vhca_id;
379*2d9fd380Sjfb8856606 		/* 1-to-1 mapping, only the first one is used. */
380*2d9fd380Sjfb8856606 		peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue;
381*2d9fd380Sjfb8856606 		peer_info->tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
382*2d9fd380Sjfb8856606 		peer_info->manual_bind = txq_ctrl->hairpin_conf.manual_bind;
383*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, peer_queue);
384*2d9fd380Sjfb8856606 	} else { /* Peer port used as ingress. */
385*2d9fd380Sjfb8856606 		struct mlx5_rxq_ctrl *rxq_ctrl;
386*2d9fd380Sjfb8856606 
387*2d9fd380Sjfb8856606 		rxq_ctrl = mlx5_rxq_get(dev, peer_queue);
388*2d9fd380Sjfb8856606 		if (rxq_ctrl == NULL) {
389*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
390*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
391*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
392*2d9fd380Sjfb8856606 			return -rte_errno;
393*2d9fd380Sjfb8856606 		}
394*2d9fd380Sjfb8856606 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
395*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
396*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d is not a hairpin Rxq",
397*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
398*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, peer_queue);
399*2d9fd380Sjfb8856606 			return -rte_errno;
400*2d9fd380Sjfb8856606 		}
401*2d9fd380Sjfb8856606 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
402*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
403*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
404*2d9fd380Sjfb8856606 				dev->data->port_id, peer_queue);
405*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, peer_queue);
406*2d9fd380Sjfb8856606 			return -rte_errno;
407*2d9fd380Sjfb8856606 		}
408*2d9fd380Sjfb8856606 		peer_info->qp_id = rxq_ctrl->obj->rq->id;
409*2d9fd380Sjfb8856606 		peer_info->vhca_id = priv->config.hca_attr.vhca_id;
410*2d9fd380Sjfb8856606 		peer_info->peer_q = rxq_ctrl->hairpin_conf.peers[0].queue;
411*2d9fd380Sjfb8856606 		peer_info->tx_explicit = rxq_ctrl->hairpin_conf.tx_explicit;
412*2d9fd380Sjfb8856606 		peer_info->manual_bind = rxq_ctrl->hairpin_conf.manual_bind;
413*2d9fd380Sjfb8856606 		mlx5_rxq_release(dev, peer_queue);
414*2d9fd380Sjfb8856606 	}
415*2d9fd380Sjfb8856606 	return 0;
416*2d9fd380Sjfb8856606 }
417*2d9fd380Sjfb8856606 
418*2d9fd380Sjfb8856606 /*
419*2d9fd380Sjfb8856606  * Bind the hairpin queue with the peer HW information.
420*2d9fd380Sjfb8856606  * This needs to be called twice both for Tx and Rx queues of a pair.
421*2d9fd380Sjfb8856606  * If the queue is already bound, it is considered successful.
422*2d9fd380Sjfb8856606  *
423*2d9fd380Sjfb8856606  * @param dev
424*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
425*2d9fd380Sjfb8856606  * @param cur_queue
426*2d9fd380Sjfb8856606  *   Index of the queue to change the HW configuration to bind.
427*2d9fd380Sjfb8856606  * @param peer_info
428*2d9fd380Sjfb8856606  *   Pointer to information of the peer queue.
429*2d9fd380Sjfb8856606  * @param direction
430*2d9fd380Sjfb8856606  *   Positive to configure the TxQ, zero to configure the RxQ.
431*2d9fd380Sjfb8856606  *
432*2d9fd380Sjfb8856606  * @return
433*2d9fd380Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
434*2d9fd380Sjfb8856606  */
435*2d9fd380Sjfb8856606 int
mlx5_hairpin_queue_peer_bind(struct rte_eth_dev * dev,uint16_t cur_queue,struct rte_hairpin_peer_info * peer_info,uint32_t direction)436*2d9fd380Sjfb8856606 mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue,
437*2d9fd380Sjfb8856606 			     struct rte_hairpin_peer_info *peer_info,
438*2d9fd380Sjfb8856606 			     uint32_t direction)
439*2d9fd380Sjfb8856606 {
440*2d9fd380Sjfb8856606 	int ret = 0;
441*2d9fd380Sjfb8856606 
442*2d9fd380Sjfb8856606 	/*
443*2d9fd380Sjfb8856606 	 * Consistency checking of the peer queue: opposite direction is used
444*2d9fd380Sjfb8856606 	 * to get the peer queue info with ethdev port ID, no need to check.
445*2d9fd380Sjfb8856606 	 */
446*2d9fd380Sjfb8856606 	if (peer_info->peer_q != cur_queue) {
447*2d9fd380Sjfb8856606 		rte_errno = EINVAL;
448*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "port %u queue %d and peer queue %d mismatch",
449*2d9fd380Sjfb8856606 			dev->data->port_id, cur_queue, peer_info->peer_q);
450*2d9fd380Sjfb8856606 		return -rte_errno;
451*2d9fd380Sjfb8856606 	}
452*2d9fd380Sjfb8856606 	if (direction != 0) {
453*2d9fd380Sjfb8856606 		struct mlx5_txq_ctrl *txq_ctrl;
454*2d9fd380Sjfb8856606 		struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
455*2d9fd380Sjfb8856606 
456*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, cur_queue);
457*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL) {
458*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
459*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
460*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
461*2d9fd380Sjfb8856606 			return -rte_errno;
462*2d9fd380Sjfb8856606 		}
463*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
464*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
465*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
466*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
467*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
468*2d9fd380Sjfb8856606 			return -rte_errno;
469*2d9fd380Sjfb8856606 		}
470*2d9fd380Sjfb8856606 		if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
471*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
472*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Txq object found: %d",
473*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
474*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
475*2d9fd380Sjfb8856606 			return -rte_errno;
476*2d9fd380Sjfb8856606 		}
477*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_status != 0) {
478*2d9fd380Sjfb8856606 			DRV_LOG(DEBUG, "port %u Tx queue %d is already bound",
479*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
480*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
481*2d9fd380Sjfb8856606 			return 0;
482*2d9fd380Sjfb8856606 		}
483*2d9fd380Sjfb8856606 		/*
484*2d9fd380Sjfb8856606 		 * All queues' of one port consistency checking is done in the
485*2d9fd380Sjfb8856606 		 * bind() function, and that is optional.
486*2d9fd380Sjfb8856606 		 */
487*2d9fd380Sjfb8856606 		if (peer_info->tx_explicit !=
488*2d9fd380Sjfb8856606 		    txq_ctrl->hairpin_conf.tx_explicit) {
489*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
490*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Tx queue %d and peer Tx rule mode"
491*2d9fd380Sjfb8856606 				" mismatch", dev->data->port_id, cur_queue);
492*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
493*2d9fd380Sjfb8856606 			return -rte_errno;
494*2d9fd380Sjfb8856606 		}
495*2d9fd380Sjfb8856606 		if (peer_info->manual_bind !=
496*2d9fd380Sjfb8856606 		    txq_ctrl->hairpin_conf.manual_bind) {
497*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
498*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Tx queue %d and peer binding mode"
499*2d9fd380Sjfb8856606 				" mismatch", dev->data->port_id, cur_queue);
500*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
501*2d9fd380Sjfb8856606 			return -rte_errno;
502*2d9fd380Sjfb8856606 		}
503*2d9fd380Sjfb8856606 		sq_attr.state = MLX5_SQC_STATE_RDY;
504*2d9fd380Sjfb8856606 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
505*2d9fd380Sjfb8856606 		sq_attr.hairpin_peer_rq = peer_info->qp_id;
506*2d9fd380Sjfb8856606 		sq_attr.hairpin_peer_vhca = peer_info->vhca_id;
507*2d9fd380Sjfb8856606 		ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
508*2d9fd380Sjfb8856606 		if (ret == 0)
509*2d9fd380Sjfb8856606 			txq_ctrl->hairpin_status = 1;
510*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, cur_queue);
511*2d9fd380Sjfb8856606 	} else {
512*2d9fd380Sjfb8856606 		struct mlx5_rxq_ctrl *rxq_ctrl;
513*2d9fd380Sjfb8856606 		struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
514*2d9fd380Sjfb8856606 
515*2d9fd380Sjfb8856606 		rxq_ctrl = mlx5_rxq_get(dev, cur_queue);
516*2d9fd380Sjfb8856606 		if (rxq_ctrl == NULL) {
517*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
518*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
519*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
520*2d9fd380Sjfb8856606 			return -rte_errno;
521*2d9fd380Sjfb8856606 		}
522*2d9fd380Sjfb8856606 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
523*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
524*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
525*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
526*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
527*2d9fd380Sjfb8856606 			return -rte_errno;
528*2d9fd380Sjfb8856606 		}
529*2d9fd380Sjfb8856606 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
530*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
531*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
532*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
533*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
534*2d9fd380Sjfb8856606 			return -rte_errno;
535*2d9fd380Sjfb8856606 		}
536*2d9fd380Sjfb8856606 		if (rxq_ctrl->hairpin_status != 0) {
537*2d9fd380Sjfb8856606 			DRV_LOG(DEBUG, "port %u Rx queue %d is already bound",
538*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
539*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
540*2d9fd380Sjfb8856606 			return 0;
541*2d9fd380Sjfb8856606 		}
542*2d9fd380Sjfb8856606 		if (peer_info->tx_explicit !=
543*2d9fd380Sjfb8856606 		    rxq_ctrl->hairpin_conf.tx_explicit) {
544*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
545*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Rx queue %d and peer Tx rule mode"
546*2d9fd380Sjfb8856606 				" mismatch", dev->data->port_id, cur_queue);
547*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
548*2d9fd380Sjfb8856606 			return -rte_errno;
549*2d9fd380Sjfb8856606 		}
550*2d9fd380Sjfb8856606 		if (peer_info->manual_bind !=
551*2d9fd380Sjfb8856606 		    rxq_ctrl->hairpin_conf.manual_bind) {
552*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
553*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Rx queue %d and peer binding mode"
554*2d9fd380Sjfb8856606 				" mismatch", dev->data->port_id, cur_queue);
555*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
556*2d9fd380Sjfb8856606 			return -rte_errno;
557*2d9fd380Sjfb8856606 		}
558*2d9fd380Sjfb8856606 		rq_attr.state = MLX5_SQC_STATE_RDY;
559*2d9fd380Sjfb8856606 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
560*2d9fd380Sjfb8856606 		rq_attr.hairpin_peer_sq = peer_info->qp_id;
561*2d9fd380Sjfb8856606 		rq_attr.hairpin_peer_vhca = peer_info->vhca_id;
562*2d9fd380Sjfb8856606 		ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
563*2d9fd380Sjfb8856606 		if (ret == 0)
564*2d9fd380Sjfb8856606 			rxq_ctrl->hairpin_status = 1;
565*2d9fd380Sjfb8856606 		mlx5_rxq_release(dev, cur_queue);
566*2d9fd380Sjfb8856606 	}
567*2d9fd380Sjfb8856606 	return ret;
568*2d9fd380Sjfb8856606 }
569*2d9fd380Sjfb8856606 
570*2d9fd380Sjfb8856606 /*
571*2d9fd380Sjfb8856606  * Unbind the hairpin queue and reset its HW configuration.
572*2d9fd380Sjfb8856606  * This needs to be called twice both for Tx and Rx queues of a pair.
573*2d9fd380Sjfb8856606  * If the queue is already unbound, it is considered successful.
574*2d9fd380Sjfb8856606  *
575*2d9fd380Sjfb8856606  * @param dev
576*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
577*2d9fd380Sjfb8856606  * @param cur_queue
578*2d9fd380Sjfb8856606  *   Index of the queue to change the HW configuration to unbind.
579*2d9fd380Sjfb8856606  * @param direction
580*2d9fd380Sjfb8856606  *   Positive to reset the TxQ, zero to reset the RxQ.
581*2d9fd380Sjfb8856606  *
582*2d9fd380Sjfb8856606  * @return
583*2d9fd380Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
584*2d9fd380Sjfb8856606  */
585*2d9fd380Sjfb8856606 int
mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev * dev,uint16_t cur_queue,uint32_t direction)586*2d9fd380Sjfb8856606 mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue,
587*2d9fd380Sjfb8856606 			       uint32_t direction)
588*2d9fd380Sjfb8856606 {
589*2d9fd380Sjfb8856606 	int ret = 0;
590*2d9fd380Sjfb8856606 
591*2d9fd380Sjfb8856606 	if (direction != 0) {
592*2d9fd380Sjfb8856606 		struct mlx5_txq_ctrl *txq_ctrl;
593*2d9fd380Sjfb8856606 		struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
594*2d9fd380Sjfb8856606 
595*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, cur_queue);
596*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL) {
597*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
598*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
599*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
600*2d9fd380Sjfb8856606 			return -rte_errno;
601*2d9fd380Sjfb8856606 		}
602*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
603*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
604*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
605*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
606*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
607*2d9fd380Sjfb8856606 			return -rte_errno;
608*2d9fd380Sjfb8856606 		}
609*2d9fd380Sjfb8856606 		/* Already unbound, return success before obj checking. */
610*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_status == 0) {
611*2d9fd380Sjfb8856606 			DRV_LOG(DEBUG, "port %u Tx queue %d is already unbound",
612*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
613*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
614*2d9fd380Sjfb8856606 			return 0;
615*2d9fd380Sjfb8856606 		}
616*2d9fd380Sjfb8856606 		if (!txq_ctrl->obj || !txq_ctrl->obj->sq) {
617*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
618*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Txq object found: %d",
619*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
620*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, cur_queue);
621*2d9fd380Sjfb8856606 			return -rte_errno;
622*2d9fd380Sjfb8856606 		}
623*2d9fd380Sjfb8856606 		sq_attr.state = MLX5_SQC_STATE_RST;
624*2d9fd380Sjfb8856606 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
625*2d9fd380Sjfb8856606 		ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
626*2d9fd380Sjfb8856606 		if (ret == 0)
627*2d9fd380Sjfb8856606 			txq_ctrl->hairpin_status = 0;
628*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, cur_queue);
629*2d9fd380Sjfb8856606 	} else {
630*2d9fd380Sjfb8856606 		struct mlx5_rxq_ctrl *rxq_ctrl;
631*2d9fd380Sjfb8856606 		struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
632*2d9fd380Sjfb8856606 
633*2d9fd380Sjfb8856606 		rxq_ctrl = mlx5_rxq_get(dev, cur_queue);
634*2d9fd380Sjfb8856606 		if (rxq_ctrl == NULL) {
635*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
636*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
637*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
638*2d9fd380Sjfb8856606 			return -rte_errno;
639*2d9fd380Sjfb8856606 		}
640*2d9fd380Sjfb8856606 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
641*2d9fd380Sjfb8856606 			rte_errno = EINVAL;
642*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
643*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
644*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
645*2d9fd380Sjfb8856606 			return -rte_errno;
646*2d9fd380Sjfb8856606 		}
647*2d9fd380Sjfb8856606 		if (rxq_ctrl->hairpin_status == 0) {
648*2d9fd380Sjfb8856606 			DRV_LOG(DEBUG, "port %u Rx queue %d is already unbound",
649*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
650*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
651*2d9fd380Sjfb8856606 			return 0;
652*2d9fd380Sjfb8856606 		}
653*2d9fd380Sjfb8856606 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
654*2d9fd380Sjfb8856606 			rte_errno = ENOMEM;
655*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
656*2d9fd380Sjfb8856606 				dev->data->port_id, cur_queue);
657*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, cur_queue);
658*2d9fd380Sjfb8856606 			return -rte_errno;
659*2d9fd380Sjfb8856606 		}
660*2d9fd380Sjfb8856606 		rq_attr.state = MLX5_SQC_STATE_RST;
661*2d9fd380Sjfb8856606 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
662*2d9fd380Sjfb8856606 		ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
663*2d9fd380Sjfb8856606 		if (ret == 0)
664*2d9fd380Sjfb8856606 			rxq_ctrl->hairpin_status = 0;
665*2d9fd380Sjfb8856606 		mlx5_rxq_release(dev, cur_queue);
666*2d9fd380Sjfb8856606 	}
667*2d9fd380Sjfb8856606 	return ret;
668*2d9fd380Sjfb8856606 }
669*2d9fd380Sjfb8856606 
670*2d9fd380Sjfb8856606 /*
671*2d9fd380Sjfb8856606  * Bind the hairpin port pairs, from the Tx to the peer Rx.
672*2d9fd380Sjfb8856606  * This function only supports to bind the Tx to one Rx.
673*2d9fd380Sjfb8856606  *
674*2d9fd380Sjfb8856606  * @param dev
675*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
676*2d9fd380Sjfb8856606  * @param rx_port
677*2d9fd380Sjfb8856606  *   Port identifier of the Rx port.
678*2d9fd380Sjfb8856606  *
679*2d9fd380Sjfb8856606  * @return
680*2d9fd380Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
681*2d9fd380Sjfb8856606  */
682*2d9fd380Sjfb8856606 static int
mlx5_hairpin_bind_single_port(struct rte_eth_dev * dev,uint16_t rx_port)683*2d9fd380Sjfb8856606 mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
684*2d9fd380Sjfb8856606 {
685*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
686*2d9fd380Sjfb8856606 	int ret = 0;
687*2d9fd380Sjfb8856606 	struct mlx5_txq_ctrl *txq_ctrl;
688*2d9fd380Sjfb8856606 	uint32_t i;
689*2d9fd380Sjfb8856606 	struct rte_hairpin_peer_info peer = {0xffffff};
690*2d9fd380Sjfb8856606 	struct rte_hairpin_peer_info cur;
691*2d9fd380Sjfb8856606 	const struct rte_eth_hairpin_conf *conf;
692*2d9fd380Sjfb8856606 	uint16_t num_q = 0;
693*2d9fd380Sjfb8856606 	uint16_t local_port = priv->dev_data->port_id;
694*2d9fd380Sjfb8856606 	uint32_t manual;
695*2d9fd380Sjfb8856606 	uint32_t explicit;
696*2d9fd380Sjfb8856606 	uint16_t rx_queue;
697*2d9fd380Sjfb8856606 
698*2d9fd380Sjfb8856606 	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
699*2d9fd380Sjfb8856606 		rte_errno = ENODEV;
700*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
701*2d9fd380Sjfb8856606 		return -rte_errno;
702*2d9fd380Sjfb8856606 	}
703*2d9fd380Sjfb8856606 	/*
704*2d9fd380Sjfb8856606 	 * Before binding TxQ to peer RxQ, first round loop will be used for
705*2d9fd380Sjfb8856606 	 * checking the queues' configuration consistency. This would be a
706*2d9fd380Sjfb8856606 	 * little time consuming but better than doing the rollback.
707*2d9fd380Sjfb8856606 	 */
708*2d9fd380Sjfb8856606 	for (i = 0; i != priv->txqs_n; i++) {
709*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, i);
710*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL)
711*2d9fd380Sjfb8856606 			continue;
712*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
713*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
714*2d9fd380Sjfb8856606 			continue;
715*2d9fd380Sjfb8856606 		}
716*2d9fd380Sjfb8856606 		/*
717*2d9fd380Sjfb8856606 		 * All hairpin Tx queues of a single port that connected to the
718*2d9fd380Sjfb8856606 		 * same peer Rx port should have the same "auto binding" and
719*2d9fd380Sjfb8856606 		 * "implicit Tx flow" modes.
720*2d9fd380Sjfb8856606 		 * Peer consistency checking will be done in per queue binding.
721*2d9fd380Sjfb8856606 		 */
722*2d9fd380Sjfb8856606 		conf = &txq_ctrl->hairpin_conf;
723*2d9fd380Sjfb8856606 		if (conf->peers[0].port == rx_port) {
724*2d9fd380Sjfb8856606 			if (num_q == 0) {
725*2d9fd380Sjfb8856606 				manual = conf->manual_bind;
726*2d9fd380Sjfb8856606 				explicit = conf->tx_explicit;
727*2d9fd380Sjfb8856606 			} else {
728*2d9fd380Sjfb8856606 				if (manual != conf->manual_bind ||
729*2d9fd380Sjfb8856606 				    explicit != conf->tx_explicit) {
730*2d9fd380Sjfb8856606 					rte_errno = EINVAL;
731*2d9fd380Sjfb8856606 					DRV_LOG(ERR, "port %u queue %d mode"
732*2d9fd380Sjfb8856606 						" mismatch: %u %u, %u %u",
733*2d9fd380Sjfb8856606 						local_port, i, manual,
734*2d9fd380Sjfb8856606 						conf->manual_bind, explicit,
735*2d9fd380Sjfb8856606 						conf->tx_explicit);
736*2d9fd380Sjfb8856606 					mlx5_txq_release(dev, i);
737*2d9fd380Sjfb8856606 					return -rte_errno;
738*2d9fd380Sjfb8856606 				}
739*2d9fd380Sjfb8856606 			}
740*2d9fd380Sjfb8856606 			num_q++;
741*2d9fd380Sjfb8856606 		}
742*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, i);
743*2d9fd380Sjfb8856606 	}
744*2d9fd380Sjfb8856606 	/* Once no queue is configured, success is returned directly. */
745*2d9fd380Sjfb8856606 	if (num_q == 0)
746*2d9fd380Sjfb8856606 		return ret;
747*2d9fd380Sjfb8856606 	/* All the hairpin TX queues need to be traversed again. */
748*2d9fd380Sjfb8856606 	for (i = 0; i != priv->txqs_n; i++) {
749*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, i);
750*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL)
751*2d9fd380Sjfb8856606 			continue;
752*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
753*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
754*2d9fd380Sjfb8856606 			continue;
755*2d9fd380Sjfb8856606 		}
756*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
757*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
758*2d9fd380Sjfb8856606 			continue;
759*2d9fd380Sjfb8856606 		}
760*2d9fd380Sjfb8856606 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
761*2d9fd380Sjfb8856606 		/*
762*2d9fd380Sjfb8856606 		 * Fetch peer RxQ's information.
763*2d9fd380Sjfb8856606 		 * No need to pass the information of the current queue.
764*2d9fd380Sjfb8856606 		 */
765*2d9fd380Sjfb8856606 		ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue,
766*2d9fd380Sjfb8856606 							NULL, &peer, 1);
767*2d9fd380Sjfb8856606 		if (ret != 0) {
768*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
769*2d9fd380Sjfb8856606 			goto error;
770*2d9fd380Sjfb8856606 		}
771*2d9fd380Sjfb8856606 		/* Accessing its own device, inside mlx5 PMD. */
772*2d9fd380Sjfb8856606 		ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1);
773*2d9fd380Sjfb8856606 		if (ret != 0) {
774*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
775*2d9fd380Sjfb8856606 			goto error;
776*2d9fd380Sjfb8856606 		}
777*2d9fd380Sjfb8856606 		/* Pass TxQ's information to peer RxQ and try binding. */
778*2d9fd380Sjfb8856606 		cur.peer_q = rx_queue;
779*2d9fd380Sjfb8856606 		cur.qp_id = txq_ctrl->obj->sq->id;
780*2d9fd380Sjfb8856606 		cur.vhca_id = priv->config.hca_attr.vhca_id;
781*2d9fd380Sjfb8856606 		cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
782*2d9fd380Sjfb8856606 		cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
783*2d9fd380Sjfb8856606 		/*
784*2d9fd380Sjfb8856606 		 * In order to access another device in a proper way, RTE level
785*2d9fd380Sjfb8856606 		 * private function is needed.
786*2d9fd380Sjfb8856606 		 */
787*2d9fd380Sjfb8856606 		ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue,
788*2d9fd380Sjfb8856606 						      &cur, 0);
789*2d9fd380Sjfb8856606 		if (ret != 0) {
790*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
791*2d9fd380Sjfb8856606 			goto error;
792*2d9fd380Sjfb8856606 		}
793*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, i);
794*2d9fd380Sjfb8856606 	}
795*2d9fd380Sjfb8856606 	return 0;
796*2d9fd380Sjfb8856606 error:
797*2d9fd380Sjfb8856606 	/*
798*2d9fd380Sjfb8856606 	 * Do roll-back process for the queues already bound.
799*2d9fd380Sjfb8856606 	 * No need to check the return value of the queue unbind function.
800*2d9fd380Sjfb8856606 	 */
801*2d9fd380Sjfb8856606 	do {
802*2d9fd380Sjfb8856606 		/* No validation is needed here. */
803*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, i);
804*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL)
805*2d9fd380Sjfb8856606 			continue;
806*2d9fd380Sjfb8856606 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
807*2d9fd380Sjfb8856606 		rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
808*2d9fd380Sjfb8856606 		mlx5_hairpin_queue_peer_unbind(dev, i, 1);
809*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, i);
810*2d9fd380Sjfb8856606 	} while (i--);
811*2d9fd380Sjfb8856606 	return ret;
812*2d9fd380Sjfb8856606 }
813*2d9fd380Sjfb8856606 
814*2d9fd380Sjfb8856606 /*
815*2d9fd380Sjfb8856606  * Unbind the hairpin port pair, HW configuration of both devices will be clear
816*2d9fd380Sjfb8856606  * and status will be reset for all the queues used between the them.
817*2d9fd380Sjfb8856606  * This function only supports to unbind the Tx from one Rx.
818*2d9fd380Sjfb8856606  *
819*2d9fd380Sjfb8856606  * @param dev
820*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
821*2d9fd380Sjfb8856606  * @param rx_port
822*2d9fd380Sjfb8856606  *   Port identifier of the Rx port.
823*2d9fd380Sjfb8856606  *
824*2d9fd380Sjfb8856606  * @return
825*2d9fd380Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
826*2d9fd380Sjfb8856606  */
827*2d9fd380Sjfb8856606 static int
mlx5_hairpin_unbind_single_port(struct rte_eth_dev * dev,uint16_t rx_port)828*2d9fd380Sjfb8856606 mlx5_hairpin_unbind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
829*2d9fd380Sjfb8856606 {
830*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
831*2d9fd380Sjfb8856606 	struct mlx5_txq_ctrl *txq_ctrl;
832*2d9fd380Sjfb8856606 	uint32_t i;
833*2d9fd380Sjfb8856606 	int ret;
834*2d9fd380Sjfb8856606 	uint16_t cur_port = priv->dev_data->port_id;
835*2d9fd380Sjfb8856606 
836*2d9fd380Sjfb8856606 	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
837*2d9fd380Sjfb8856606 		rte_errno = ENODEV;
838*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
839*2d9fd380Sjfb8856606 		return -rte_errno;
840*2d9fd380Sjfb8856606 	}
841*2d9fd380Sjfb8856606 	for (i = 0; i != priv->txqs_n; i++) {
842*2d9fd380Sjfb8856606 		uint16_t rx_queue;
843*2d9fd380Sjfb8856606 
844*2d9fd380Sjfb8856606 		txq_ctrl = mlx5_txq_get(dev, i);
845*2d9fd380Sjfb8856606 		if (txq_ctrl == NULL)
846*2d9fd380Sjfb8856606 			continue;
847*2d9fd380Sjfb8856606 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
848*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
849*2d9fd380Sjfb8856606 			continue;
850*2d9fd380Sjfb8856606 		}
851*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
852*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
853*2d9fd380Sjfb8856606 			continue;
854*2d9fd380Sjfb8856606 		}
855*2d9fd380Sjfb8856606 		/* Indeed, only the first used queue needs to be checked. */
856*2d9fd380Sjfb8856606 		if (txq_ctrl->hairpin_conf.manual_bind == 0) {
857*2d9fd380Sjfb8856606 			if (cur_port != rx_port) {
858*2d9fd380Sjfb8856606 				rte_errno = EINVAL;
859*2d9fd380Sjfb8856606 				DRV_LOG(ERR, "port %u and port %u are in"
860*2d9fd380Sjfb8856606 					" auto-bind mode", cur_port, rx_port);
861*2d9fd380Sjfb8856606 				mlx5_txq_release(dev, i);
862*2d9fd380Sjfb8856606 				return -rte_errno;
863*2d9fd380Sjfb8856606 			} else {
864*2d9fd380Sjfb8856606 				return 0;
865*2d9fd380Sjfb8856606 			}
866*2d9fd380Sjfb8856606 		}
867*2d9fd380Sjfb8856606 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
868*2d9fd380Sjfb8856606 		mlx5_txq_release(dev, i);
869*2d9fd380Sjfb8856606 		ret = rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
870*2d9fd380Sjfb8856606 		if (ret) {
871*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Rx queue %d unbind - failure",
872*2d9fd380Sjfb8856606 				rx_port, rx_queue);
873*2d9fd380Sjfb8856606 			return ret;
874*2d9fd380Sjfb8856606 		}
875*2d9fd380Sjfb8856606 		ret = mlx5_hairpin_queue_peer_unbind(dev, i, 1);
876*2d9fd380Sjfb8856606 		if (ret) {
877*2d9fd380Sjfb8856606 			DRV_LOG(ERR, "port %u Tx queue %d unbind - failure",
878*2d9fd380Sjfb8856606 				cur_port, i);
879*2d9fd380Sjfb8856606 			return ret;
880*2d9fd380Sjfb8856606 		}
881*2d9fd380Sjfb8856606 	}
882*2d9fd380Sjfb8856606 	return 0;
883*2d9fd380Sjfb8856606 }
884*2d9fd380Sjfb8856606 
885*2d9fd380Sjfb8856606 /*
886*2d9fd380Sjfb8856606  * Bind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
887*2d9fd380Sjfb8856606  * @see mlx5_hairpin_bind_single_port()
888*2d9fd380Sjfb8856606  */
889*2d9fd380Sjfb8856606 int
mlx5_hairpin_bind(struct rte_eth_dev * dev,uint16_t rx_port)890*2d9fd380Sjfb8856606 mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port)
891*2d9fd380Sjfb8856606 {
892*2d9fd380Sjfb8856606 	int ret = 0;
893*2d9fd380Sjfb8856606 	uint16_t p, pp;
894*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
895*2d9fd380Sjfb8856606 
896*2d9fd380Sjfb8856606 	/*
897*2d9fd380Sjfb8856606 	 * If the Rx port has no hairpin configuration with the current port,
898*2d9fd380Sjfb8856606 	 * the binding will be skipped in the called function of single port.
899*2d9fd380Sjfb8856606 	 * Device started status will be checked only before the queue
900*2d9fd380Sjfb8856606 	 * information updating.
901*2d9fd380Sjfb8856606 	 */
902*2d9fd380Sjfb8856606 	if (rx_port == RTE_MAX_ETHPORTS) {
903*2d9fd380Sjfb8856606 		MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) {
904*2d9fd380Sjfb8856606 			ret = mlx5_hairpin_bind_single_port(dev, p);
905*2d9fd380Sjfb8856606 			if (ret != 0)
906*2d9fd380Sjfb8856606 				goto unbind;
907*2d9fd380Sjfb8856606 		}
908*2d9fd380Sjfb8856606 		return ret;
909*2d9fd380Sjfb8856606 	} else {
910*2d9fd380Sjfb8856606 		return mlx5_hairpin_bind_single_port(dev, rx_port);
911*2d9fd380Sjfb8856606 	}
912*2d9fd380Sjfb8856606 unbind:
913*2d9fd380Sjfb8856606 	MLX5_ETH_FOREACH_DEV(pp, priv->pci_dev)
914*2d9fd380Sjfb8856606 		if (pp < p)
915*2d9fd380Sjfb8856606 			mlx5_hairpin_unbind_single_port(dev, pp);
916*2d9fd380Sjfb8856606 	return ret;
917*2d9fd380Sjfb8856606 }
918*2d9fd380Sjfb8856606 
919*2d9fd380Sjfb8856606 /*
920*2d9fd380Sjfb8856606  * Unbind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
921*2d9fd380Sjfb8856606  * @see mlx5_hairpin_unbind_single_port()
922*2d9fd380Sjfb8856606  */
923*2d9fd380Sjfb8856606 int
mlx5_hairpin_unbind(struct rte_eth_dev * dev,uint16_t rx_port)924*2d9fd380Sjfb8856606 mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port)
925*2d9fd380Sjfb8856606 {
926*2d9fd380Sjfb8856606 	int ret = 0;
927*2d9fd380Sjfb8856606 	uint16_t p;
928*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
929*2d9fd380Sjfb8856606 
930*2d9fd380Sjfb8856606 	if (rx_port == RTE_MAX_ETHPORTS)
931*2d9fd380Sjfb8856606 		MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) {
932*2d9fd380Sjfb8856606 			ret = mlx5_hairpin_unbind_single_port(dev, p);
933*2d9fd380Sjfb8856606 			if (ret != 0)
934*2d9fd380Sjfb8856606 				return ret;
935*2d9fd380Sjfb8856606 		}
936*2d9fd380Sjfb8856606 	else
937*2d9fd380Sjfb8856606 		ret = mlx5_hairpin_unbind_single_port(dev, rx_port);
938*2d9fd380Sjfb8856606 	return ret;
939*2d9fd380Sjfb8856606 }
940*2d9fd380Sjfb8856606 
941*2d9fd380Sjfb8856606 /*
942*2d9fd380Sjfb8856606  * DPDK callback to get the hairpin peer ports list.
943*2d9fd380Sjfb8856606  * This will return the actual number of peer ports and save the identifiers
944*2d9fd380Sjfb8856606  * into the array (sorted, may be different from that when setting up the
945*2d9fd380Sjfb8856606  * hairpin peer queues).
946*2d9fd380Sjfb8856606  * The peer port ID could be the same as the port ID of the current device.
947*2d9fd380Sjfb8856606  *
948*2d9fd380Sjfb8856606  * @param dev
949*2d9fd380Sjfb8856606  *   Pointer to Ethernet device structure.
950*2d9fd380Sjfb8856606  * @param peer_ports
951*2d9fd380Sjfb8856606  *   Pointer to array to save the port identifiers.
952*2d9fd380Sjfb8856606  * @param len
953*2d9fd380Sjfb8856606  *   The length of the array.
954*2d9fd380Sjfb8856606  * @param direction
955*2d9fd380Sjfb8856606  *   Current port to peer port direction.
956*2d9fd380Sjfb8856606  *   positive - current used as Tx to get all peer Rx ports.
957*2d9fd380Sjfb8856606  *   zero - current used as Rx to get all peer Tx ports.
958*2d9fd380Sjfb8856606  *
959*2d9fd380Sjfb8856606  * @return
960*2d9fd380Sjfb8856606  *   0 or positive value on success, actual number of peer ports.
961*2d9fd380Sjfb8856606  *   a negative errno value otherwise and rte_errno is set.
962*2d9fd380Sjfb8856606  */
963*2d9fd380Sjfb8856606 int
mlx5_hairpin_get_peer_ports(struct rte_eth_dev * dev,uint16_t * peer_ports,size_t len,uint32_t direction)964*2d9fd380Sjfb8856606 mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports,
965*2d9fd380Sjfb8856606 			    size_t len, uint32_t direction)
966*2d9fd380Sjfb8856606 {
967*2d9fd380Sjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
968*2d9fd380Sjfb8856606 	struct mlx5_txq_ctrl *txq_ctrl;
969*2d9fd380Sjfb8856606 	struct mlx5_rxq_ctrl *rxq_ctrl;
970*2d9fd380Sjfb8856606 	uint32_t i;
971*2d9fd380Sjfb8856606 	uint16_t pp;
972*2d9fd380Sjfb8856606 	uint32_t bits[(RTE_MAX_ETHPORTS + 31) / 32] = {0};
973*2d9fd380Sjfb8856606 	int ret = 0;
974*2d9fd380Sjfb8856606 
975*2d9fd380Sjfb8856606 	if (direction) {
976*2d9fd380Sjfb8856606 		for (i = 0; i < priv->txqs_n; i++) {
977*2d9fd380Sjfb8856606 			txq_ctrl = mlx5_txq_get(dev, i);
978*2d9fd380Sjfb8856606 			if (!txq_ctrl)
979*2d9fd380Sjfb8856606 				continue;
980*2d9fd380Sjfb8856606 			if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
981*2d9fd380Sjfb8856606 				mlx5_txq_release(dev, i);
982*2d9fd380Sjfb8856606 				continue;
983*2d9fd380Sjfb8856606 			}
984*2d9fd380Sjfb8856606 			pp = txq_ctrl->hairpin_conf.peers[0].port;
985*2d9fd380Sjfb8856606 			if (pp >= RTE_MAX_ETHPORTS) {
986*2d9fd380Sjfb8856606 				rte_errno = ERANGE;
987*2d9fd380Sjfb8856606 				mlx5_txq_release(dev, i);
988*2d9fd380Sjfb8856606 				DRV_LOG(ERR, "port %hu queue %u peer port "
989*2d9fd380Sjfb8856606 					"out of range %hu",
990*2d9fd380Sjfb8856606 					priv->dev_data->port_id, i, pp);
991*2d9fd380Sjfb8856606 				return -rte_errno;
992*2d9fd380Sjfb8856606 			}
993*2d9fd380Sjfb8856606 			bits[pp / 32] |= 1 << (pp % 32);
994*2d9fd380Sjfb8856606 			mlx5_txq_release(dev, i);
995*2d9fd380Sjfb8856606 		}
996*2d9fd380Sjfb8856606 	} else {
997*2d9fd380Sjfb8856606 		for (i = 0; i < priv->rxqs_n; i++) {
998*2d9fd380Sjfb8856606 			rxq_ctrl = mlx5_rxq_get(dev, i);
999*2d9fd380Sjfb8856606 			if (!rxq_ctrl)
1000*2d9fd380Sjfb8856606 				continue;
1001*2d9fd380Sjfb8856606 			if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
1002*2d9fd380Sjfb8856606 				mlx5_rxq_release(dev, i);
1003*2d9fd380Sjfb8856606 				continue;
1004*2d9fd380Sjfb8856606 			}
1005*2d9fd380Sjfb8856606 			pp = rxq_ctrl->hairpin_conf.peers[0].port;
1006*2d9fd380Sjfb8856606 			if (pp >= RTE_MAX_ETHPORTS) {
1007*2d9fd380Sjfb8856606 				rte_errno = ERANGE;
1008*2d9fd380Sjfb8856606 				mlx5_rxq_release(dev, i);
1009*2d9fd380Sjfb8856606 				DRV_LOG(ERR, "port %hu queue %u peer port "
1010*2d9fd380Sjfb8856606 					"out of range %hu",
1011*2d9fd380Sjfb8856606 					priv->dev_data->port_id, i, pp);
1012*2d9fd380Sjfb8856606 				return -rte_errno;
1013*2d9fd380Sjfb8856606 			}
1014*2d9fd380Sjfb8856606 			bits[pp / 32] |= 1 << (pp % 32);
1015*2d9fd380Sjfb8856606 			mlx5_rxq_release(dev, i);
1016*2d9fd380Sjfb8856606 		}
1017*2d9fd380Sjfb8856606 	}
1018*2d9fd380Sjfb8856606 	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
1019*2d9fd380Sjfb8856606 		if (bits[i / 32] & (1 << (i % 32))) {
1020*2d9fd380Sjfb8856606 			if ((size_t)ret >= len) {
1021*2d9fd380Sjfb8856606 				rte_errno = E2BIG;
1022*2d9fd380Sjfb8856606 				return -rte_errno;
1023*2d9fd380Sjfb8856606 			}
1024*2d9fd380Sjfb8856606 			peer_ports[ret++] = i;
1025*2d9fd380Sjfb8856606 		}
1026*2d9fd380Sjfb8856606 	}
1027*2d9fd380Sjfb8856606 	return ret;
1028*2d9fd380Sjfb8856606 }
1029*2d9fd380Sjfb8856606 
10304418919fSjohnjiang /**
1031a9643ea8Slogwang  * DPDK callback to start the device.
1032a9643ea8Slogwang  *
1033a9643ea8Slogwang  * Simulate device start by attaching all configured flows.
1034a9643ea8Slogwang  *
1035a9643ea8Slogwang  * @param dev
1036a9643ea8Slogwang  *   Pointer to Ethernet device structure.
1037a9643ea8Slogwang  *
1038a9643ea8Slogwang  * @return
1039579bf1e2Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
1040a9643ea8Slogwang  */
1041a9643ea8Slogwang int
mlx5_dev_start(struct rte_eth_dev * dev)1042a9643ea8Slogwang mlx5_dev_start(struct rte_eth_dev *dev)
1043a9643ea8Slogwang {
10441646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
1045579bf1e2Sjfb8856606 	int ret;
1046*2d9fd380Sjfb8856606 	int fine_inline;
1047a9643ea8Slogwang 
1048579bf1e2Sjfb8856606 	DRV_LOG(DEBUG, "port %u starting device", dev->data->port_id);
1049*2d9fd380Sjfb8856606 	fine_inline = rte_mbuf_dynflag_lookup
1050*2d9fd380Sjfb8856606 		(RTE_PMD_MLX5_FINE_GRANULARITY_INLINE, NULL);
1051*2d9fd380Sjfb8856606 	if (fine_inline >= 0)
1052*2d9fd380Sjfb8856606 		rte_net_mlx5_dynf_inline_mask = 1UL << fine_inline;
1053*2d9fd380Sjfb8856606 	else
1054*2d9fd380Sjfb8856606 		rte_net_mlx5_dynf_inline_mask = 0;
10554418919fSjohnjiang 	if (dev->data->nb_rx_queues > 0) {
10564418919fSjohnjiang 		ret = mlx5_dev_configure_rss_reta(dev);
10574418919fSjohnjiang 		if (ret) {
10584418919fSjohnjiang 			DRV_LOG(ERR, "port %u reta config failed: %s",
10594418919fSjohnjiang 				dev->data->port_id, strerror(rte_errno));
10604418919fSjohnjiang 			return -rte_errno;
10614418919fSjohnjiang 		}
10624418919fSjohnjiang 	}
1063*2d9fd380Sjfb8856606 	ret = mlx5_txpp_start(dev);
1064*2d9fd380Sjfb8856606 	if (ret) {
1065*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "port %u Tx packet pacing init failed: %s",
1066*2d9fd380Sjfb8856606 			dev->data->port_id, strerror(rte_errno));
1067*2d9fd380Sjfb8856606 		goto error;
1068*2d9fd380Sjfb8856606 	}
1069579bf1e2Sjfb8856606 	ret = mlx5_txq_start(dev);
1070579bf1e2Sjfb8856606 	if (ret) {
1071579bf1e2Sjfb8856606 		DRV_LOG(ERR, "port %u Tx queue allocation failed: %s",
1072579bf1e2Sjfb8856606 			dev->data->port_id, strerror(rte_errno));
1073*2d9fd380Sjfb8856606 		goto error;
1074a9643ea8Slogwang 	}
1075579bf1e2Sjfb8856606 	ret = mlx5_rxq_start(dev);
1076579bf1e2Sjfb8856606 	if (ret) {
1077579bf1e2Sjfb8856606 		DRV_LOG(ERR, "port %u Rx queue allocation failed: %s",
1078579bf1e2Sjfb8856606 			dev->data->port_id, strerror(rte_errno));
1079*2d9fd380Sjfb8856606 		goto error;
10802bfe3f2eSlogwang 	}
1081*2d9fd380Sjfb8856606 	/*
1082*2d9fd380Sjfb8856606 	 * Such step will be skipped if there is no hairpin TX queue configured
1083*2d9fd380Sjfb8856606 	 * with RX peer queue from the same device.
1084*2d9fd380Sjfb8856606 	 */
1085*2d9fd380Sjfb8856606 	ret = mlx5_hairpin_auto_bind(dev);
10864418919fSjohnjiang 	if (ret) {
1087*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "port %u hairpin auto binding failed: %s",
10884418919fSjohnjiang 			dev->data->port_id, strerror(rte_errno));
1089*2d9fd380Sjfb8856606 		goto error;
10904418919fSjohnjiang 	}
1091*2d9fd380Sjfb8856606 	/* Set started flag here for the following steps like control flow. */
1092579bf1e2Sjfb8856606 	dev->data->dev_started = 1;
1093579bf1e2Sjfb8856606 	ret = mlx5_rx_intr_vec_enable(dev);
1094579bf1e2Sjfb8856606 	if (ret) {
1095579bf1e2Sjfb8856606 		DRV_LOG(ERR, "port %u Rx interrupt vector creation failed",
10962bfe3f2eSlogwang 			dev->data->port_id);
10972bfe3f2eSlogwang 		goto error;
10982bfe3f2eSlogwang 	}
1099*2d9fd380Sjfb8856606 	mlx5_os_stats_init(dev);
1100579bf1e2Sjfb8856606 	ret = mlx5_traffic_enable(dev);
1101579bf1e2Sjfb8856606 	if (ret) {
1102*2d9fd380Sjfb8856606 		DRV_LOG(ERR, "port %u failed to set defaults flows",
1103579bf1e2Sjfb8856606 			dev->data->port_id);
1104579bf1e2Sjfb8856606 		goto error;
1105579bf1e2Sjfb8856606 	}
1106*2d9fd380Sjfb8856606 	/* Set a mask and offset of dynamic metadata flows into Rx queues. */
11070c6bd470Sfengbojiang 	mlx5_flow_rxq_dynf_metadata_set(dev);
1108*2d9fd380Sjfb8856606 	/* Set flags and context to convert Rx timestamps. */
1109*2d9fd380Sjfb8856606 	mlx5_rxq_timestamp_set(dev);
1110*2d9fd380Sjfb8856606 	/* Set a mask and offset of scheduling on timestamp into Tx queues. */
1111*2d9fd380Sjfb8856606 	mlx5_txq_dynf_timestamp_set(dev);
1112*2d9fd380Sjfb8856606 	/*
1113*2d9fd380Sjfb8856606 	 * In non-cached mode, it only needs to start the default mreg copy
1114*2d9fd380Sjfb8856606 	 * action and no flow created by application exists anymore.
1115*2d9fd380Sjfb8856606 	 * But it is worth wrapping the interface for further usage.
1116*2d9fd380Sjfb8856606 	 */
1117*2d9fd380Sjfb8856606 	ret = mlx5_flow_start_default(dev);
1118579bf1e2Sjfb8856606 	if (ret) {
1119*2d9fd380Sjfb8856606 		DRV_LOG(DEBUG, "port %u failed to start default actions: %s",
1120*2d9fd380Sjfb8856606 			dev->data->port_id, strerror(rte_errno));
1121579bf1e2Sjfb8856606 		goto error;
1122579bf1e2Sjfb8856606 	}
11234418919fSjohnjiang 	rte_wmb();
1124579bf1e2Sjfb8856606 	dev->tx_pkt_burst = mlx5_select_tx_function(dev);
1125579bf1e2Sjfb8856606 	dev->rx_pkt_burst = mlx5_select_rx_function(dev);
11264418919fSjohnjiang 	/* Enable datapath on secondary process. */
1127*2d9fd380Sjfb8856606 	mlx5_mp_os_req_start_rxtx(dev);
11280c6bd470Sfengbojiang 	if (priv->sh->intr_handle.fd >= 0) {
1129*2d9fd380Sjfb8856606 		priv->sh->port[priv->dev_port - 1].ih_port_id =
11300c6bd470Sfengbojiang 					(uint32_t)dev->data->port_id;
11310c6bd470Sfengbojiang 	} else {
11320c6bd470Sfengbojiang 		DRV_LOG(INFO, "port %u starts without LSC and RMV interrupts.",
11330c6bd470Sfengbojiang 			dev->data->port_id);
11340c6bd470Sfengbojiang 		dev->data->dev_conf.intr_conf.lsc = 0;
11350c6bd470Sfengbojiang 		dev->data->dev_conf.intr_conf.rmv = 0;
11360c6bd470Sfengbojiang 	}
11370c6bd470Sfengbojiang 	if (priv->sh->intr_handle_devx.fd >= 0)
1138*2d9fd380Sjfb8856606 		priv->sh->port[priv->dev_port - 1].devx_ih_port_id =
11390c6bd470Sfengbojiang 					(uint32_t)dev->data->port_id;
11402bfe3f2eSlogwang 	return 0;
11412bfe3f2eSlogwang error:
1142579bf1e2Sjfb8856606 	ret = rte_errno; /* Save rte_errno before cleanup. */
11432bfe3f2eSlogwang 	/* Rollback. */
11442bfe3f2eSlogwang 	dev->data->dev_started = 0;
1145*2d9fd380Sjfb8856606 	mlx5_flow_stop_default(dev);
1146579bf1e2Sjfb8856606 	mlx5_traffic_disable(dev);
1147579bf1e2Sjfb8856606 	mlx5_txq_stop(dev);
1148579bf1e2Sjfb8856606 	mlx5_rxq_stop(dev);
1149*2d9fd380Sjfb8856606 	mlx5_txpp_stop(dev); /* Stop last. */
1150579bf1e2Sjfb8856606 	rte_errno = ret; /* Restore rte_errno. */
1151579bf1e2Sjfb8856606 	return -rte_errno;
1152a9643ea8Slogwang }
1153a9643ea8Slogwang 
1154a9643ea8Slogwang /**
1155a9643ea8Slogwang  * DPDK callback to stop the device.
1156a9643ea8Slogwang  *
1157a9643ea8Slogwang  * Simulate device stop by detaching all configured flows.
1158a9643ea8Slogwang  *
1159a9643ea8Slogwang  * @param dev
1160a9643ea8Slogwang  *   Pointer to Ethernet device structure.
1161a9643ea8Slogwang  */
1162*2d9fd380Sjfb8856606 int
mlx5_dev_stop(struct rte_eth_dev * dev)1163a9643ea8Slogwang mlx5_dev_stop(struct rte_eth_dev *dev)
1164a9643ea8Slogwang {
11651646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
1166a9643ea8Slogwang 
11672bfe3f2eSlogwang 	dev->data->dev_started = 0;
11682bfe3f2eSlogwang 	/* Prevent crashes when queues are still in use. */
11692bfe3f2eSlogwang 	dev->rx_pkt_burst = removed_rx_burst;
11702bfe3f2eSlogwang 	dev->tx_pkt_burst = removed_tx_burst;
11712bfe3f2eSlogwang 	rte_wmb();
11724418919fSjohnjiang 	/* Disable datapath on secondary process. */
1173*2d9fd380Sjfb8856606 	mlx5_mp_os_req_stop_rxtx(dev);
11742bfe3f2eSlogwang 	usleep(1000 * priv->rxqs_n);
1175579bf1e2Sjfb8856606 	DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id);
1176*2d9fd380Sjfb8856606 	mlx5_flow_stop_default(dev);
1177*2d9fd380Sjfb8856606 	/* Control flows for default traffic can be removed firstly. */
1178579bf1e2Sjfb8856606 	mlx5_traffic_disable(dev);
1179*2d9fd380Sjfb8856606 	/* All RX queue flags will be cleared in the flush interface. */
1180*2d9fd380Sjfb8856606 	mlx5_flow_list_flush(dev, &priv->flows, true);
1181579bf1e2Sjfb8856606 	mlx5_rx_intr_vec_disable(dev);
1182*2d9fd380Sjfb8856606 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
1183*2d9fd380Sjfb8856606 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
1184579bf1e2Sjfb8856606 	mlx5_txq_stop(dev);
1185579bf1e2Sjfb8856606 	mlx5_rxq_stop(dev);
1186*2d9fd380Sjfb8856606 	mlx5_txpp_stop(dev);
1187*2d9fd380Sjfb8856606 
1188*2d9fd380Sjfb8856606 	return 0;
1189a9643ea8Slogwang }
11902bfe3f2eSlogwang 
11912bfe3f2eSlogwang /**
11922bfe3f2eSlogwang  * Enable traffic flows configured by control plane
11932bfe3f2eSlogwang  *
1194579bf1e2Sjfb8856606  * @param dev
11952bfe3f2eSlogwang  *   Pointer to Ethernet device private data.
11962bfe3f2eSlogwang  * @param dev
11972bfe3f2eSlogwang  *   Pointer to Ethernet device structure.
11982bfe3f2eSlogwang  *
11992bfe3f2eSlogwang  * @return
1200579bf1e2Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
12012bfe3f2eSlogwang  */
12022bfe3f2eSlogwang int
mlx5_traffic_enable(struct rte_eth_dev * dev)1203579bf1e2Sjfb8856606 mlx5_traffic_enable(struct rte_eth_dev *dev)
12042bfe3f2eSlogwang {
12051646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
12062bfe3f2eSlogwang 	struct rte_flow_item_eth bcast = {
12072bfe3f2eSlogwang 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
12082bfe3f2eSlogwang 	};
12092bfe3f2eSlogwang 	struct rte_flow_item_eth ipv6_multi_spec = {
12102bfe3f2eSlogwang 		.dst.addr_bytes = "\x33\x33\x00\x00\x00\x00",
12112bfe3f2eSlogwang 	};
12122bfe3f2eSlogwang 	struct rte_flow_item_eth ipv6_multi_mask = {
12132bfe3f2eSlogwang 		.dst.addr_bytes = "\xff\xff\x00\x00\x00\x00",
12142bfe3f2eSlogwang 	};
12152bfe3f2eSlogwang 	struct rte_flow_item_eth unicast = {
12162bfe3f2eSlogwang 		.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
12172bfe3f2eSlogwang 	};
12182bfe3f2eSlogwang 	struct rte_flow_item_eth unicast_mask = {
12192bfe3f2eSlogwang 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
12202bfe3f2eSlogwang 	};
12212bfe3f2eSlogwang 	const unsigned int vlan_filter_n = priv->vlan_filter_n;
12224418919fSjohnjiang 	const struct rte_ether_addr cmp = {
12232bfe3f2eSlogwang 		.addr_bytes = "\x00\x00\x00\x00\x00\x00",
12242bfe3f2eSlogwang 	};
12252bfe3f2eSlogwang 	unsigned int i;
12262bfe3f2eSlogwang 	unsigned int j;
12272bfe3f2eSlogwang 	int ret;
12282bfe3f2eSlogwang 
12294418919fSjohnjiang 	/*
12304418919fSjohnjiang 	 * Hairpin txq default flow should be created no matter if it is
12314418919fSjohnjiang 	 * isolation mode. Or else all the packets to be sent will be sent
12324418919fSjohnjiang 	 * out directly without the TX flow actions, e.g. encapsulation.
12334418919fSjohnjiang 	 */
12344418919fSjohnjiang 	for (i = 0; i != priv->txqs_n; ++i) {
12354418919fSjohnjiang 		struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
12364418919fSjohnjiang 		if (!txq_ctrl)
12374418919fSjohnjiang 			continue;
1238*2d9fd380Sjfb8856606 		/* Only Tx implicit mode requires the default Tx flow. */
1239*2d9fd380Sjfb8856606 		if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN &&
1240*2d9fd380Sjfb8856606 		    txq_ctrl->hairpin_conf.tx_explicit == 0 &&
1241*2d9fd380Sjfb8856606 		    txq_ctrl->hairpin_conf.peers[0].port ==
1242*2d9fd380Sjfb8856606 		    priv->dev_data->port_id) {
12434418919fSjohnjiang 			ret = mlx5_ctrl_flow_source_queue(dev, i);
12444418919fSjohnjiang 			if (ret) {
12454418919fSjohnjiang 				mlx5_txq_release(dev, i);
12464418919fSjohnjiang 				goto error;
12474418919fSjohnjiang 			}
12484418919fSjohnjiang 		}
12494418919fSjohnjiang 		mlx5_txq_release(dev, i);
12504418919fSjohnjiang 	}
12514418919fSjohnjiang 	if (priv->config.dv_esw_en && !priv->config.vf) {
12524418919fSjohnjiang 		if (mlx5_flow_create_esw_table_zero_flow(dev))
12534418919fSjohnjiang 			priv->fdb_def_rule = 1;
12544418919fSjohnjiang 		else
12554418919fSjohnjiang 			DRV_LOG(INFO, "port %u FDB default rule cannot be"
12564418919fSjohnjiang 				" configured - only Eswitch group 0 flows are"
12574418919fSjohnjiang 				" supported.", dev->data->port_id);
12584418919fSjohnjiang 	}
1259*2d9fd380Sjfb8856606 	if (!priv->config.lacp_by_user && priv->pf_bond >= 0) {
1260*2d9fd380Sjfb8856606 		ret = mlx5_flow_lacp_miss(dev);
1261*2d9fd380Sjfb8856606 		if (ret)
1262*2d9fd380Sjfb8856606 			DRV_LOG(INFO, "port %u LACP rule cannot be created - "
1263*2d9fd380Sjfb8856606 				"forward LACP to kernel.", dev->data->port_id);
1264*2d9fd380Sjfb8856606 		else
1265*2d9fd380Sjfb8856606 			DRV_LOG(INFO, "LACP traffic will be missed in port %u."
1266*2d9fd380Sjfb8856606 				, dev->data->port_id);
1267*2d9fd380Sjfb8856606 	}
12682bfe3f2eSlogwang 	if (priv->isolated)
12692bfe3f2eSlogwang 		return 0;
12702bfe3f2eSlogwang 	if (dev->data->promiscuous) {
12712bfe3f2eSlogwang 		struct rte_flow_item_eth promisc = {
12722bfe3f2eSlogwang 			.dst.addr_bytes = "\x00\x00\x00\x00\x00\x00",
12732bfe3f2eSlogwang 			.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
12742bfe3f2eSlogwang 			.type = 0,
12752bfe3f2eSlogwang 		};
12762bfe3f2eSlogwang 
1277579bf1e2Sjfb8856606 		ret = mlx5_ctrl_flow(dev, &promisc, &promisc);
1278579bf1e2Sjfb8856606 		if (ret)
1279579bf1e2Sjfb8856606 			goto error;
12802bfe3f2eSlogwang 	}
12812bfe3f2eSlogwang 	if (dev->data->all_multicast) {
12822bfe3f2eSlogwang 		struct rte_flow_item_eth multicast = {
12832bfe3f2eSlogwang 			.dst.addr_bytes = "\x01\x00\x00\x00\x00\x00",
12842bfe3f2eSlogwang 			.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
12852bfe3f2eSlogwang 			.type = 0,
12862bfe3f2eSlogwang 		};
12872bfe3f2eSlogwang 
1288579bf1e2Sjfb8856606 		ret = mlx5_ctrl_flow(dev, &multicast, &multicast);
1289579bf1e2Sjfb8856606 		if (ret)
1290579bf1e2Sjfb8856606 			goto error;
12912bfe3f2eSlogwang 	} else {
12922bfe3f2eSlogwang 		/* Add broadcast/multicast flows. */
12932bfe3f2eSlogwang 		for (i = 0; i != vlan_filter_n; ++i) {
12942bfe3f2eSlogwang 			uint16_t vlan = priv->vlan_filter[i];
12952bfe3f2eSlogwang 
12962bfe3f2eSlogwang 			struct rte_flow_item_vlan vlan_spec = {
12972bfe3f2eSlogwang 				.tci = rte_cpu_to_be_16(vlan),
12982bfe3f2eSlogwang 			};
1299579bf1e2Sjfb8856606 			struct rte_flow_item_vlan vlan_mask =
1300579bf1e2Sjfb8856606 				rte_flow_item_vlan_mask;
13012bfe3f2eSlogwang 
13022bfe3f2eSlogwang 			ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast,
13032bfe3f2eSlogwang 						  &vlan_spec, &vlan_mask);
13042bfe3f2eSlogwang 			if (ret)
13052bfe3f2eSlogwang 				goto error;
13062bfe3f2eSlogwang 			ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec,
13072bfe3f2eSlogwang 						  &ipv6_multi_mask,
13082bfe3f2eSlogwang 						  &vlan_spec, &vlan_mask);
13092bfe3f2eSlogwang 			if (ret)
13102bfe3f2eSlogwang 				goto error;
13112bfe3f2eSlogwang 		}
13122bfe3f2eSlogwang 		if (!vlan_filter_n) {
13132bfe3f2eSlogwang 			ret = mlx5_ctrl_flow(dev, &bcast, &bcast);
13142bfe3f2eSlogwang 			if (ret)
13152bfe3f2eSlogwang 				goto error;
13162bfe3f2eSlogwang 			ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec,
13172bfe3f2eSlogwang 					     &ipv6_multi_mask);
13182bfe3f2eSlogwang 			if (ret)
13192bfe3f2eSlogwang 				goto error;
13202bfe3f2eSlogwang 		}
13212bfe3f2eSlogwang 	}
13222bfe3f2eSlogwang 	/* Add MAC address flows. */
13232bfe3f2eSlogwang 	for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
13244418919fSjohnjiang 		struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
13252bfe3f2eSlogwang 
13262bfe3f2eSlogwang 		if (!memcmp(mac, &cmp, sizeof(*mac)))
13272bfe3f2eSlogwang 			continue;
13282bfe3f2eSlogwang 		memcpy(&unicast.dst.addr_bytes,
13292bfe3f2eSlogwang 		       mac->addr_bytes,
13304418919fSjohnjiang 		       RTE_ETHER_ADDR_LEN);
13312bfe3f2eSlogwang 		for (j = 0; j != vlan_filter_n; ++j) {
13322bfe3f2eSlogwang 			uint16_t vlan = priv->vlan_filter[j];
13332bfe3f2eSlogwang 
13342bfe3f2eSlogwang 			struct rte_flow_item_vlan vlan_spec = {
13352bfe3f2eSlogwang 				.tci = rte_cpu_to_be_16(vlan),
13362bfe3f2eSlogwang 			};
1337579bf1e2Sjfb8856606 			struct rte_flow_item_vlan vlan_mask =
1338579bf1e2Sjfb8856606 				rte_flow_item_vlan_mask;
13392bfe3f2eSlogwang 
13402bfe3f2eSlogwang 			ret = mlx5_ctrl_flow_vlan(dev, &unicast,
13412bfe3f2eSlogwang 						  &unicast_mask,
13422bfe3f2eSlogwang 						  &vlan_spec,
13432bfe3f2eSlogwang 						  &vlan_mask);
13442bfe3f2eSlogwang 			if (ret)
13452bfe3f2eSlogwang 				goto error;
13462bfe3f2eSlogwang 		}
13472bfe3f2eSlogwang 		if (!vlan_filter_n) {
1348579bf1e2Sjfb8856606 			ret = mlx5_ctrl_flow(dev, &unicast, &unicast_mask);
13492bfe3f2eSlogwang 			if (ret)
13502bfe3f2eSlogwang 				goto error;
13512bfe3f2eSlogwang 		}
13522bfe3f2eSlogwang 	}
13532bfe3f2eSlogwang 	return 0;
13542bfe3f2eSlogwang error:
1355579bf1e2Sjfb8856606 	ret = rte_errno; /* Save rte_errno before cleanup. */
1356*2d9fd380Sjfb8856606 	mlx5_flow_list_flush(dev, &priv->ctrl_flows, false);
1357579bf1e2Sjfb8856606 	rte_errno = ret; /* Restore rte_errno. */
1358579bf1e2Sjfb8856606 	return -rte_errno;
13592bfe3f2eSlogwang }
13602bfe3f2eSlogwang 
13612bfe3f2eSlogwang 
13622bfe3f2eSlogwang /**
13632bfe3f2eSlogwang  * Disable traffic flows configured by control plane
13642bfe3f2eSlogwang  *
13652bfe3f2eSlogwang  * @param dev
1366579bf1e2Sjfb8856606  *   Pointer to Ethernet device private data.
13672bfe3f2eSlogwang  */
1368579bf1e2Sjfb8856606 void
mlx5_traffic_disable(struct rte_eth_dev * dev)1369579bf1e2Sjfb8856606 mlx5_traffic_disable(struct rte_eth_dev *dev)
13702bfe3f2eSlogwang {
13711646932aSjfb8856606 	struct mlx5_priv *priv = dev->data->dev_private;
13722bfe3f2eSlogwang 
1373*2d9fd380Sjfb8856606 	mlx5_flow_list_flush(dev, &priv->ctrl_flows, false);
13742bfe3f2eSlogwang }
13752bfe3f2eSlogwang 
13762bfe3f2eSlogwang /**
13772bfe3f2eSlogwang  * Restart traffic flows configured by control plane
13782bfe3f2eSlogwang  *
13792bfe3f2eSlogwang  * @param dev
1380579bf1e2Sjfb8856606  *   Pointer to Ethernet device private data.
13812bfe3f2eSlogwang  *
13822bfe3f2eSlogwang  * @return
1383579bf1e2Sjfb8856606  *   0 on success, a negative errno value otherwise and rte_errno is set.
13842bfe3f2eSlogwang  */
13852bfe3f2eSlogwang int
mlx5_traffic_restart(struct rte_eth_dev * dev)13862bfe3f2eSlogwang mlx5_traffic_restart(struct rte_eth_dev *dev)
13872bfe3f2eSlogwang {
1388579bf1e2Sjfb8856606 	if (dev->data->dev_started) {
1389579bf1e2Sjfb8856606 		mlx5_traffic_disable(dev);
1390579bf1e2Sjfb8856606 		return mlx5_traffic_enable(dev);
1391579bf1e2Sjfb8856606 	}
13922bfe3f2eSlogwang 	return 0;
13932bfe3f2eSlogwang }
1394