xref: /dpdk/drivers/net/mlx5/mlx5_trigger.c (revision 37cd4501e873f30c69f738c3efe4730e7c95d60a)
18fd92a66SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
2e60fbd5bSAdrien Mazarguil  * Copyright 2015 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2015 Mellanox Technologies, Ltd
4e60fbd5bSAdrien Mazarguil  */
58fd92a66SOlivier Matz 
63f2fe392SNélio Laranjeiro #include <unistd.h>
7e60fbd5bSAdrien Mazarguil 
8e60fbd5bSAdrien Mazarguil #include <rte_ether.h>
9ffc905f3SFerruh Yigit #include <rte_ethdev_driver.h>
10198a3c33SNelio Laranjeiro #include <rte_interrupts.h>
11198a3c33SNelio Laranjeiro #include <rte_alarm.h>
12e60fbd5bSAdrien Mazarguil 
131260a87bSMichael Baum #include <mlx5_malloc.h>
141260a87bSMichael Baum 
15e60fbd5bSAdrien Mazarguil #include "mlx5.h"
16b8dc6b0eSVu Pham #include "mlx5_mr.h"
17e60fbd5bSAdrien Mazarguil #include "mlx5_rxtx.h"
18e60fbd5bSAdrien Mazarguil #include "mlx5_utils.h"
19efa79e68SOri Kam #include "rte_pmd_mlx5.h"
20e60fbd5bSAdrien Mazarguil 
21fb732b0aSNélio Laranjeiro /**
22fb732b0aSNélio Laranjeiro  * Stop traffic on Tx queues.
23fb732b0aSNélio Laranjeiro  *
24fb732b0aSNélio Laranjeiro  * @param dev
25fb732b0aSNélio Laranjeiro  *   Pointer to Ethernet device structure.
26fb732b0aSNélio Laranjeiro  */
276e78005aSNélio Laranjeiro static void
28af4f09f2SNélio Laranjeiro mlx5_txq_stop(struct rte_eth_dev *dev)
296e78005aSNélio Laranjeiro {
30dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
316e78005aSNélio Laranjeiro 	unsigned int i;
326e78005aSNélio Laranjeiro 
336e78005aSNélio Laranjeiro 	for (i = 0; i != priv->txqs_n; ++i)
34af4f09f2SNélio Laranjeiro 		mlx5_txq_release(dev, i);
356e78005aSNélio Laranjeiro }
366e78005aSNélio Laranjeiro 
37fb732b0aSNélio Laranjeiro /**
38fb732b0aSNélio Laranjeiro  * Start traffic on Tx queues.
39fb732b0aSNélio Laranjeiro  *
40fb732b0aSNélio Laranjeiro  * @param dev
41fb732b0aSNélio Laranjeiro  *   Pointer to Ethernet device structure.
42fb732b0aSNélio Laranjeiro  *
43fb732b0aSNélio Laranjeiro  * @return
44a6d83b6aSNélio Laranjeiro  *   0 on success, a negative errno value otherwise and rte_errno is set.
45fb732b0aSNélio Laranjeiro  */
466e78005aSNélio Laranjeiro static int
47af4f09f2SNélio Laranjeiro mlx5_txq_start(struct rte_eth_dev *dev)
486e78005aSNélio Laranjeiro {
49dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
506e78005aSNélio Laranjeiro 	unsigned int i;
51a6d83b6aSNélio Laranjeiro 	int ret;
526e78005aSNélio Laranjeiro 
536e78005aSNélio Laranjeiro 	for (i = 0; i != priv->txqs_n; ++i) {
54af4f09f2SNélio Laranjeiro 		struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
55f49f4483SMichael Baum 		struct mlx5_txq_data *txq_data = &txq_ctrl->txq;
56f49f4483SMichael Baum 		uint32_t flags = MLX5_MEM_RTE | MLX5_MEM_ZERO;
576e78005aSNélio Laranjeiro 
586e78005aSNélio Laranjeiro 		if (!txq_ctrl)
596e78005aSNélio Laranjeiro 			continue;
6086d259ceSMichael Baum 		if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD)
616e78005aSNélio Laranjeiro 			txq_alloc_elts(txq_ctrl);
62f49f4483SMichael Baum 		MLX5_ASSERT(!txq_ctrl->obj);
63f49f4483SMichael Baum 		txq_ctrl->obj = mlx5_malloc(flags, sizeof(struct mlx5_txq_obj),
64f49f4483SMichael Baum 					    0, txq_ctrl->socket);
65894c4a8eSOri Kam 		if (!txq_ctrl->obj) {
66f49f4483SMichael Baum 			DRV_LOG(ERR, "Port %u Tx queue %u cannot allocate "
67f49f4483SMichael Baum 				"memory resources.", dev->data->port_id,
68f49f4483SMichael Baum 				txq_data->idx);
69a6d83b6aSNélio Laranjeiro 			rte_errno = ENOMEM;
706e78005aSNélio Laranjeiro 			goto error;
716e78005aSNélio Laranjeiro 		}
72f49f4483SMichael Baum 		ret = priv->obj_ops.txq_obj_new(dev, i);
73f49f4483SMichael Baum 		if (ret < 0) {
74f49f4483SMichael Baum 			mlx5_free(txq_ctrl->obj);
75f49f4483SMichael Baum 			txq_ctrl->obj = NULL;
76f49f4483SMichael Baum 			goto error;
77f49f4483SMichael Baum 		}
78f49f4483SMichael Baum 		if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD) {
79f49f4483SMichael Baum 			size_t size = txq_data->cqe_s * sizeof(*txq_data->fcqs);
80f49f4483SMichael Baum 			txq_data->fcqs = mlx5_malloc(flags, size,
81f49f4483SMichael Baum 						     RTE_CACHE_LINE_SIZE,
82f49f4483SMichael Baum 						     txq_ctrl->socket);
83f49f4483SMichael Baum 			if (!txq_data->fcqs) {
84f49f4483SMichael Baum 				DRV_LOG(ERR, "Port %u Tx queue %u cannot "
85f49f4483SMichael Baum 					"allocate memory (FCQ).",
86f49f4483SMichael Baum 					dev->data->port_id, i);
87f49f4483SMichael Baum 				rte_errno = ENOMEM;
88f49f4483SMichael Baum 				goto error;
89f49f4483SMichael Baum 			}
90f49f4483SMichael Baum 		}
91f49f4483SMichael Baum 		DRV_LOG(DEBUG, "Port %u txq %u updated with %p.",
92f49f4483SMichael Baum 			dev->data->port_id, i, (void *)&txq_ctrl->obj);
93f49f4483SMichael Baum 		LIST_INSERT_HEAD(&priv->txqsobj, txq_ctrl->obj, next);
946e78005aSNélio Laranjeiro 	}
95a6d83b6aSNélio Laranjeiro 	return 0;
966e78005aSNélio Laranjeiro error:
97a6d83b6aSNélio Laranjeiro 	ret = rte_errno; /* Save rte_errno before cleanup. */
9824f653a7SYongseok Koh 	do {
9924f653a7SYongseok Koh 		mlx5_txq_release(dev, i);
10024f653a7SYongseok Koh 	} while (i-- != 0);
101a6d83b6aSNélio Laranjeiro 	rte_errno = ret; /* Restore rte_errno. */
102a6d83b6aSNélio Laranjeiro 	return -rte_errno;
1036e78005aSNélio Laranjeiro }
1046e78005aSNélio Laranjeiro 
105fb732b0aSNélio Laranjeiro /**
106fb732b0aSNélio Laranjeiro  * Stop traffic on Rx queues.
107fb732b0aSNélio Laranjeiro  *
108fb732b0aSNélio Laranjeiro  * @param dev
109fb732b0aSNélio Laranjeiro  *   Pointer to Ethernet device structure.
110fb732b0aSNélio Laranjeiro  */
111a1366b1aSNélio Laranjeiro static void
112af4f09f2SNélio Laranjeiro mlx5_rxq_stop(struct rte_eth_dev *dev)
113a1366b1aSNélio Laranjeiro {
114dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
115a1366b1aSNélio Laranjeiro 	unsigned int i;
116a1366b1aSNélio Laranjeiro 
117a1366b1aSNélio Laranjeiro 	for (i = 0; i != priv->rxqs_n; ++i)
118af4f09f2SNélio Laranjeiro 		mlx5_rxq_release(dev, i);
119a1366b1aSNélio Laranjeiro }
120a1366b1aSNélio Laranjeiro 
121fb732b0aSNélio Laranjeiro /**
122fb732b0aSNélio Laranjeiro  * Start traffic on Rx queues.
123fb732b0aSNélio Laranjeiro  *
124fb732b0aSNélio Laranjeiro  * @param dev
125fb732b0aSNélio Laranjeiro  *   Pointer to Ethernet device structure.
126fb732b0aSNélio Laranjeiro  *
127fb732b0aSNélio Laranjeiro  * @return
128a6d83b6aSNélio Laranjeiro  *   0 on success, a negative errno value otherwise and rte_errno is set.
129fb732b0aSNélio Laranjeiro  */
130a1366b1aSNélio Laranjeiro static int
131af4f09f2SNélio Laranjeiro mlx5_rxq_start(struct rte_eth_dev *dev)
132a1366b1aSNélio Laranjeiro {
133dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
134a1366b1aSNélio Laranjeiro 	unsigned int i;
135a1366b1aSNélio Laranjeiro 	int ret = 0;
136a1366b1aSNélio Laranjeiro 
1377d6bf6b8SYongseok Koh 	/* Allocate/reuse/resize mempool for Multi-Packet RQ. */
13824f653a7SYongseok Koh 	if (mlx5_mprq_alloc_mp(dev)) {
13924f653a7SYongseok Koh 		/* Should not release Rx queues but return immediately. */
14024f653a7SYongseok Koh 		return -rte_errno;
14124f653a7SYongseok Koh 	}
1421260a87bSMichael Baum 	DRV_LOG(DEBUG, "Port %u device_attr.max_qp_wr is %d.",
1431260a87bSMichael Baum 		dev->data->port_id, priv->sh->device_attr.max_qp_wr);
1441260a87bSMichael Baum 	DRV_LOG(DEBUG, "Port %u device_attr.max_sge is %d.",
1451260a87bSMichael Baum 		dev->data->port_id, priv->sh->device_attr.max_sge);
146a1366b1aSNélio Laranjeiro 	for (i = 0; i != priv->rxqs_n; ++i) {
147af4f09f2SNélio Laranjeiro 		struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_get(dev, i);
148a1366b1aSNélio Laranjeiro 
149a1366b1aSNélio Laranjeiro 		if (!rxq_ctrl)
150a1366b1aSNélio Laranjeiro 			continue;
1516deb19e1SMichael Baum 		if (rxq_ctrl->type == MLX5_RXQ_TYPE_STANDARD) {
152213e2727SViacheslav Ovsiienko 			/* Pre-register Rx mempools. */
153213e2727SViacheslav Ovsiienko 			if (mlx5_rxq_mprq_enabled(&rxq_ctrl->rxq)) {
154213e2727SViacheslav Ovsiienko 				mlx5_mr_update_mp(dev, &rxq_ctrl->rxq.mr_ctrl,
155213e2727SViacheslav Ovsiienko 						  rxq_ctrl->rxq.mprq_mp);
156213e2727SViacheslav Ovsiienko 			} else {
157213e2727SViacheslav Ovsiienko 				uint32_t s;
158213e2727SViacheslav Ovsiienko 
159213e2727SViacheslav Ovsiienko 				for (s = 0; s < rxq_ctrl->rxq.rxseg_n; s++)
160213e2727SViacheslav Ovsiienko 					mlx5_mr_update_mp
161213e2727SViacheslav Ovsiienko 						(dev, &rxq_ctrl->rxq.mr_ctrl,
162213e2727SViacheslav Ovsiienko 						rxq_ctrl->rxq.rxseg[s].mp);
163213e2727SViacheslav Ovsiienko 			}
164a1366b1aSNélio Laranjeiro 			ret = rxq_alloc_elts(rxq_ctrl);
165a1366b1aSNélio Laranjeiro 			if (ret)
166a1366b1aSNélio Laranjeiro 				goto error;
1676deb19e1SMichael Baum 		}
1681260a87bSMichael Baum 		MLX5_ASSERT(!rxq_ctrl->obj);
1691260a87bSMichael Baum 		rxq_ctrl->obj = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO,
1701260a87bSMichael Baum 					    sizeof(*rxq_ctrl->obj), 0,
1711260a87bSMichael Baum 					    rxq_ctrl->socket);
1721260a87bSMichael Baum 		if (!rxq_ctrl->obj) {
1731260a87bSMichael Baum 			DRV_LOG(ERR,
1741260a87bSMichael Baum 				"Port %u Rx queue %u can't allocate resources.",
1751260a87bSMichael Baum 				dev->data->port_id, (*priv->rxqs)[i]->idx);
1761260a87bSMichael Baum 			rte_errno = ENOMEM;
177a1366b1aSNélio Laranjeiro 			goto error;
178a1366b1aSNélio Laranjeiro 		}
1795eaf882eSMichael Baum 		ret = priv->obj_ops.rxq_obj_new(dev, i);
1801260a87bSMichael Baum 		if (ret) {
1811260a87bSMichael Baum 			mlx5_free(rxq_ctrl->obj);
1821260a87bSMichael Baum 			goto error;
1831260a87bSMichael Baum 		}
1841260a87bSMichael Baum 		DRV_LOG(DEBUG, "Port %u rxq %u updated with %p.",
1851260a87bSMichael Baum 			dev->data->port_id, i, (void *)&rxq_ctrl->obj);
1861260a87bSMichael Baum 		LIST_INSERT_HEAD(&priv->rxqsobj, rxq_ctrl->obj, next);
1871260a87bSMichael Baum 	}
188a6d83b6aSNélio Laranjeiro 	return 0;
189a1366b1aSNélio Laranjeiro error:
190a6d83b6aSNélio Laranjeiro 	ret = rte_errno; /* Save rte_errno before cleanup. */
19124f653a7SYongseok Koh 	do {
19224f653a7SYongseok Koh 		mlx5_rxq_release(dev, i);
19324f653a7SYongseok Koh 	} while (i-- != 0);
194a6d83b6aSNélio Laranjeiro 	rte_errno = ret; /* Restore rte_errno. */
195a6d83b6aSNélio Laranjeiro 	return -rte_errno;
196a1366b1aSNélio Laranjeiro }
197a1366b1aSNélio Laranjeiro 
198e60fbd5bSAdrien Mazarguil /**
1996a338ad4SOri Kam  * Binds Tx queues to Rx queues for hairpin.
2006a338ad4SOri Kam  *
2016a338ad4SOri Kam  * Binds Tx queues to the target Rx queues.
2026a338ad4SOri Kam  *
2036a338ad4SOri Kam  * @param dev
2046a338ad4SOri Kam  *   Pointer to Ethernet device structure.
2056a338ad4SOri Kam  *
2066a338ad4SOri Kam  * @return
2076a338ad4SOri Kam  *   0 on success, a negative errno value otherwise and rte_errno is set.
2086a338ad4SOri Kam  */
2096a338ad4SOri Kam static int
210*37cd4501SBing Zhao mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
2116a338ad4SOri Kam {
2126a338ad4SOri Kam 	struct mlx5_priv *priv = dev->data->dev_private;
2136a338ad4SOri Kam 	struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
2146a338ad4SOri Kam 	struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
2156a338ad4SOri Kam 	struct mlx5_txq_ctrl *txq_ctrl;
2166a338ad4SOri Kam 	struct mlx5_rxq_ctrl *rxq_ctrl;
2176a338ad4SOri Kam 	struct mlx5_devx_obj *sq;
2186a338ad4SOri Kam 	struct mlx5_devx_obj *rq;
2196a338ad4SOri Kam 	unsigned int i;
2206a338ad4SOri Kam 	int ret = 0;
2216a338ad4SOri Kam 
2226a338ad4SOri Kam 	for (i = 0; i != priv->txqs_n; ++i) {
2236a338ad4SOri Kam 		txq_ctrl = mlx5_txq_get(dev, i);
2246a338ad4SOri Kam 		if (!txq_ctrl)
2256a338ad4SOri Kam 			continue;
2266a338ad4SOri Kam 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
2276a338ad4SOri Kam 			mlx5_txq_release(dev, i);
2286a338ad4SOri Kam 			continue;
2296a338ad4SOri Kam 		}
2306a338ad4SOri Kam 		if (!txq_ctrl->obj) {
2316a338ad4SOri Kam 			rte_errno = ENOMEM;
2326a338ad4SOri Kam 			DRV_LOG(ERR, "port %u no txq object found: %d",
2336a338ad4SOri Kam 				dev->data->port_id, i);
2346a338ad4SOri Kam 			mlx5_txq_release(dev, i);
2356a338ad4SOri Kam 			return -rte_errno;
2366a338ad4SOri Kam 		}
2376a338ad4SOri Kam 		sq = txq_ctrl->obj->sq;
2386a338ad4SOri Kam 		rxq_ctrl = mlx5_rxq_get(dev,
2396a338ad4SOri Kam 					txq_ctrl->hairpin_conf.peers[0].queue);
2406a338ad4SOri Kam 		if (!rxq_ctrl) {
2416a338ad4SOri Kam 			mlx5_txq_release(dev, i);
2426a338ad4SOri Kam 			rte_errno = EINVAL;
2436a338ad4SOri Kam 			DRV_LOG(ERR, "port %u no rxq object found: %d",
2446a338ad4SOri Kam 				dev->data->port_id,
2456a338ad4SOri Kam 				txq_ctrl->hairpin_conf.peers[0].queue);
2466a338ad4SOri Kam 			return -rte_errno;
2476a338ad4SOri Kam 		}
2486a338ad4SOri Kam 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN ||
2496a338ad4SOri Kam 		    rxq_ctrl->hairpin_conf.peers[0].queue != i) {
2506a338ad4SOri Kam 			rte_errno = ENOMEM;
2516a338ad4SOri Kam 			DRV_LOG(ERR, "port %u Tx queue %d can't be binded to "
2526a338ad4SOri Kam 				"Rx queue %d", dev->data->port_id,
2536a338ad4SOri Kam 				i, txq_ctrl->hairpin_conf.peers[0].queue);
2546a338ad4SOri Kam 			goto error;
2556a338ad4SOri Kam 		}
2566a338ad4SOri Kam 		rq = rxq_ctrl->obj->rq;
2576a338ad4SOri Kam 		if (!rq) {
2586a338ad4SOri Kam 			rte_errno = ENOMEM;
2596a338ad4SOri Kam 			DRV_LOG(ERR, "port %u hairpin no matching rxq: %d",
2606a338ad4SOri Kam 				dev->data->port_id,
2616a338ad4SOri Kam 				txq_ctrl->hairpin_conf.peers[0].queue);
2626a338ad4SOri Kam 			goto error;
2636a338ad4SOri Kam 		}
2646a338ad4SOri Kam 		sq_attr.state = MLX5_SQC_STATE_RDY;
2656a338ad4SOri Kam 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
2666a338ad4SOri Kam 		sq_attr.hairpin_peer_rq = rq->id;
2676a338ad4SOri Kam 		sq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
2686a338ad4SOri Kam 		ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr);
2696a338ad4SOri Kam 		if (ret)
2706a338ad4SOri Kam 			goto error;
2716a338ad4SOri Kam 		rq_attr.state = MLX5_SQC_STATE_RDY;
2726a338ad4SOri Kam 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
2736a338ad4SOri Kam 		rq_attr.hairpin_peer_sq = sq->id;
2746a338ad4SOri Kam 		rq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
2756a338ad4SOri Kam 		ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
2766a338ad4SOri Kam 		if (ret)
2776a338ad4SOri Kam 			goto error;
2786a338ad4SOri Kam 		mlx5_txq_release(dev, i);
2796a338ad4SOri Kam 		mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
2806a338ad4SOri Kam 	}
2816a338ad4SOri Kam 	return 0;
2826a338ad4SOri Kam error:
2836a338ad4SOri Kam 	mlx5_txq_release(dev, i);
2846a338ad4SOri Kam 	mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
2856a338ad4SOri Kam 	return -rte_errno;
2866a338ad4SOri Kam }
2876a338ad4SOri Kam 
288*37cd4501SBing Zhao /*
289*37cd4501SBing Zhao  * Fetch the peer queue's SW & HW information.
290*37cd4501SBing Zhao  *
291*37cd4501SBing Zhao  * @param dev
292*37cd4501SBing Zhao  *   Pointer to Ethernet device structure.
293*37cd4501SBing Zhao  * @param peer_queue
294*37cd4501SBing Zhao  *   Index of the queue to fetch the information.
295*37cd4501SBing Zhao  * @param current_info
296*37cd4501SBing Zhao  *   Pointer to the input peer information, not used currently.
297*37cd4501SBing Zhao  * @param peer_info
298*37cd4501SBing Zhao  *   Pointer to the structure to store the information, output.
299*37cd4501SBing Zhao  * @param direction
300*37cd4501SBing Zhao  *   Positive to get the RxQ information, zero to get the TxQ information.
301*37cd4501SBing Zhao  *
302*37cd4501SBing Zhao  * @return
303*37cd4501SBing Zhao  *   0 on success, a negative errno value otherwise and rte_errno is set.
304*37cd4501SBing Zhao  */
305*37cd4501SBing Zhao int
306*37cd4501SBing Zhao mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue,
307*37cd4501SBing Zhao 			       struct rte_hairpin_peer_info *current_info,
308*37cd4501SBing Zhao 			       struct rte_hairpin_peer_info *peer_info,
309*37cd4501SBing Zhao 			       uint32_t direction)
310*37cd4501SBing Zhao {
311*37cd4501SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
312*37cd4501SBing Zhao 	RTE_SET_USED(current_info);
313*37cd4501SBing Zhao 
314*37cd4501SBing Zhao 	if (dev->data->dev_started == 0) {
315*37cd4501SBing Zhao 		rte_errno = EBUSY;
316*37cd4501SBing Zhao 		DRV_LOG(ERR, "peer port %u is not started",
317*37cd4501SBing Zhao 			dev->data->port_id);
318*37cd4501SBing Zhao 		return -rte_errno;
319*37cd4501SBing Zhao 	}
320*37cd4501SBing Zhao 	/*
321*37cd4501SBing Zhao 	 * Peer port used as egress. In the current design, hairpin Tx queue
322*37cd4501SBing Zhao 	 * will be bound to the peer Rx queue. Indeed, only the information of
323*37cd4501SBing Zhao 	 * peer Rx queue needs to be fetched.
324*37cd4501SBing Zhao 	 */
325*37cd4501SBing Zhao 	if (direction == 0) {
326*37cd4501SBing Zhao 		struct mlx5_txq_ctrl *txq_ctrl;
327*37cd4501SBing Zhao 
328*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, peer_queue);
329*37cd4501SBing Zhao 		if (txq_ctrl == NULL) {
330*37cd4501SBing Zhao 			rte_errno = EINVAL;
331*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
332*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
333*37cd4501SBing Zhao 			return -rte_errno;
334*37cd4501SBing Zhao 		}
335*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
336*37cd4501SBing Zhao 			rte_errno = EINVAL;
337*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d is not a hairpin Txq",
338*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
339*37cd4501SBing Zhao 			mlx5_txq_release(dev, peer_queue);
340*37cd4501SBing Zhao 			return -rte_errno;
341*37cd4501SBing Zhao 		}
342*37cd4501SBing Zhao 		if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
343*37cd4501SBing Zhao 			rte_errno = ENOMEM;
344*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Txq object found: %d",
345*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
346*37cd4501SBing Zhao 			mlx5_txq_release(dev, peer_queue);
347*37cd4501SBing Zhao 			return -rte_errno;
348*37cd4501SBing Zhao 		}
349*37cd4501SBing Zhao 		peer_info->qp_id = txq_ctrl->obj->sq->id;
350*37cd4501SBing Zhao 		peer_info->vhca_id = priv->config.hca_attr.vhca_id;
351*37cd4501SBing Zhao 		/* 1-to-1 mapping, only the first one is used. */
352*37cd4501SBing Zhao 		peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue;
353*37cd4501SBing Zhao 		peer_info->tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
354*37cd4501SBing Zhao 		peer_info->manual_bind = txq_ctrl->hairpin_conf.manual_bind;
355*37cd4501SBing Zhao 		mlx5_txq_release(dev, peer_queue);
356*37cd4501SBing Zhao 	} else { /* Peer port used as ingress. */
357*37cd4501SBing Zhao 		struct mlx5_rxq_ctrl *rxq_ctrl;
358*37cd4501SBing Zhao 
359*37cd4501SBing Zhao 		rxq_ctrl = mlx5_rxq_get(dev, peer_queue);
360*37cd4501SBing Zhao 		if (rxq_ctrl == NULL) {
361*37cd4501SBing Zhao 			rte_errno = EINVAL;
362*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
363*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
364*37cd4501SBing Zhao 			return -rte_errno;
365*37cd4501SBing Zhao 		}
366*37cd4501SBing Zhao 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
367*37cd4501SBing Zhao 			rte_errno = EINVAL;
368*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d is not a hairpin Rxq",
369*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
370*37cd4501SBing Zhao 			mlx5_rxq_release(dev, peer_queue);
371*37cd4501SBing Zhao 			return -rte_errno;
372*37cd4501SBing Zhao 		}
373*37cd4501SBing Zhao 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
374*37cd4501SBing Zhao 			rte_errno = ENOMEM;
375*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
376*37cd4501SBing Zhao 				dev->data->port_id, peer_queue);
377*37cd4501SBing Zhao 			mlx5_rxq_release(dev, peer_queue);
378*37cd4501SBing Zhao 			return -rte_errno;
379*37cd4501SBing Zhao 		}
380*37cd4501SBing Zhao 		peer_info->qp_id = rxq_ctrl->obj->rq->id;
381*37cd4501SBing Zhao 		peer_info->vhca_id = priv->config.hca_attr.vhca_id;
382*37cd4501SBing Zhao 		peer_info->peer_q = rxq_ctrl->hairpin_conf.peers[0].queue;
383*37cd4501SBing Zhao 		peer_info->tx_explicit = rxq_ctrl->hairpin_conf.tx_explicit;
384*37cd4501SBing Zhao 		peer_info->manual_bind = rxq_ctrl->hairpin_conf.manual_bind;
385*37cd4501SBing Zhao 		mlx5_rxq_release(dev, peer_queue);
386*37cd4501SBing Zhao 	}
387*37cd4501SBing Zhao 	return 0;
388*37cd4501SBing Zhao }
389*37cd4501SBing Zhao 
390*37cd4501SBing Zhao /*
391*37cd4501SBing Zhao  * Bind the hairpin queue with the peer HW information.
392*37cd4501SBing Zhao  * This needs to be called twice both for Tx and Rx queues of a pair.
393*37cd4501SBing Zhao  * If the queue is already bound, it is considered successful.
394*37cd4501SBing Zhao  *
395*37cd4501SBing Zhao  * @param dev
396*37cd4501SBing Zhao  *   Pointer to Ethernet device structure.
397*37cd4501SBing Zhao  * @param cur_queue
398*37cd4501SBing Zhao  *   Index of the queue to change the HW configuration to bind.
399*37cd4501SBing Zhao  * @param peer_info
400*37cd4501SBing Zhao  *   Pointer to information of the peer queue.
401*37cd4501SBing Zhao  * @param direction
402*37cd4501SBing Zhao  *   Positive to configure the TxQ, zero to configure the RxQ.
403*37cd4501SBing Zhao  *
404*37cd4501SBing Zhao  * @return
405*37cd4501SBing Zhao  *   0 on success, a negative errno value otherwise and rte_errno is set.
406*37cd4501SBing Zhao  */
407*37cd4501SBing Zhao int
408*37cd4501SBing Zhao mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue,
409*37cd4501SBing Zhao 			     struct rte_hairpin_peer_info *peer_info,
410*37cd4501SBing Zhao 			     uint32_t direction)
411*37cd4501SBing Zhao {
412*37cd4501SBing Zhao 	int ret = 0;
413*37cd4501SBing Zhao 
414*37cd4501SBing Zhao 	/*
415*37cd4501SBing Zhao 	 * Consistency checking of the peer queue: opposite direction is used
416*37cd4501SBing Zhao 	 * to get the peer queue info with ethdev port ID, no need to check.
417*37cd4501SBing Zhao 	 */
418*37cd4501SBing Zhao 	if (peer_info->peer_q != cur_queue) {
419*37cd4501SBing Zhao 		rte_errno = EINVAL;
420*37cd4501SBing Zhao 		DRV_LOG(ERR, "port %u queue %d and peer queue %d mismatch",
421*37cd4501SBing Zhao 			dev->data->port_id, cur_queue, peer_info->peer_q);
422*37cd4501SBing Zhao 		return -rte_errno;
423*37cd4501SBing Zhao 	}
424*37cd4501SBing Zhao 	if (direction != 0) {
425*37cd4501SBing Zhao 		struct mlx5_txq_ctrl *txq_ctrl;
426*37cd4501SBing Zhao 		struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
427*37cd4501SBing Zhao 
428*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, cur_queue);
429*37cd4501SBing Zhao 		if (txq_ctrl == NULL) {
430*37cd4501SBing Zhao 			rte_errno = EINVAL;
431*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
432*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
433*37cd4501SBing Zhao 			return -rte_errno;
434*37cd4501SBing Zhao 		}
435*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
436*37cd4501SBing Zhao 			rte_errno = EINVAL;
437*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
438*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
439*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
440*37cd4501SBing Zhao 			return -rte_errno;
441*37cd4501SBing Zhao 		}
442*37cd4501SBing Zhao 		if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) {
443*37cd4501SBing Zhao 			rte_errno = ENOMEM;
444*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Txq object found: %d",
445*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
446*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
447*37cd4501SBing Zhao 			return -rte_errno;
448*37cd4501SBing Zhao 		}
449*37cd4501SBing Zhao 		if (txq_ctrl->hairpin_status != 0) {
450*37cd4501SBing Zhao 			DRV_LOG(DEBUG, "port %u Tx queue %d is already bound",
451*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
452*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
453*37cd4501SBing Zhao 			return 0;
454*37cd4501SBing Zhao 		}
455*37cd4501SBing Zhao 		/*
456*37cd4501SBing Zhao 		 * All queues' of one port consistency checking is done in the
457*37cd4501SBing Zhao 		 * bind() function, and that is optional.
458*37cd4501SBing Zhao 		 */
459*37cd4501SBing Zhao 		if (peer_info->tx_explicit !=
460*37cd4501SBing Zhao 		    txq_ctrl->hairpin_conf.tx_explicit) {
461*37cd4501SBing Zhao 			rte_errno = EINVAL;
462*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Tx queue %d and peer Tx rule mode"
463*37cd4501SBing Zhao 				" mismatch", dev->data->port_id, cur_queue);
464*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
465*37cd4501SBing Zhao 			return -rte_errno;
466*37cd4501SBing Zhao 		}
467*37cd4501SBing Zhao 		if (peer_info->manual_bind !=
468*37cd4501SBing Zhao 		    txq_ctrl->hairpin_conf.manual_bind) {
469*37cd4501SBing Zhao 			rte_errno = EINVAL;
470*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Tx queue %d and peer binding mode"
471*37cd4501SBing Zhao 				" mismatch", dev->data->port_id, cur_queue);
472*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
473*37cd4501SBing Zhao 			return -rte_errno;
474*37cd4501SBing Zhao 		}
475*37cd4501SBing Zhao 		sq_attr.state = MLX5_SQC_STATE_RDY;
476*37cd4501SBing Zhao 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
477*37cd4501SBing Zhao 		sq_attr.hairpin_peer_rq = peer_info->qp_id;
478*37cd4501SBing Zhao 		sq_attr.hairpin_peer_vhca = peer_info->vhca_id;
479*37cd4501SBing Zhao 		ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
480*37cd4501SBing Zhao 		if (ret == 0)
481*37cd4501SBing Zhao 			txq_ctrl->hairpin_status = 1;
482*37cd4501SBing Zhao 		mlx5_txq_release(dev, cur_queue);
483*37cd4501SBing Zhao 	} else {
484*37cd4501SBing Zhao 		struct mlx5_rxq_ctrl *rxq_ctrl;
485*37cd4501SBing Zhao 		struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
486*37cd4501SBing Zhao 
487*37cd4501SBing Zhao 		rxq_ctrl = mlx5_rxq_get(dev, cur_queue);
488*37cd4501SBing Zhao 		if (rxq_ctrl == NULL) {
489*37cd4501SBing Zhao 			rte_errno = EINVAL;
490*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
491*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
492*37cd4501SBing Zhao 			return -rte_errno;
493*37cd4501SBing Zhao 		}
494*37cd4501SBing Zhao 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
495*37cd4501SBing Zhao 			rte_errno = EINVAL;
496*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
497*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
498*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
499*37cd4501SBing Zhao 			return -rte_errno;
500*37cd4501SBing Zhao 		}
501*37cd4501SBing Zhao 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
502*37cd4501SBing Zhao 			rte_errno = ENOMEM;
503*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
504*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
505*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
506*37cd4501SBing Zhao 			return -rte_errno;
507*37cd4501SBing Zhao 		}
508*37cd4501SBing Zhao 		if (rxq_ctrl->hairpin_status != 0) {
509*37cd4501SBing Zhao 			DRV_LOG(DEBUG, "port %u Rx queue %d is already bound",
510*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
511*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
512*37cd4501SBing Zhao 			return 0;
513*37cd4501SBing Zhao 		}
514*37cd4501SBing Zhao 		if (peer_info->tx_explicit !=
515*37cd4501SBing Zhao 		    rxq_ctrl->hairpin_conf.tx_explicit) {
516*37cd4501SBing Zhao 			rte_errno = EINVAL;
517*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Rx queue %d and peer Tx rule mode"
518*37cd4501SBing Zhao 				" mismatch", dev->data->port_id, cur_queue);
519*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
520*37cd4501SBing Zhao 			return -rte_errno;
521*37cd4501SBing Zhao 		}
522*37cd4501SBing Zhao 		if (peer_info->manual_bind !=
523*37cd4501SBing Zhao 		    rxq_ctrl->hairpin_conf.manual_bind) {
524*37cd4501SBing Zhao 			rte_errno = EINVAL;
525*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Rx queue %d and peer binding mode"
526*37cd4501SBing Zhao 				" mismatch", dev->data->port_id, cur_queue);
527*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
528*37cd4501SBing Zhao 			return -rte_errno;
529*37cd4501SBing Zhao 		}
530*37cd4501SBing Zhao 		rq_attr.state = MLX5_SQC_STATE_RDY;
531*37cd4501SBing Zhao 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
532*37cd4501SBing Zhao 		rq_attr.hairpin_peer_sq = peer_info->qp_id;
533*37cd4501SBing Zhao 		rq_attr.hairpin_peer_vhca = peer_info->vhca_id;
534*37cd4501SBing Zhao 		ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
535*37cd4501SBing Zhao 		if (ret == 0)
536*37cd4501SBing Zhao 			rxq_ctrl->hairpin_status = 1;
537*37cd4501SBing Zhao 		mlx5_rxq_release(dev, cur_queue);
538*37cd4501SBing Zhao 	}
539*37cd4501SBing Zhao 	return ret;
540*37cd4501SBing Zhao }
541*37cd4501SBing Zhao 
542*37cd4501SBing Zhao /*
543*37cd4501SBing Zhao  * Unbind the hairpin queue and reset its HW configuration.
544*37cd4501SBing Zhao  * This needs to be called twice both for Tx and Rx queues of a pair.
545*37cd4501SBing Zhao  * If the queue is already unbound, it is considered successful.
546*37cd4501SBing Zhao  *
547*37cd4501SBing Zhao  * @param dev
548*37cd4501SBing Zhao  *   Pointer to Ethernet device structure.
549*37cd4501SBing Zhao  * @param cur_queue
550*37cd4501SBing Zhao  *   Index of the queue to change the HW configuration to unbind.
551*37cd4501SBing Zhao  * @param direction
552*37cd4501SBing Zhao  *   Positive to reset the TxQ, zero to reset the RxQ.
553*37cd4501SBing Zhao  *
554*37cd4501SBing Zhao  * @return
555*37cd4501SBing Zhao  *   0 on success, a negative errno value otherwise and rte_errno is set.
556*37cd4501SBing Zhao  */
557*37cd4501SBing Zhao int
558*37cd4501SBing Zhao mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue,
559*37cd4501SBing Zhao 			       uint32_t direction)
560*37cd4501SBing Zhao {
561*37cd4501SBing Zhao 	int ret = 0;
562*37cd4501SBing Zhao 
563*37cd4501SBing Zhao 	if (direction != 0) {
564*37cd4501SBing Zhao 		struct mlx5_txq_ctrl *txq_ctrl;
565*37cd4501SBing Zhao 		struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
566*37cd4501SBing Zhao 
567*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, cur_queue);
568*37cd4501SBing Zhao 		if (txq_ctrl == NULL) {
569*37cd4501SBing Zhao 			rte_errno = EINVAL;
570*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Tx queue %d",
571*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
572*37cd4501SBing Zhao 			return -rte_errno;
573*37cd4501SBing Zhao 		}
574*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
575*37cd4501SBing Zhao 			rte_errno = EINVAL;
576*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d not a hairpin Txq",
577*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
578*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
579*37cd4501SBing Zhao 			return -rte_errno;
580*37cd4501SBing Zhao 		}
581*37cd4501SBing Zhao 		/* Already unbound, return success before obj checking. */
582*37cd4501SBing Zhao 		if (txq_ctrl->hairpin_status == 0) {
583*37cd4501SBing Zhao 			DRV_LOG(DEBUG, "port %u Tx queue %d is already unbound",
584*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
585*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
586*37cd4501SBing Zhao 			return 0;
587*37cd4501SBing Zhao 		}
588*37cd4501SBing Zhao 		if (!txq_ctrl->obj || !txq_ctrl->obj->sq) {
589*37cd4501SBing Zhao 			rte_errno = ENOMEM;
590*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Txq object found: %d",
591*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
592*37cd4501SBing Zhao 			mlx5_txq_release(dev, cur_queue);
593*37cd4501SBing Zhao 			return -rte_errno;
594*37cd4501SBing Zhao 		}
595*37cd4501SBing Zhao 		sq_attr.state = MLX5_SQC_STATE_RST;
596*37cd4501SBing Zhao 		sq_attr.sq_state = MLX5_SQC_STATE_RST;
597*37cd4501SBing Zhao 		ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr);
598*37cd4501SBing Zhao 		if (ret == 0)
599*37cd4501SBing Zhao 			txq_ctrl->hairpin_status = 0;
600*37cd4501SBing Zhao 		mlx5_txq_release(dev, cur_queue);
601*37cd4501SBing Zhao 	} else {
602*37cd4501SBing Zhao 		struct mlx5_rxq_ctrl *rxq_ctrl;
603*37cd4501SBing Zhao 		struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
604*37cd4501SBing Zhao 
605*37cd4501SBing Zhao 		rxq_ctrl = mlx5_rxq_get(dev, cur_queue);
606*37cd4501SBing Zhao 		if (rxq_ctrl == NULL) {
607*37cd4501SBing Zhao 			rte_errno = EINVAL;
608*37cd4501SBing Zhao 			DRV_LOG(ERR, "Failed to get port %u Rx queue %d",
609*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
610*37cd4501SBing Zhao 			return -rte_errno;
611*37cd4501SBing Zhao 		}
612*37cd4501SBing Zhao 		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
613*37cd4501SBing Zhao 			rte_errno = EINVAL;
614*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq",
615*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
616*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
617*37cd4501SBing Zhao 			return -rte_errno;
618*37cd4501SBing Zhao 		}
619*37cd4501SBing Zhao 		if (rxq_ctrl->hairpin_status == 0) {
620*37cd4501SBing Zhao 			DRV_LOG(DEBUG, "port %u Rx queue %d is already unbound",
621*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
622*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
623*37cd4501SBing Zhao 			return 0;
624*37cd4501SBing Zhao 		}
625*37cd4501SBing Zhao 		if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) {
626*37cd4501SBing Zhao 			rte_errno = ENOMEM;
627*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u no Rxq object found: %d",
628*37cd4501SBing Zhao 				dev->data->port_id, cur_queue);
629*37cd4501SBing Zhao 			mlx5_rxq_release(dev, cur_queue);
630*37cd4501SBing Zhao 			return -rte_errno;
631*37cd4501SBing Zhao 		}
632*37cd4501SBing Zhao 		rq_attr.state = MLX5_SQC_STATE_RST;
633*37cd4501SBing Zhao 		rq_attr.rq_state = MLX5_SQC_STATE_RST;
634*37cd4501SBing Zhao 		ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr);
635*37cd4501SBing Zhao 		if (ret == 0)
636*37cd4501SBing Zhao 			rxq_ctrl->hairpin_status = 0;
637*37cd4501SBing Zhao 		mlx5_rxq_release(dev, cur_queue);
638*37cd4501SBing Zhao 	}
639*37cd4501SBing Zhao 	return ret;
640*37cd4501SBing Zhao }
641*37cd4501SBing Zhao 
642*37cd4501SBing Zhao /*
643*37cd4501SBing Zhao  * Bind the hairpin port pairs, from the Tx to the peer Rx.
644*37cd4501SBing Zhao  * This function only supports to bind the Tx to one Rx.
645*37cd4501SBing Zhao  *
646*37cd4501SBing Zhao  * @param dev
647*37cd4501SBing Zhao  *   Pointer to Ethernet device structure.
648*37cd4501SBing Zhao  * @param rx_port
649*37cd4501SBing Zhao  *   Port identifier of the Rx port.
650*37cd4501SBing Zhao  *
651*37cd4501SBing Zhao  * @return
652*37cd4501SBing Zhao  *   0 on success, a negative errno value otherwise and rte_errno is set.
653*37cd4501SBing Zhao  */
654*37cd4501SBing Zhao static int
655*37cd4501SBing Zhao mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
656*37cd4501SBing Zhao {
657*37cd4501SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
658*37cd4501SBing Zhao 	int ret = 0;
659*37cd4501SBing Zhao 	struct mlx5_txq_ctrl *txq_ctrl;
660*37cd4501SBing Zhao 	uint32_t i;
661*37cd4501SBing Zhao 	struct rte_hairpin_peer_info peer = {0xffffff};
662*37cd4501SBing Zhao 	struct rte_hairpin_peer_info cur;
663*37cd4501SBing Zhao 	const struct rte_eth_hairpin_conf *conf;
664*37cd4501SBing Zhao 	uint16_t num_q = 0;
665*37cd4501SBing Zhao 	uint16_t local_port = priv->dev_data->port_id;
666*37cd4501SBing Zhao 	uint32_t manual;
667*37cd4501SBing Zhao 	uint32_t explicit;
668*37cd4501SBing Zhao 	uint16_t rx_queue;
669*37cd4501SBing Zhao 
670*37cd4501SBing Zhao 	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
671*37cd4501SBing Zhao 		rte_errno = ENODEV;
672*37cd4501SBing Zhao 		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
673*37cd4501SBing Zhao 		return -rte_errno;
674*37cd4501SBing Zhao 	}
675*37cd4501SBing Zhao 	/*
676*37cd4501SBing Zhao 	 * Before binding TxQ to peer RxQ, first round loop will be used for
677*37cd4501SBing Zhao 	 * checking the queues' configuration consistency. This would be a
678*37cd4501SBing Zhao 	 * little time consuming but better than doing the rollback.
679*37cd4501SBing Zhao 	 */
680*37cd4501SBing Zhao 	for (i = 0; i != priv->txqs_n; i++) {
681*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, i);
682*37cd4501SBing Zhao 		if (txq_ctrl == NULL)
683*37cd4501SBing Zhao 			continue;
684*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
685*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
686*37cd4501SBing Zhao 			continue;
687*37cd4501SBing Zhao 		}
688*37cd4501SBing Zhao 		/*
689*37cd4501SBing Zhao 		 * All hairpin Tx queues of a single port that connected to the
690*37cd4501SBing Zhao 		 * same peer Rx port should have the same "auto binding" and
691*37cd4501SBing Zhao 		 * "implicit Tx flow" modes.
692*37cd4501SBing Zhao 		 * Peer consistency checking will be done in per queue binding.
693*37cd4501SBing Zhao 		 */
694*37cd4501SBing Zhao 		conf = &txq_ctrl->hairpin_conf;
695*37cd4501SBing Zhao 		if (conf->peers[0].port == rx_port) {
696*37cd4501SBing Zhao 			if (num_q == 0) {
697*37cd4501SBing Zhao 				manual = conf->manual_bind;
698*37cd4501SBing Zhao 				explicit = conf->tx_explicit;
699*37cd4501SBing Zhao 			} else {
700*37cd4501SBing Zhao 				if (manual != conf->manual_bind ||
701*37cd4501SBing Zhao 				    explicit != conf->tx_explicit) {
702*37cd4501SBing Zhao 					rte_errno = EINVAL;
703*37cd4501SBing Zhao 					DRV_LOG(ERR, "port %u queue %d mode"
704*37cd4501SBing Zhao 						" mismatch: %u %u, %u %u",
705*37cd4501SBing Zhao 						local_port, i, manual,
706*37cd4501SBing Zhao 						conf->manual_bind, explicit,
707*37cd4501SBing Zhao 						conf->tx_explicit);
708*37cd4501SBing Zhao 					mlx5_txq_release(dev, i);
709*37cd4501SBing Zhao 					return -rte_errno;
710*37cd4501SBing Zhao 				}
711*37cd4501SBing Zhao 			}
712*37cd4501SBing Zhao 			num_q++;
713*37cd4501SBing Zhao 		}
714*37cd4501SBing Zhao 		mlx5_txq_release(dev, i);
715*37cd4501SBing Zhao 	}
716*37cd4501SBing Zhao 	/* Once no queue is configured, success is returned directly. */
717*37cd4501SBing Zhao 	if (num_q == 0)
718*37cd4501SBing Zhao 		return ret;
719*37cd4501SBing Zhao 	/* All the hairpin TX queues need to be traversed again. */
720*37cd4501SBing Zhao 	for (i = 0; i != priv->txqs_n; i++) {
721*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, i);
722*37cd4501SBing Zhao 		if (txq_ctrl == NULL)
723*37cd4501SBing Zhao 			continue;
724*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
725*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
726*37cd4501SBing Zhao 			continue;
727*37cd4501SBing Zhao 		}
728*37cd4501SBing Zhao 		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
729*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
730*37cd4501SBing Zhao 			continue;
731*37cd4501SBing Zhao 		}
732*37cd4501SBing Zhao 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
733*37cd4501SBing Zhao 		/*
734*37cd4501SBing Zhao 		 * Fetch peer RxQ's information.
735*37cd4501SBing Zhao 		 * No need to pass the information of the current queue.
736*37cd4501SBing Zhao 		 */
737*37cd4501SBing Zhao 		ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue,
738*37cd4501SBing Zhao 							NULL, &peer, 1);
739*37cd4501SBing Zhao 		if (ret != 0) {
740*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
741*37cd4501SBing Zhao 			goto error;
742*37cd4501SBing Zhao 		}
743*37cd4501SBing Zhao 		/* Accessing its own device, inside mlx5 PMD. */
744*37cd4501SBing Zhao 		ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1);
745*37cd4501SBing Zhao 		if (ret != 0) {
746*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
747*37cd4501SBing Zhao 			goto error;
748*37cd4501SBing Zhao 		}
749*37cd4501SBing Zhao 		/* Pass TxQ's information to peer RxQ and try binding. */
750*37cd4501SBing Zhao 		cur.peer_q = rx_queue;
751*37cd4501SBing Zhao 		cur.qp_id = txq_ctrl->obj->sq->id;
752*37cd4501SBing Zhao 		cur.vhca_id = priv->config.hca_attr.vhca_id;
753*37cd4501SBing Zhao 		cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
754*37cd4501SBing Zhao 		cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
755*37cd4501SBing Zhao 		/*
756*37cd4501SBing Zhao 		 * In order to access another device in a proper way, RTE level
757*37cd4501SBing Zhao 		 * private function is needed.
758*37cd4501SBing Zhao 		 */
759*37cd4501SBing Zhao 		ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue,
760*37cd4501SBing Zhao 						      &cur, 0);
761*37cd4501SBing Zhao 		if (ret != 0) {
762*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
763*37cd4501SBing Zhao 			goto error;
764*37cd4501SBing Zhao 		}
765*37cd4501SBing Zhao 		mlx5_txq_release(dev, i);
766*37cd4501SBing Zhao 	}
767*37cd4501SBing Zhao 	return 0;
768*37cd4501SBing Zhao error:
769*37cd4501SBing Zhao 	/*
770*37cd4501SBing Zhao 	 * Do roll-back process for the queues already bound.
771*37cd4501SBing Zhao 	 * No need to check the return value of the queue unbind function.
772*37cd4501SBing Zhao 	 */
773*37cd4501SBing Zhao 	do {
774*37cd4501SBing Zhao 		/* No validation is needed here. */
775*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, i);
776*37cd4501SBing Zhao 		if (txq_ctrl == NULL)
777*37cd4501SBing Zhao 			continue;
778*37cd4501SBing Zhao 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
779*37cd4501SBing Zhao 		rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
780*37cd4501SBing Zhao 		mlx5_hairpin_queue_peer_unbind(dev, i, 1);
781*37cd4501SBing Zhao 		mlx5_txq_release(dev, i);
782*37cd4501SBing Zhao 	} while (i--);
783*37cd4501SBing Zhao 	return ret;
784*37cd4501SBing Zhao }
785*37cd4501SBing Zhao 
786*37cd4501SBing Zhao /*
787*37cd4501SBing Zhao  * Unbind the hairpin port pair, HW configuration of both devices will be clear
788*37cd4501SBing Zhao  * and status will be reset for all the queues used between the them.
789*37cd4501SBing Zhao  * This function only supports to unbind the Tx from one Rx.
790*37cd4501SBing Zhao  *
791*37cd4501SBing Zhao  * @param dev
792*37cd4501SBing Zhao  *   Pointer to Ethernet device structure.
793*37cd4501SBing Zhao  * @param rx_port
794*37cd4501SBing Zhao  *   Port identifier of the Rx port.
795*37cd4501SBing Zhao  *
796*37cd4501SBing Zhao  * @return
797*37cd4501SBing Zhao  *   0 on success, a negative errno value otherwise and rte_errno is set.
798*37cd4501SBing Zhao  */
799*37cd4501SBing Zhao static int
800*37cd4501SBing Zhao mlx5_hairpin_unbind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
801*37cd4501SBing Zhao {
802*37cd4501SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
803*37cd4501SBing Zhao 	struct mlx5_txq_ctrl *txq_ctrl;
804*37cd4501SBing Zhao 	uint32_t i;
805*37cd4501SBing Zhao 	int ret;
806*37cd4501SBing Zhao 	uint16_t cur_port = priv->dev_data->port_id;
807*37cd4501SBing Zhao 
808*37cd4501SBing Zhao 	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
809*37cd4501SBing Zhao 		rte_errno = ENODEV;
810*37cd4501SBing Zhao 		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
811*37cd4501SBing Zhao 		return -rte_errno;
812*37cd4501SBing Zhao 	}
813*37cd4501SBing Zhao 	for (i = 0; i != priv->txqs_n; i++) {
814*37cd4501SBing Zhao 		uint16_t rx_queue;
815*37cd4501SBing Zhao 
816*37cd4501SBing Zhao 		txq_ctrl = mlx5_txq_get(dev, i);
817*37cd4501SBing Zhao 		if (txq_ctrl == NULL)
818*37cd4501SBing Zhao 			continue;
819*37cd4501SBing Zhao 		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
820*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
821*37cd4501SBing Zhao 			continue;
822*37cd4501SBing Zhao 		}
823*37cd4501SBing Zhao 		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
824*37cd4501SBing Zhao 			mlx5_txq_release(dev, i);
825*37cd4501SBing Zhao 			continue;
826*37cd4501SBing Zhao 		}
827*37cd4501SBing Zhao 		/* Indeed, only the first used queue needs to be checked. */
828*37cd4501SBing Zhao 		if (txq_ctrl->hairpin_conf.manual_bind == 0) {
829*37cd4501SBing Zhao 			if (cur_port != rx_port) {
830*37cd4501SBing Zhao 				rte_errno = EINVAL;
831*37cd4501SBing Zhao 				DRV_LOG(ERR, "port %u and port %u are in"
832*37cd4501SBing Zhao 					" auto-bind mode", cur_port, rx_port);
833*37cd4501SBing Zhao 				mlx5_txq_release(dev, i);
834*37cd4501SBing Zhao 				return -rte_errno;
835*37cd4501SBing Zhao 			} else {
836*37cd4501SBing Zhao 				return 0;
837*37cd4501SBing Zhao 			}
838*37cd4501SBing Zhao 		}
839*37cd4501SBing Zhao 		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
840*37cd4501SBing Zhao 		mlx5_txq_release(dev, i);
841*37cd4501SBing Zhao 		ret = rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
842*37cd4501SBing Zhao 		if (ret) {
843*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Rx queue %d unbind - failure",
844*37cd4501SBing Zhao 				rx_port, rx_queue);
845*37cd4501SBing Zhao 			return ret;
846*37cd4501SBing Zhao 		}
847*37cd4501SBing Zhao 		ret = mlx5_hairpin_queue_peer_unbind(dev, i, 1);
848*37cd4501SBing Zhao 		if (ret) {
849*37cd4501SBing Zhao 			DRV_LOG(ERR, "port %u Tx queue %d unbind - failure",
850*37cd4501SBing Zhao 				cur_port, i);
851*37cd4501SBing Zhao 			return ret;
852*37cd4501SBing Zhao 		}
853*37cd4501SBing Zhao 	}
854*37cd4501SBing Zhao 	return 0;
855*37cd4501SBing Zhao }
856*37cd4501SBing Zhao 
857*37cd4501SBing Zhao /*
858*37cd4501SBing Zhao  * Bind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
859*37cd4501SBing Zhao  * @see mlx5_hairpin_bind_single_port()
860*37cd4501SBing Zhao  */
861*37cd4501SBing Zhao int
862*37cd4501SBing Zhao mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port)
863*37cd4501SBing Zhao {
864*37cd4501SBing Zhao 	int ret = 0;
865*37cd4501SBing Zhao 	uint16_t p, pp;
866*37cd4501SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
867*37cd4501SBing Zhao 
868*37cd4501SBing Zhao 	/*
869*37cd4501SBing Zhao 	 * If the Rx port has no hairpin configuration with the current port,
870*37cd4501SBing Zhao 	 * the binding will be skipped in the called function of single port.
871*37cd4501SBing Zhao 	 * Device started status will be checked only before the queue
872*37cd4501SBing Zhao 	 * information updating.
873*37cd4501SBing Zhao 	 */
874*37cd4501SBing Zhao 	if (rx_port == RTE_MAX_ETHPORTS) {
875*37cd4501SBing Zhao 		MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) {
876*37cd4501SBing Zhao 			ret = mlx5_hairpin_bind_single_port(dev, p);
877*37cd4501SBing Zhao 			if (ret != 0)
878*37cd4501SBing Zhao 				goto unbind;
879*37cd4501SBing Zhao 		}
880*37cd4501SBing Zhao 		return ret;
881*37cd4501SBing Zhao 	} else {
882*37cd4501SBing Zhao 		return mlx5_hairpin_bind_single_port(dev, rx_port);
883*37cd4501SBing Zhao 	}
884*37cd4501SBing Zhao unbind:
885*37cd4501SBing Zhao 	MLX5_ETH_FOREACH_DEV(pp, priv->pci_dev)
886*37cd4501SBing Zhao 		if (pp < p)
887*37cd4501SBing Zhao 			mlx5_hairpin_unbind_single_port(dev, pp);
888*37cd4501SBing Zhao 	return ret;
889*37cd4501SBing Zhao }
890*37cd4501SBing Zhao 
891*37cd4501SBing Zhao /*
892*37cd4501SBing Zhao  * Unbind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS.
893*37cd4501SBing Zhao  * @see mlx5_hairpin_unbind_single_port()
894*37cd4501SBing Zhao  */
895*37cd4501SBing Zhao int
896*37cd4501SBing Zhao mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port)
897*37cd4501SBing Zhao {
898*37cd4501SBing Zhao 	int ret = 0;
899*37cd4501SBing Zhao 	uint16_t p;
900*37cd4501SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
901*37cd4501SBing Zhao 
902*37cd4501SBing Zhao 	if (rx_port == RTE_MAX_ETHPORTS)
903*37cd4501SBing Zhao 		MLX5_ETH_FOREACH_DEV(p, priv->pci_dev) {
904*37cd4501SBing Zhao 			ret = mlx5_hairpin_unbind_single_port(dev, p);
905*37cd4501SBing Zhao 			if (ret != 0)
906*37cd4501SBing Zhao 				return ret;
907*37cd4501SBing Zhao 		}
908*37cd4501SBing Zhao 	else
909*37cd4501SBing Zhao 		ret = mlx5_hairpin_bind_single_port(dev, rx_port);
910*37cd4501SBing Zhao 	return ret;
911*37cd4501SBing Zhao }
912*37cd4501SBing Zhao 
9136a338ad4SOri Kam /**
914e60fbd5bSAdrien Mazarguil  * DPDK callback to start the device.
915e60fbd5bSAdrien Mazarguil  *
916e60fbd5bSAdrien Mazarguil  * Simulate device start by attaching all configured flows.
917e60fbd5bSAdrien Mazarguil  *
918e60fbd5bSAdrien Mazarguil  * @param dev
919e60fbd5bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
920e60fbd5bSAdrien Mazarguil  *
921e60fbd5bSAdrien Mazarguil  * @return
922a6d83b6aSNélio Laranjeiro  *   0 on success, a negative errno value otherwise and rte_errno is set.
923e60fbd5bSAdrien Mazarguil  */
924e60fbd5bSAdrien Mazarguil int
925e60fbd5bSAdrien Mazarguil mlx5_dev_start(struct rte_eth_dev *dev)
926e60fbd5bSAdrien Mazarguil {
92733860cfaSSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
928a6d83b6aSNélio Laranjeiro 	int ret;
929efa79e68SOri Kam 	int fine_inline;
930e60fbd5bSAdrien Mazarguil 
93124f653a7SYongseok Koh 	DRV_LOG(DEBUG, "port %u starting device", dev->data->port_id);
932efa79e68SOri Kam 	fine_inline = rte_mbuf_dynflag_lookup
933efa79e68SOri Kam 		(RTE_PMD_MLX5_FINE_GRANULARITY_INLINE, NULL);
934042540e4SThomas Monjalon 	if (fine_inline >= 0)
935efa79e68SOri Kam 		rte_net_mlx5_dynf_inline_mask = 1UL << fine_inline;
936efa79e68SOri Kam 	else
937efa79e68SOri Kam 		rte_net_mlx5_dynf_inline_mask = 0;
938606d6905SShiri Kuzin 	if (dev->data->nb_rx_queues > 0) {
93963bd1629SOri Kam 		ret = mlx5_dev_configure_rss_reta(dev);
94063bd1629SOri Kam 		if (ret) {
94163bd1629SOri Kam 			DRV_LOG(ERR, "port %u reta config failed: %s",
94263bd1629SOri Kam 				dev->data->port_id, strerror(rte_errno));
94363bd1629SOri Kam 			return -rte_errno;
94463bd1629SOri Kam 		}
945606d6905SShiri Kuzin 	}
946d133f4cdSViacheslav Ovsiienko 	ret = mlx5_txpp_start(dev);
947d133f4cdSViacheslav Ovsiienko 	if (ret) {
948d133f4cdSViacheslav Ovsiienko 		DRV_LOG(ERR, "port %u Tx packet pacing init failed: %s",
949d133f4cdSViacheslav Ovsiienko 			dev->data->port_id, strerror(rte_errno));
950d133f4cdSViacheslav Ovsiienko 		goto error;
951d133f4cdSViacheslav Ovsiienko 	}
952a6d83b6aSNélio Laranjeiro 	ret = mlx5_txq_start(dev);
953a6d83b6aSNélio Laranjeiro 	if (ret) {
954a170a30dSNélio Laranjeiro 		DRV_LOG(ERR, "port %u Tx queue allocation failed: %s",
9550f99970bSNélio Laranjeiro 			dev->data->port_id, strerror(rte_errno));
956d133f4cdSViacheslav Ovsiienko 		goto error;
9576e78005aSNélio Laranjeiro 	}
958a6d83b6aSNélio Laranjeiro 	ret = mlx5_rxq_start(dev);
959a6d83b6aSNélio Laranjeiro 	if (ret) {
960a170a30dSNélio Laranjeiro 		DRV_LOG(ERR, "port %u Rx queue allocation failed: %s",
9610f99970bSNélio Laranjeiro 			dev->data->port_id, strerror(rte_errno));
962d133f4cdSViacheslav Ovsiienko 		goto error;
963a1366b1aSNélio Laranjeiro 	}
964*37cd4501SBing Zhao 	ret = mlx5_hairpin_auto_bind(dev);
9656a338ad4SOri Kam 	if (ret) {
9666a338ad4SOri Kam 		DRV_LOG(ERR, "port %u hairpin binding failed: %s",
9676a338ad4SOri Kam 			dev->data->port_id, strerror(rte_errno));
968d133f4cdSViacheslav Ovsiienko 		goto error;
9696a338ad4SOri Kam 	}
970e7bfa359SBing Zhao 	/* Set started flag here for the following steps like control flow. */
97124f653a7SYongseok Koh 	dev->data->dev_started = 1;
972a6d83b6aSNélio Laranjeiro 	ret = mlx5_rx_intr_vec_enable(dev);
973a6d83b6aSNélio Laranjeiro 	if (ret) {
974a170a30dSNélio Laranjeiro 		DRV_LOG(ERR, "port %u Rx interrupt vector creation failed",
9750f99970bSNélio Laranjeiro 			dev->data->port_id);
976e1016cb7SAdrien Mazarguil 		goto error;
9773c7d44afSShahaf Shuler 	}
97873bf9235SOphir Munk 	mlx5_os_stats_init(dev);
9797ba5320bSNélio Laranjeiro 	ret = mlx5_traffic_enable(dev);
980a6d83b6aSNélio Laranjeiro 	if (ret) {
9818db7e3b6SBing Zhao 		DRV_LOG(ERR, "port %u failed to set defaults flows",
982e313ef4cSShahaf Shuler 			dev->data->port_id);
983e313ef4cSShahaf Shuler 		goto error;
984e313ef4cSShahaf Shuler 	}
985a2854c4dSViacheslav Ovsiienko 	/* Set a mask and offset of dynamic metadata flows into Rx queues. */
9866c55b622SAlexander Kozyrev 	mlx5_flow_rxq_dynf_metadata_set(dev);
987a2854c4dSViacheslav Ovsiienko 	/* Set flags and context to convert Rx timestamps. */
988a2854c4dSViacheslav Ovsiienko 	mlx5_rxq_timestamp_set(dev);
989a2854c4dSViacheslav Ovsiienko 	/* Set a mask and offset of scheduling on timestamp into Tx queues. */
9903172c471SViacheslav Ovsiienko 	mlx5_txq_dynf_timestamp_set(dev);
9918db7e3b6SBing Zhao 	/*
9928db7e3b6SBing Zhao 	 * In non-cached mode, it only needs to start the default mreg copy
9938db7e3b6SBing Zhao 	 * action and no flow created by application exists anymore.
9948db7e3b6SBing Zhao 	 * But it is worth wrapping the interface for further usage.
9958db7e3b6SBing Zhao 	 */
9968db7e3b6SBing Zhao 	ret = mlx5_flow_start_default(dev);
9977ba5320bSNélio Laranjeiro 	if (ret) {
9988db7e3b6SBing Zhao 		DRV_LOG(DEBUG, "port %u failed to start default actions: %s",
9998db7e3b6SBing Zhao 			dev->data->port_id, strerror(rte_errno));
10007ba5320bSNélio Laranjeiro 		goto error;
10017ba5320bSNélio Laranjeiro 	}
10022aac5b5dSYongseok Koh 	rte_wmb();
10037ba5320bSNélio Laranjeiro 	dev->tx_pkt_burst = mlx5_select_tx_function(dev);
10047ba5320bSNélio Laranjeiro 	dev->rx_pkt_burst = mlx5_select_rx_function(dev);
10052aac5b5dSYongseok Koh 	/* Enable datapath on secondary process. */
10062e86c4e5SOphir Munk 	mlx5_mp_os_req_start_rxtx(dev);
100733860cfaSSuanming Mou 	if (priv->sh->intr_handle.fd >= 0) {
100891389890SOphir Munk 		priv->sh->port[priv->dev_port - 1].ih_port_id =
100933860cfaSSuanming Mou 					(uint32_t)dev->data->port_id;
101033860cfaSSuanming Mou 	} else {
101133860cfaSSuanming Mou 		DRV_LOG(INFO, "port %u starts without LSC and RMV interrupts.",
101233860cfaSSuanming Mou 			dev->data->port_id);
101333860cfaSSuanming Mou 		dev->data->dev_conf.intr_conf.lsc = 0;
101433860cfaSSuanming Mou 		dev->data->dev_conf.intr_conf.rmv = 0;
101533860cfaSSuanming Mou 	}
101633860cfaSSuanming Mou 	if (priv->sh->intr_handle_devx.fd >= 0)
101791389890SOphir Munk 		priv->sh->port[priv->dev_port - 1].devx_ih_port_id =
101833860cfaSSuanming Mou 					(uint32_t)dev->data->port_id;
1019c8d4ee50SNélio Laranjeiro 	return 0;
1020c8d4ee50SNélio Laranjeiro error:
1021a6d83b6aSNélio Laranjeiro 	ret = rte_errno; /* Save rte_errno before cleanup. */
1022e60fbd5bSAdrien Mazarguil 	/* Rollback. */
1023272733b5SNélio Laranjeiro 	dev->data->dev_started = 0;
10248db7e3b6SBing Zhao 	mlx5_flow_stop_default(dev);
1025af4f09f2SNélio Laranjeiro 	mlx5_traffic_disable(dev);
1026af4f09f2SNélio Laranjeiro 	mlx5_txq_stop(dev);
1027af4f09f2SNélio Laranjeiro 	mlx5_rxq_stop(dev);
1028d133f4cdSViacheslav Ovsiienko 	mlx5_txpp_stop(dev); /* Stop last. */
1029a6d83b6aSNélio Laranjeiro 	rte_errno = ret; /* Restore rte_errno. */
1030a6d83b6aSNélio Laranjeiro 	return -rte_errno;
1031e60fbd5bSAdrien Mazarguil }
1032e60fbd5bSAdrien Mazarguil 
1033e60fbd5bSAdrien Mazarguil /**
1034e60fbd5bSAdrien Mazarguil  * DPDK callback to stop the device.
1035e60fbd5bSAdrien Mazarguil  *
1036e60fbd5bSAdrien Mazarguil  * Simulate device stop by detaching all configured flows.
1037e60fbd5bSAdrien Mazarguil  *
1038e60fbd5bSAdrien Mazarguil  * @param dev
1039e60fbd5bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
1040e60fbd5bSAdrien Mazarguil  */
104162024eb8SIvan Ilchenko int
1042e60fbd5bSAdrien Mazarguil mlx5_dev_stop(struct rte_eth_dev *dev)
1043e60fbd5bSAdrien Mazarguil {
1044dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
1045e60fbd5bSAdrien Mazarguil 
10463f2fe392SNélio Laranjeiro 	dev->data->dev_started = 0;
10473f2fe392SNélio Laranjeiro 	/* Prevent crashes when queues are still in use. */
10483f2fe392SNélio Laranjeiro 	dev->rx_pkt_burst = removed_rx_burst;
10493f2fe392SNélio Laranjeiro 	dev->tx_pkt_burst = removed_tx_burst;
10503f2fe392SNélio Laranjeiro 	rte_wmb();
10512aac5b5dSYongseok Koh 	/* Disable datapath on secondary process. */
10522e86c4e5SOphir Munk 	mlx5_mp_os_req_stop_rxtx(dev);
10533f2fe392SNélio Laranjeiro 	usleep(1000 * priv->rxqs_n);
105424f653a7SYongseok Koh 	DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id);
10558db7e3b6SBing Zhao 	mlx5_flow_stop_default(dev);
10568db7e3b6SBing Zhao 	/* Control flows for default traffic can be removed firstly. */
1057af4f09f2SNélio Laranjeiro 	mlx5_traffic_disable(dev);
10588db7e3b6SBing Zhao 	/* All RX queue flags will be cleared in the flush interface. */
10598db7e3b6SBing Zhao 	mlx5_flow_list_flush(dev, &priv->flows, true);
1060af4f09f2SNélio Laranjeiro 	mlx5_rx_intr_vec_disable(dev);
106191389890SOphir Munk 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
106291389890SOphir Munk 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
1063af4f09f2SNélio Laranjeiro 	mlx5_txq_stop(dev);
1064af4f09f2SNélio Laranjeiro 	mlx5_rxq_stop(dev);
1065d133f4cdSViacheslav Ovsiienko 	mlx5_txpp_stop(dev);
106662024eb8SIvan Ilchenko 
106762024eb8SIvan Ilchenko 	return 0;
1068e60fbd5bSAdrien Mazarguil }
1069272733b5SNélio Laranjeiro 
1070272733b5SNélio Laranjeiro /**
1071272733b5SNélio Laranjeiro  * Enable traffic flows configured by control plane
1072272733b5SNélio Laranjeiro  *
1073af4f09f2SNélio Laranjeiro  * @param dev
1074272733b5SNélio Laranjeiro  *   Pointer to Ethernet device private data.
1075272733b5SNélio Laranjeiro  * @param dev
1076272733b5SNélio Laranjeiro  *   Pointer to Ethernet device structure.
1077272733b5SNélio Laranjeiro  *
1078272733b5SNélio Laranjeiro  * @return
1079a6d83b6aSNélio Laranjeiro  *   0 on success, a negative errno value otherwise and rte_errno is set.
1080272733b5SNélio Laranjeiro  */
1081272733b5SNélio Laranjeiro int
1082af4f09f2SNélio Laranjeiro mlx5_traffic_enable(struct rte_eth_dev *dev)
1083272733b5SNélio Laranjeiro {
1084dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
1085272733b5SNélio Laranjeiro 	struct rte_flow_item_eth bcast = {
1086272733b5SNélio Laranjeiro 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
1087272733b5SNélio Laranjeiro 	};
1088272733b5SNélio Laranjeiro 	struct rte_flow_item_eth ipv6_multi_spec = {
1089272733b5SNélio Laranjeiro 		.dst.addr_bytes = "\x33\x33\x00\x00\x00\x00",
1090272733b5SNélio Laranjeiro 	};
1091272733b5SNélio Laranjeiro 	struct rte_flow_item_eth ipv6_multi_mask = {
1092272733b5SNélio Laranjeiro 		.dst.addr_bytes = "\xff\xff\x00\x00\x00\x00",
1093272733b5SNélio Laranjeiro 	};
1094272733b5SNélio Laranjeiro 	struct rte_flow_item_eth unicast = {
1095272733b5SNélio Laranjeiro 		.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
1096272733b5SNélio Laranjeiro 	};
1097272733b5SNélio Laranjeiro 	struct rte_flow_item_eth unicast_mask = {
1098272733b5SNélio Laranjeiro 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
1099272733b5SNélio Laranjeiro 	};
1100272733b5SNélio Laranjeiro 	const unsigned int vlan_filter_n = priv->vlan_filter_n;
11016d13ea8eSOlivier Matz 	const struct rte_ether_addr cmp = {
1102272733b5SNélio Laranjeiro 		.addr_bytes = "\x00\x00\x00\x00\x00\x00",
1103272733b5SNélio Laranjeiro 	};
1104272733b5SNélio Laranjeiro 	unsigned int i;
1105272733b5SNélio Laranjeiro 	unsigned int j;
1106272733b5SNélio Laranjeiro 	int ret;
1107272733b5SNélio Laranjeiro 
11083c84f34eSOri Kam 	/*
11093c84f34eSOri Kam 	 * Hairpin txq default flow should be created no matter if it is
11103c84f34eSOri Kam 	 * isolation mode. Or else all the packets to be sent will be sent
11113c84f34eSOri Kam 	 * out directly without the TX flow actions, e.g. encapsulation.
11123c84f34eSOri Kam 	 */
11133c84f34eSOri Kam 	for (i = 0; i != priv->txqs_n; ++i) {
11143c84f34eSOri Kam 		struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
11153c84f34eSOri Kam 		if (!txq_ctrl)
11163c84f34eSOri Kam 			continue;
11173c84f34eSOri Kam 		if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) {
11183c84f34eSOri Kam 			ret = mlx5_ctrl_flow_source_queue(dev, i);
11193c84f34eSOri Kam 			if (ret) {
11203c84f34eSOri Kam 				mlx5_txq_release(dev, i);
11213c84f34eSOri Kam 				goto error;
11223c84f34eSOri Kam 			}
11233c84f34eSOri Kam 		}
11243c84f34eSOri Kam 		mlx5_txq_release(dev, i);
11253c84f34eSOri Kam 	}
1126fbde4331SMatan Azrad 	if (priv->config.dv_esw_en && !priv->config.vf) {
1127fbde4331SMatan Azrad 		if (mlx5_flow_create_esw_table_zero_flow(dev))
1128fbde4331SMatan Azrad 			priv->fdb_def_rule = 1;
1129fbde4331SMatan Azrad 		else
1130fbde4331SMatan Azrad 			DRV_LOG(INFO, "port %u FDB default rule cannot be"
1131fbde4331SMatan Azrad 				" configured - only Eswitch group 0 flows are"
1132fbde4331SMatan Azrad 				" supported.", dev->data->port_id);
1133fbde4331SMatan Azrad 	}
11340f0ae73aSShiri Kuzin 	if (!priv->config.lacp_by_user && priv->pf_bond >= 0) {
11350f0ae73aSShiri Kuzin 		ret = mlx5_flow_lacp_miss(dev);
11360f0ae73aSShiri Kuzin 		if (ret)
11370f0ae73aSShiri Kuzin 			DRV_LOG(INFO, "port %u LACP rule cannot be created - "
11380f0ae73aSShiri Kuzin 				"forward LACP to kernel.", dev->data->port_id);
11390f0ae73aSShiri Kuzin 		else
11400f0ae73aSShiri Kuzin 			DRV_LOG(INFO, "LACP traffic will be missed in port %u."
11410f0ae73aSShiri Kuzin 				, dev->data->port_id);
11420f0ae73aSShiri Kuzin 	}
1143f8cb4b57SNélio Laranjeiro 	if (priv->isolated)
1144f8cb4b57SNélio Laranjeiro 		return 0;
1145f8cb4b57SNélio Laranjeiro 	if (dev->data->promiscuous) {
1146f8cb4b57SNélio Laranjeiro 		struct rte_flow_item_eth promisc = {
1147f8cb4b57SNélio Laranjeiro 			.dst.addr_bytes = "\x00\x00\x00\x00\x00\x00",
1148f8cb4b57SNélio Laranjeiro 			.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
1149f8cb4b57SNélio Laranjeiro 			.type = 0,
1150f8cb4b57SNélio Laranjeiro 		};
1151f8cb4b57SNélio Laranjeiro 
1152a6d83b6aSNélio Laranjeiro 		ret = mlx5_ctrl_flow(dev, &promisc, &promisc);
1153a6d83b6aSNélio Laranjeiro 		if (ret)
1154a6d83b6aSNélio Laranjeiro 			goto error;
1155f8cb4b57SNélio Laranjeiro 	}
1156f8cb4b57SNélio Laranjeiro 	if (dev->data->all_multicast) {
1157f8cb4b57SNélio Laranjeiro 		struct rte_flow_item_eth multicast = {
1158f8cb4b57SNélio Laranjeiro 			.dst.addr_bytes = "\x01\x00\x00\x00\x00\x00",
1159f8cb4b57SNélio Laranjeiro 			.src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
1160f8cb4b57SNélio Laranjeiro 			.type = 0,
1161f8cb4b57SNélio Laranjeiro 		};
1162f8cb4b57SNélio Laranjeiro 
1163a6d83b6aSNélio Laranjeiro 		ret = mlx5_ctrl_flow(dev, &multicast, &multicast);
1164a6d83b6aSNélio Laranjeiro 		if (ret)
1165a6d83b6aSNélio Laranjeiro 			goto error;
1166f8cb4b57SNélio Laranjeiro 	} else {
1167f8cb4b57SNélio Laranjeiro 		/* Add broadcast/multicast flows. */
1168f8cb4b57SNélio Laranjeiro 		for (i = 0; i != vlan_filter_n; ++i) {
1169f8cb4b57SNélio Laranjeiro 			uint16_t vlan = priv->vlan_filter[i];
1170f8cb4b57SNélio Laranjeiro 
1171f8cb4b57SNélio Laranjeiro 			struct rte_flow_item_vlan vlan_spec = {
1172f8cb4b57SNélio Laranjeiro 				.tci = rte_cpu_to_be_16(vlan),
1173f8cb4b57SNélio Laranjeiro 			};
11742bc98393SNelio Laranjeiro 			struct rte_flow_item_vlan vlan_mask =
11752bc98393SNelio Laranjeiro 				rte_flow_item_vlan_mask;
1176f8cb4b57SNélio Laranjeiro 
1177f8cb4b57SNélio Laranjeiro 			ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast,
1178f8cb4b57SNélio Laranjeiro 						  &vlan_spec, &vlan_mask);
1179f8cb4b57SNélio Laranjeiro 			if (ret)
1180f8cb4b57SNélio Laranjeiro 				goto error;
1181f8cb4b57SNélio Laranjeiro 			ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec,
1182f8cb4b57SNélio Laranjeiro 						  &ipv6_multi_mask,
1183f8cb4b57SNélio Laranjeiro 						  &vlan_spec, &vlan_mask);
1184f8cb4b57SNélio Laranjeiro 			if (ret)
1185f8cb4b57SNélio Laranjeiro 				goto error;
1186f8cb4b57SNélio Laranjeiro 		}
1187f8cb4b57SNélio Laranjeiro 		if (!vlan_filter_n) {
1188f8cb4b57SNélio Laranjeiro 			ret = mlx5_ctrl_flow(dev, &bcast, &bcast);
1189f8cb4b57SNélio Laranjeiro 			if (ret)
1190f8cb4b57SNélio Laranjeiro 				goto error;
1191f8cb4b57SNélio Laranjeiro 			ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec,
1192f8cb4b57SNélio Laranjeiro 					     &ipv6_multi_mask);
1193f8cb4b57SNélio Laranjeiro 			if (ret)
1194f8cb4b57SNélio Laranjeiro 				goto error;
1195f8cb4b57SNélio Laranjeiro 		}
1196f8cb4b57SNélio Laranjeiro 	}
1197f8cb4b57SNélio Laranjeiro 	/* Add MAC address flows. */
1198272733b5SNélio Laranjeiro 	for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) {
11996d13ea8eSOlivier Matz 		struct rte_ether_addr *mac = &dev->data->mac_addrs[i];
1200272733b5SNélio Laranjeiro 
1201272733b5SNélio Laranjeiro 		if (!memcmp(mac, &cmp, sizeof(*mac)))
1202272733b5SNélio Laranjeiro 			continue;
1203272733b5SNélio Laranjeiro 		memcpy(&unicast.dst.addr_bytes,
1204272733b5SNélio Laranjeiro 		       mac->addr_bytes,
120535b2d13fSOlivier Matz 		       RTE_ETHER_ADDR_LEN);
1206272733b5SNélio Laranjeiro 		for (j = 0; j != vlan_filter_n; ++j) {
1207272733b5SNélio Laranjeiro 			uint16_t vlan = priv->vlan_filter[j];
1208272733b5SNélio Laranjeiro 
1209272733b5SNélio Laranjeiro 			struct rte_flow_item_vlan vlan_spec = {
1210272733b5SNélio Laranjeiro 				.tci = rte_cpu_to_be_16(vlan),
1211272733b5SNélio Laranjeiro 			};
12122bc98393SNelio Laranjeiro 			struct rte_flow_item_vlan vlan_mask =
12132bc98393SNelio Laranjeiro 				rte_flow_item_vlan_mask;
1214272733b5SNélio Laranjeiro 
1215272733b5SNélio Laranjeiro 			ret = mlx5_ctrl_flow_vlan(dev, &unicast,
1216272733b5SNélio Laranjeiro 						  &unicast_mask,
1217272733b5SNélio Laranjeiro 						  &vlan_spec,
1218272733b5SNélio Laranjeiro 						  &vlan_mask);
1219272733b5SNélio Laranjeiro 			if (ret)
1220272733b5SNélio Laranjeiro 				goto error;
1221272733b5SNélio Laranjeiro 		}
1222272733b5SNélio Laranjeiro 		if (!vlan_filter_n) {
1223a6d83b6aSNélio Laranjeiro 			ret = mlx5_ctrl_flow(dev, &unicast, &unicast_mask);
1224272733b5SNélio Laranjeiro 			if (ret)
1225272733b5SNélio Laranjeiro 				goto error;
1226272733b5SNélio Laranjeiro 		}
1227272733b5SNélio Laranjeiro 	}
1228272733b5SNélio Laranjeiro 	return 0;
1229272733b5SNélio Laranjeiro error:
1230a6d83b6aSNélio Laranjeiro 	ret = rte_errno; /* Save rte_errno before cleanup. */
12318db7e3b6SBing Zhao 	mlx5_flow_list_flush(dev, &priv->ctrl_flows, false);
1232a6d83b6aSNélio Laranjeiro 	rte_errno = ret; /* Restore rte_errno. */
1233a6d83b6aSNélio Laranjeiro 	return -rte_errno;
1234272733b5SNélio Laranjeiro }
1235272733b5SNélio Laranjeiro 
1236272733b5SNélio Laranjeiro 
1237272733b5SNélio Laranjeiro /**
1238272733b5SNélio Laranjeiro  * Disable traffic flows configured by control plane
1239272733b5SNélio Laranjeiro  *
1240272733b5SNélio Laranjeiro  * @param dev
1241af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device private data.
1242272733b5SNélio Laranjeiro  */
1243925061b5SNélio Laranjeiro void
1244af4f09f2SNélio Laranjeiro mlx5_traffic_disable(struct rte_eth_dev *dev)
1245272733b5SNélio Laranjeiro {
1246dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
1247272733b5SNélio Laranjeiro 
12488db7e3b6SBing Zhao 	mlx5_flow_list_flush(dev, &priv->ctrl_flows, false);
1249272733b5SNélio Laranjeiro }
1250272733b5SNélio Laranjeiro 
1251272733b5SNélio Laranjeiro /**
1252272733b5SNélio Laranjeiro  * Restart traffic flows configured by control plane
1253272733b5SNélio Laranjeiro  *
1254272733b5SNélio Laranjeiro  * @param dev
1255af4f09f2SNélio Laranjeiro  *   Pointer to Ethernet device private data.
1256272733b5SNélio Laranjeiro  *
1257272733b5SNélio Laranjeiro  * @return
1258a6d83b6aSNélio Laranjeiro  *   0 on success, a negative errno value otherwise and rte_errno is set.
1259272733b5SNélio Laranjeiro  */
1260272733b5SNélio Laranjeiro int
1261272733b5SNélio Laranjeiro mlx5_traffic_restart(struct rte_eth_dev *dev)
1262272733b5SNélio Laranjeiro {
1263af4f09f2SNélio Laranjeiro 	if (dev->data->dev_started) {
1264af4f09f2SNélio Laranjeiro 		mlx5_traffic_disable(dev);
1265a6d83b6aSNélio Laranjeiro 		return mlx5_traffic_enable(dev);
1266af4f09f2SNélio Laranjeiro 	}
1267272733b5SNélio Laranjeiro 	return 0;
1268272733b5SNélio Laranjeiro }
1269