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