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> 9df96fd0dSBruce Richardson #include <ethdev_driver.h> 10198a3c33SNelio Laranjeiro #include <rte_interrupts.h> 11198a3c33SNelio Laranjeiro #include <rte_alarm.h> 1220698c9fSOphir Munk #include <rte_cycles.h> 13e60fbd5bSAdrien Mazarguil 141260a87bSMichael Baum #include <mlx5_malloc.h> 151260a87bSMichael Baum 16e60fbd5bSAdrien Mazarguil #include "mlx5.h" 17ec4e11d4SDmitry Kozlyuk #include "mlx5_flow.h" 18151cbe3aSMichael Baum #include "mlx5_rx.h" 19377b69fbSMichael Baum #include "mlx5_tx.h" 20e60fbd5bSAdrien Mazarguil #include "mlx5_utils.h" 21efa79e68SOri Kam #include "rte_pmd_mlx5.h" 22e60fbd5bSAdrien Mazarguil 23fb732b0aSNélio Laranjeiro /** 24fb732b0aSNélio Laranjeiro * Stop traffic on Tx queues. 25fb732b0aSNélio Laranjeiro * 26fb732b0aSNélio Laranjeiro * @param dev 27fb732b0aSNélio Laranjeiro * Pointer to Ethernet device structure. 28fb732b0aSNélio Laranjeiro */ 296e78005aSNélio Laranjeiro static void 30af4f09f2SNélio Laranjeiro mlx5_txq_stop(struct rte_eth_dev *dev) 316e78005aSNélio Laranjeiro { 32dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 336e78005aSNélio Laranjeiro unsigned int i; 346e78005aSNélio Laranjeiro 356e78005aSNélio Laranjeiro for (i = 0; i != priv->txqs_n; ++i) 36af4f09f2SNélio Laranjeiro mlx5_txq_release(dev, i); 376e78005aSNélio Laranjeiro } 386e78005aSNélio Laranjeiro 39fb732b0aSNélio Laranjeiro /** 40fb732b0aSNélio Laranjeiro * Start traffic on Tx queues. 41fb732b0aSNélio Laranjeiro * 42fb732b0aSNélio Laranjeiro * @param dev 43fb732b0aSNélio Laranjeiro * Pointer to Ethernet device structure. 44fb732b0aSNélio Laranjeiro * 45fb732b0aSNélio Laranjeiro * @return 46a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 47fb732b0aSNélio Laranjeiro */ 486e78005aSNélio Laranjeiro static int 49af4f09f2SNélio Laranjeiro mlx5_txq_start(struct rte_eth_dev *dev) 506e78005aSNélio Laranjeiro { 51dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 526e78005aSNélio Laranjeiro unsigned int i; 53a6d83b6aSNélio Laranjeiro int ret; 546e78005aSNélio Laranjeiro 556e78005aSNélio Laranjeiro for (i = 0; i != priv->txqs_n; ++i) { 56af4f09f2SNélio Laranjeiro struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i); 57f49f4483SMichael Baum struct mlx5_txq_data *txq_data = &txq_ctrl->txq; 58f49f4483SMichael Baum uint32_t flags = MLX5_MEM_RTE | MLX5_MEM_ZERO; 596e78005aSNélio Laranjeiro 606e78005aSNélio Laranjeiro if (!txq_ctrl) 616e78005aSNélio Laranjeiro continue; 6286d259ceSMichael Baum if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD) 636e78005aSNélio Laranjeiro txq_alloc_elts(txq_ctrl); 64f49f4483SMichael Baum MLX5_ASSERT(!txq_ctrl->obj); 65f49f4483SMichael Baum txq_ctrl->obj = mlx5_malloc(flags, sizeof(struct mlx5_txq_obj), 66f49f4483SMichael Baum 0, txq_ctrl->socket); 67894c4a8eSOri Kam if (!txq_ctrl->obj) { 68f49f4483SMichael Baum DRV_LOG(ERR, "Port %u Tx queue %u cannot allocate " 69f49f4483SMichael Baum "memory resources.", dev->data->port_id, 70f49f4483SMichael Baum txq_data->idx); 71a6d83b6aSNélio Laranjeiro rte_errno = ENOMEM; 726e78005aSNélio Laranjeiro goto error; 736e78005aSNélio Laranjeiro } 74f49f4483SMichael Baum ret = priv->obj_ops.txq_obj_new(dev, i); 75f49f4483SMichael Baum if (ret < 0) { 76f49f4483SMichael Baum mlx5_free(txq_ctrl->obj); 77f49f4483SMichael Baum txq_ctrl->obj = NULL; 78f49f4483SMichael Baum goto error; 79f49f4483SMichael Baum } 80f49f4483SMichael Baum if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD) { 81f49f4483SMichael Baum size_t size = txq_data->cqe_s * sizeof(*txq_data->fcqs); 82876b5d52SMatan Azrad 83f49f4483SMichael Baum txq_data->fcqs = mlx5_malloc(flags, size, 84f49f4483SMichael Baum RTE_CACHE_LINE_SIZE, 85f49f4483SMichael Baum txq_ctrl->socket); 86f49f4483SMichael Baum if (!txq_data->fcqs) { 87f49f4483SMichael Baum DRV_LOG(ERR, "Port %u Tx queue %u cannot " 88f49f4483SMichael Baum "allocate memory (FCQ).", 89f49f4483SMichael Baum dev->data->port_id, i); 90f49f4483SMichael Baum rte_errno = ENOMEM; 91f49f4483SMichael Baum goto error; 92f49f4483SMichael Baum } 93f49f4483SMichael Baum } 94f49f4483SMichael Baum DRV_LOG(DEBUG, "Port %u txq %u updated with %p.", 95f49f4483SMichael Baum dev->data->port_id, i, (void *)&txq_ctrl->obj); 96f49f4483SMichael Baum LIST_INSERT_HEAD(&priv->txqsobj, txq_ctrl->obj, next); 976e78005aSNélio Laranjeiro } 98a6d83b6aSNélio Laranjeiro return 0; 996e78005aSNélio Laranjeiro error: 100a6d83b6aSNélio Laranjeiro ret = rte_errno; /* Save rte_errno before cleanup. */ 10124f653a7SYongseok Koh do { 10224f653a7SYongseok Koh mlx5_txq_release(dev, i); 10324f653a7SYongseok Koh } while (i-- != 0); 104a6d83b6aSNélio Laranjeiro rte_errno = ret; /* Restore rte_errno. */ 105a6d83b6aSNélio Laranjeiro return -rte_errno; 1066e78005aSNélio Laranjeiro } 1076e78005aSNélio Laranjeiro 108fb732b0aSNélio Laranjeiro /** 109fec28ca0SDmitry Kozlyuk * Translate the chunk address to MR key in order to put in into the cache. 110fec28ca0SDmitry Kozlyuk */ 111fec28ca0SDmitry Kozlyuk static void 112fec28ca0SDmitry Kozlyuk mlx5_rxq_mempool_register_cb(struct rte_mempool *mp, void *opaque, 113fec28ca0SDmitry Kozlyuk struct rte_mempool_memhdr *memhdr, 114fec28ca0SDmitry Kozlyuk unsigned int idx) 115fec28ca0SDmitry Kozlyuk { 116fec28ca0SDmitry Kozlyuk struct mlx5_rxq_data *rxq = opaque; 117fec28ca0SDmitry Kozlyuk 118fec28ca0SDmitry Kozlyuk RTE_SET_USED(mp); 119fec28ca0SDmitry Kozlyuk RTE_SET_USED(idx); 120fec28ca0SDmitry Kozlyuk mlx5_rx_addr2mr(rxq, (uintptr_t)memhdr->addr); 121fec28ca0SDmitry Kozlyuk } 122fec28ca0SDmitry Kozlyuk 123fec28ca0SDmitry Kozlyuk /** 124fec28ca0SDmitry Kozlyuk * Register Rx queue mempools and fill the Rx queue cache. 125fec28ca0SDmitry Kozlyuk * This function tolerates repeated mempool registration. 126fec28ca0SDmitry Kozlyuk * 127fec28ca0SDmitry Kozlyuk * @param[in] rxq_ctrl 128fec28ca0SDmitry Kozlyuk * Rx queue control data. 129fec28ca0SDmitry Kozlyuk * 130fec28ca0SDmitry Kozlyuk * @return 131fec28ca0SDmitry Kozlyuk * 0 on success, (-1) on failure and rte_errno is set. 132fec28ca0SDmitry Kozlyuk */ 133fec28ca0SDmitry Kozlyuk static int 13420489176SMichael Baum mlx5_rxq_mempool_register(struct mlx5_rxq_ctrl *rxq_ctrl) 135fec28ca0SDmitry Kozlyuk { 136fec28ca0SDmitry Kozlyuk struct rte_mempool *mp; 137fec28ca0SDmitry Kozlyuk uint32_t s; 138fec28ca0SDmitry Kozlyuk int ret = 0; 139fec28ca0SDmitry Kozlyuk 140fec28ca0SDmitry Kozlyuk mlx5_mr_flush_local_cache(&rxq_ctrl->rxq.mr_ctrl); 141fec28ca0SDmitry Kozlyuk /* MPRQ mempool is registered on creation, just fill the cache. */ 142fec28ca0SDmitry Kozlyuk if (mlx5_rxq_mprq_enabled(&rxq_ctrl->rxq)) { 143fec28ca0SDmitry Kozlyuk rte_mempool_mem_iter(rxq_ctrl->rxq.mprq_mp, 144fec28ca0SDmitry Kozlyuk mlx5_rxq_mempool_register_cb, 145fec28ca0SDmitry Kozlyuk &rxq_ctrl->rxq); 146fec28ca0SDmitry Kozlyuk return 0; 147fec28ca0SDmitry Kozlyuk } 148fec28ca0SDmitry Kozlyuk for (s = 0; s < rxq_ctrl->rxq.rxseg_n; s++) { 149*7297d2cdSDmitry Kozlyuk uint32_t flags; 150*7297d2cdSDmitry Kozlyuk 151fec28ca0SDmitry Kozlyuk mp = rxq_ctrl->rxq.rxseg[s].mp; 152*7297d2cdSDmitry Kozlyuk flags = rte_pktmbuf_priv_flags(mp); 15320489176SMichael Baum ret = mlx5_mr_mempool_register(rxq_ctrl->sh->cdev, mp); 154fec28ca0SDmitry Kozlyuk if (ret < 0 && rte_errno != EEXIST) 155fec28ca0SDmitry Kozlyuk return ret; 156*7297d2cdSDmitry Kozlyuk if ((flags & RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) == 0) 157fec28ca0SDmitry Kozlyuk rte_mempool_mem_iter(mp, mlx5_rxq_mempool_register_cb, 158fec28ca0SDmitry Kozlyuk &rxq_ctrl->rxq); 159fec28ca0SDmitry Kozlyuk } 160fec28ca0SDmitry Kozlyuk return 0; 161fec28ca0SDmitry Kozlyuk } 162fec28ca0SDmitry Kozlyuk 163fec28ca0SDmitry Kozlyuk /** 164fb732b0aSNélio Laranjeiro * Stop traffic on Rx queues. 165fb732b0aSNélio Laranjeiro * 166fb732b0aSNélio Laranjeiro * @param dev 167fb732b0aSNélio Laranjeiro * Pointer to Ethernet device structure. 168fb732b0aSNélio Laranjeiro */ 169a1366b1aSNélio Laranjeiro static void 170af4f09f2SNélio Laranjeiro mlx5_rxq_stop(struct rte_eth_dev *dev) 171a1366b1aSNélio Laranjeiro { 172dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 173a1366b1aSNélio Laranjeiro unsigned int i; 174a1366b1aSNélio Laranjeiro 175a1366b1aSNélio Laranjeiro for (i = 0; i != priv->rxqs_n; ++i) 176af4f09f2SNélio Laranjeiro mlx5_rxq_release(dev, i); 177a1366b1aSNélio Laranjeiro } 178a1366b1aSNélio Laranjeiro 17909c25553SXueming Li static int 18009c25553SXueming Li mlx5_rxq_ctrl_prepare(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl, 18109c25553SXueming Li unsigned int idx) 18209c25553SXueming Li { 18309c25553SXueming Li int ret = 0; 18409c25553SXueming Li 18509c25553SXueming Li if (rxq_ctrl->type == MLX5_RXQ_TYPE_STANDARD) { 18609c25553SXueming Li /* 18709c25553SXueming Li * Pre-register the mempools. Regardless of whether 18809c25553SXueming Li * the implicit registration is enabled or not, 18909c25553SXueming Li * Rx mempool destruction is tracked to free MRs. 19009c25553SXueming Li */ 19120489176SMichael Baum if (mlx5_rxq_mempool_register(rxq_ctrl) < 0) 19209c25553SXueming Li return -rte_errno; 19309c25553SXueming Li ret = rxq_alloc_elts(rxq_ctrl); 19409c25553SXueming Li if (ret) 19509c25553SXueming Li return ret; 19609c25553SXueming Li } 19709c25553SXueming Li MLX5_ASSERT(!rxq_ctrl->obj); 19809c25553SXueming Li rxq_ctrl->obj = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, 19909c25553SXueming Li sizeof(*rxq_ctrl->obj), 0, 20009c25553SXueming Li rxq_ctrl->socket); 20109c25553SXueming Li if (!rxq_ctrl->obj) { 20209c25553SXueming Li DRV_LOG(ERR, "Port %u Rx queue %u can't allocate resources.", 20309c25553SXueming Li dev->data->port_id, idx); 20409c25553SXueming Li rte_errno = ENOMEM; 20509c25553SXueming Li return -rte_errno; 20609c25553SXueming Li } 20709c25553SXueming Li DRV_LOG(DEBUG, "Port %u rxq %u updated with %p.", dev->data->port_id, 20809c25553SXueming Li idx, (void *)&rxq_ctrl->obj); 20909c25553SXueming Li return 0; 21009c25553SXueming Li } 21109c25553SXueming Li 212fb732b0aSNélio Laranjeiro /** 213fb732b0aSNélio Laranjeiro * Start traffic on Rx queues. 214fb732b0aSNélio Laranjeiro * 215fb732b0aSNélio Laranjeiro * @param dev 216fb732b0aSNélio Laranjeiro * Pointer to Ethernet device structure. 217fb732b0aSNélio Laranjeiro * 218fb732b0aSNélio Laranjeiro * @return 219a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 220fb732b0aSNélio Laranjeiro */ 221a1366b1aSNélio Laranjeiro static int 222af4f09f2SNélio Laranjeiro mlx5_rxq_start(struct rte_eth_dev *dev) 223a1366b1aSNélio Laranjeiro { 224dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 225a1366b1aSNélio Laranjeiro unsigned int i; 226a1366b1aSNélio Laranjeiro int ret = 0; 227a1366b1aSNélio Laranjeiro 2287d6bf6b8SYongseok Koh /* Allocate/reuse/resize mempool for Multi-Packet RQ. */ 22924f653a7SYongseok Koh if (mlx5_mprq_alloc_mp(dev)) { 23024f653a7SYongseok Koh /* Should not release Rx queues but return immediately. */ 23124f653a7SYongseok Koh return -rte_errno; 23224f653a7SYongseok Koh } 2331260a87bSMichael Baum DRV_LOG(DEBUG, "Port %u device_attr.max_qp_wr is %d.", 2341260a87bSMichael Baum dev->data->port_id, priv->sh->device_attr.max_qp_wr); 2351260a87bSMichael Baum DRV_LOG(DEBUG, "Port %u device_attr.max_sge is %d.", 2361260a87bSMichael Baum dev->data->port_id, priv->sh->device_attr.max_sge); 237a1366b1aSNélio Laranjeiro for (i = 0; i != priv->rxqs_n; ++i) { 2380cedf34dSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_ref(dev, i); 2390cedf34dSXueming Li struct mlx5_rxq_ctrl *rxq_ctrl; 240a1366b1aSNélio Laranjeiro 2410cedf34dSXueming Li if (rxq == NULL) 242a1366b1aSNélio Laranjeiro continue; 2430cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 24409c25553SXueming Li if (!rxq_ctrl->started) { 24509c25553SXueming Li if (mlx5_rxq_ctrl_prepare(dev, rxq_ctrl, i) < 0) 246fec28ca0SDmitry Kozlyuk goto error; 24709c25553SXueming Li LIST_INSERT_HEAD(&priv->rxqsobj, rxq_ctrl->obj, next); 248a1366b1aSNélio Laranjeiro } 2495ceb3a02SXueming Li ret = priv->obj_ops.rxq_obj_new(rxq); 2501260a87bSMichael Baum if (ret) { 2511260a87bSMichael Baum mlx5_free(rxq_ctrl->obj); 2529ec1ceabSDmitry Kozlyuk rxq_ctrl->obj = NULL; 2531260a87bSMichael Baum goto error; 2541260a87bSMichael Baum } 25509c25553SXueming Li rxq_ctrl->started = true; 2561260a87bSMichael Baum } 257a6d83b6aSNélio Laranjeiro return 0; 258a1366b1aSNélio Laranjeiro error: 259a6d83b6aSNélio Laranjeiro ret = rte_errno; /* Save rte_errno before cleanup. */ 26024f653a7SYongseok Koh do { 26124f653a7SYongseok Koh mlx5_rxq_release(dev, i); 26224f653a7SYongseok Koh } while (i-- != 0); 263a6d83b6aSNélio Laranjeiro rte_errno = ret; /* Restore rte_errno. */ 264a6d83b6aSNélio Laranjeiro return -rte_errno; 265a1366b1aSNélio Laranjeiro } 266a1366b1aSNélio Laranjeiro 267e60fbd5bSAdrien Mazarguil /** 2686a338ad4SOri Kam * Binds Tx queues to Rx queues for hairpin. 2696a338ad4SOri Kam * 2706a338ad4SOri Kam * Binds Tx queues to the target Rx queues. 2716a338ad4SOri Kam * 2726a338ad4SOri Kam * @param dev 2736a338ad4SOri Kam * Pointer to Ethernet device structure. 2746a338ad4SOri Kam * 2756a338ad4SOri Kam * @return 2766a338ad4SOri Kam * 0 on success, a negative errno value otherwise and rte_errno is set. 2776a338ad4SOri Kam */ 2786a338ad4SOri Kam static int 27937cd4501SBing Zhao mlx5_hairpin_auto_bind(struct rte_eth_dev *dev) 2806a338ad4SOri Kam { 2816a338ad4SOri Kam struct mlx5_priv *priv = dev->data->dev_private; 2826a338ad4SOri Kam struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; 2836a338ad4SOri Kam struct mlx5_devx_modify_rq_attr rq_attr = { 0 }; 2846a338ad4SOri Kam struct mlx5_txq_ctrl *txq_ctrl; 2850cedf34dSXueming Li struct mlx5_rxq_priv *rxq; 2866a338ad4SOri Kam struct mlx5_rxq_ctrl *rxq_ctrl; 2876a338ad4SOri Kam struct mlx5_devx_obj *sq; 2886a338ad4SOri Kam struct mlx5_devx_obj *rq; 2896a338ad4SOri Kam unsigned int i; 2906a338ad4SOri Kam int ret = 0; 291aa8bea0eSBing Zhao bool need_auto = false; 292aa8bea0eSBing Zhao uint16_t self_port = dev->data->port_id; 2936a338ad4SOri Kam 2946a338ad4SOri Kam for (i = 0; i != priv->txqs_n; ++i) { 2956a338ad4SOri Kam txq_ctrl = mlx5_txq_get(dev, i); 2966a338ad4SOri Kam if (!txq_ctrl) 2976a338ad4SOri Kam continue; 29875f166c2SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN || 29975f166c2SBing Zhao txq_ctrl->hairpin_conf.peers[0].port != self_port) { 3006a338ad4SOri Kam mlx5_txq_release(dev, i); 3016a338ad4SOri Kam continue; 3026a338ad4SOri Kam } 303aa8bea0eSBing Zhao if (txq_ctrl->hairpin_conf.manual_bind) { 304aa8bea0eSBing Zhao mlx5_txq_release(dev, i); 305aa8bea0eSBing Zhao return 0; 306aa8bea0eSBing Zhao } 307aa8bea0eSBing Zhao need_auto = true; 308aa8bea0eSBing Zhao mlx5_txq_release(dev, i); 309aa8bea0eSBing Zhao } 310aa8bea0eSBing Zhao if (!need_auto) 311aa8bea0eSBing Zhao return 0; 312aa8bea0eSBing Zhao for (i = 0; i != priv->txqs_n; ++i) { 313aa8bea0eSBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 314aa8bea0eSBing Zhao if (!txq_ctrl) 315aa8bea0eSBing Zhao continue; 31675f166c2SBing Zhao /* Skip hairpin queues with other peer ports. */ 31775f166c2SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN || 31875f166c2SBing Zhao txq_ctrl->hairpin_conf.peers[0].port != self_port) { 319aa8bea0eSBing Zhao mlx5_txq_release(dev, i); 320aa8bea0eSBing Zhao continue; 321aa8bea0eSBing Zhao } 3226a338ad4SOri Kam if (!txq_ctrl->obj) { 3236a338ad4SOri Kam rte_errno = ENOMEM; 3246a338ad4SOri Kam DRV_LOG(ERR, "port %u no txq object found: %d", 3256a338ad4SOri Kam dev->data->port_id, i); 3266a338ad4SOri Kam mlx5_txq_release(dev, i); 3276a338ad4SOri Kam return -rte_errno; 3286a338ad4SOri Kam } 3296a338ad4SOri Kam sq = txq_ctrl->obj->sq; 3300cedf34dSXueming Li rxq = mlx5_rxq_get(dev, txq_ctrl->hairpin_conf.peers[0].queue); 3310cedf34dSXueming Li if (rxq == NULL) { 3326a338ad4SOri Kam mlx5_txq_release(dev, i); 3336a338ad4SOri Kam rte_errno = EINVAL; 3346a338ad4SOri Kam DRV_LOG(ERR, "port %u no rxq object found: %d", 3356a338ad4SOri Kam dev->data->port_id, 3366a338ad4SOri Kam txq_ctrl->hairpin_conf.peers[0].queue); 3376a338ad4SOri Kam return -rte_errno; 3386a338ad4SOri Kam } 3390cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 3406a338ad4SOri Kam if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN || 34144126bd9SXueming Li rxq->hairpin_conf.peers[0].queue != i) { 3426a338ad4SOri Kam rte_errno = ENOMEM; 3436a338ad4SOri Kam DRV_LOG(ERR, "port %u Tx queue %d can't be binded to " 3446a338ad4SOri Kam "Rx queue %d", dev->data->port_id, 3456a338ad4SOri Kam i, txq_ctrl->hairpin_conf.peers[0].queue); 3466a338ad4SOri Kam goto error; 3476a338ad4SOri Kam } 3486a338ad4SOri Kam rq = rxq_ctrl->obj->rq; 3496a338ad4SOri Kam if (!rq) { 3506a338ad4SOri Kam rte_errno = ENOMEM; 3516a338ad4SOri Kam DRV_LOG(ERR, "port %u hairpin no matching rxq: %d", 3526a338ad4SOri Kam dev->data->port_id, 3536a338ad4SOri Kam txq_ctrl->hairpin_conf.peers[0].queue); 3546a338ad4SOri Kam goto error; 3556a338ad4SOri Kam } 3566a338ad4SOri Kam sq_attr.state = MLX5_SQC_STATE_RDY; 3576a338ad4SOri Kam sq_attr.sq_state = MLX5_SQC_STATE_RST; 3586a338ad4SOri Kam sq_attr.hairpin_peer_rq = rq->id; 3596a338ad4SOri Kam sq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id; 3606a338ad4SOri Kam ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr); 3616a338ad4SOri Kam if (ret) 3626a338ad4SOri Kam goto error; 3636a338ad4SOri Kam rq_attr.state = MLX5_SQC_STATE_RDY; 3646a338ad4SOri Kam rq_attr.rq_state = MLX5_SQC_STATE_RST; 3656a338ad4SOri Kam rq_attr.hairpin_peer_sq = sq->id; 3666a338ad4SOri Kam rq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id; 3676a338ad4SOri Kam ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr); 3686a338ad4SOri Kam if (ret) 3696a338ad4SOri Kam goto error; 370aa8bea0eSBing Zhao /* Qs with auto-bind will be destroyed directly. */ 37144126bd9SXueming Li rxq->hairpin_status = 1; 372aa8bea0eSBing Zhao txq_ctrl->hairpin_status = 1; 3736a338ad4SOri Kam mlx5_txq_release(dev, i); 3746a338ad4SOri Kam } 3756a338ad4SOri Kam return 0; 3766a338ad4SOri Kam error: 3776a338ad4SOri Kam mlx5_txq_release(dev, i); 3786a338ad4SOri Kam return -rte_errno; 3796a338ad4SOri Kam } 3806a338ad4SOri Kam 38137cd4501SBing Zhao /* 38237cd4501SBing Zhao * Fetch the peer queue's SW & HW information. 38337cd4501SBing Zhao * 38437cd4501SBing Zhao * @param dev 38537cd4501SBing Zhao * Pointer to Ethernet device structure. 38637cd4501SBing Zhao * @param peer_queue 38737cd4501SBing Zhao * Index of the queue to fetch the information. 38837cd4501SBing Zhao * @param current_info 38937cd4501SBing Zhao * Pointer to the input peer information, not used currently. 39037cd4501SBing Zhao * @param peer_info 39137cd4501SBing Zhao * Pointer to the structure to store the information, output. 39237cd4501SBing Zhao * @param direction 39337cd4501SBing Zhao * Positive to get the RxQ information, zero to get the TxQ information. 39437cd4501SBing Zhao * 39537cd4501SBing Zhao * @return 39637cd4501SBing Zhao * 0 on success, a negative errno value otherwise and rte_errno is set. 39737cd4501SBing Zhao */ 39837cd4501SBing Zhao int 39937cd4501SBing Zhao mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue, 40037cd4501SBing Zhao struct rte_hairpin_peer_info *current_info, 40137cd4501SBing Zhao struct rte_hairpin_peer_info *peer_info, 40237cd4501SBing Zhao uint32_t direction) 40337cd4501SBing Zhao { 40437cd4501SBing Zhao struct mlx5_priv *priv = dev->data->dev_private; 40537cd4501SBing Zhao RTE_SET_USED(current_info); 40637cd4501SBing Zhao 40737cd4501SBing Zhao if (dev->data->dev_started == 0) { 40837cd4501SBing Zhao rte_errno = EBUSY; 40937cd4501SBing Zhao DRV_LOG(ERR, "peer port %u is not started", 41037cd4501SBing Zhao dev->data->port_id); 41137cd4501SBing Zhao return -rte_errno; 41237cd4501SBing Zhao } 41337cd4501SBing Zhao /* 41437cd4501SBing Zhao * Peer port used as egress. In the current design, hairpin Tx queue 41537cd4501SBing Zhao * will be bound to the peer Rx queue. Indeed, only the information of 41637cd4501SBing Zhao * peer Rx queue needs to be fetched. 41737cd4501SBing Zhao */ 41837cd4501SBing Zhao if (direction == 0) { 41937cd4501SBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 42037cd4501SBing Zhao 42137cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, peer_queue); 42237cd4501SBing Zhao if (txq_ctrl == NULL) { 42337cd4501SBing Zhao rte_errno = EINVAL; 42437cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Tx queue %d", 42537cd4501SBing Zhao dev->data->port_id, peer_queue); 42637cd4501SBing Zhao return -rte_errno; 42737cd4501SBing Zhao } 42837cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 42937cd4501SBing Zhao rte_errno = EINVAL; 43037cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d is not a hairpin Txq", 43137cd4501SBing Zhao dev->data->port_id, peer_queue); 43237cd4501SBing Zhao mlx5_txq_release(dev, peer_queue); 43337cd4501SBing Zhao return -rte_errno; 43437cd4501SBing Zhao } 43537cd4501SBing Zhao if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) { 43637cd4501SBing Zhao rte_errno = ENOMEM; 43737cd4501SBing Zhao DRV_LOG(ERR, "port %u no Txq object found: %d", 43837cd4501SBing Zhao dev->data->port_id, peer_queue); 43937cd4501SBing Zhao mlx5_txq_release(dev, peer_queue); 44037cd4501SBing Zhao return -rte_errno; 44137cd4501SBing Zhao } 44237cd4501SBing Zhao peer_info->qp_id = txq_ctrl->obj->sq->id; 44337cd4501SBing Zhao peer_info->vhca_id = priv->config.hca_attr.vhca_id; 44437cd4501SBing Zhao /* 1-to-1 mapping, only the first one is used. */ 44537cd4501SBing Zhao peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue; 44637cd4501SBing Zhao peer_info->tx_explicit = txq_ctrl->hairpin_conf.tx_explicit; 44737cd4501SBing Zhao peer_info->manual_bind = txq_ctrl->hairpin_conf.manual_bind; 44837cd4501SBing Zhao mlx5_txq_release(dev, peer_queue); 44937cd4501SBing Zhao } else { /* Peer port used as ingress. */ 4500cedf34dSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, peer_queue); 45137cd4501SBing Zhao struct mlx5_rxq_ctrl *rxq_ctrl; 45237cd4501SBing Zhao 4530cedf34dSXueming Li if (rxq == NULL) { 45437cd4501SBing Zhao rte_errno = EINVAL; 45537cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Rx queue %d", 45637cd4501SBing Zhao dev->data->port_id, peer_queue); 45737cd4501SBing Zhao return -rte_errno; 45837cd4501SBing Zhao } 4590cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 46037cd4501SBing Zhao if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { 46137cd4501SBing Zhao rte_errno = EINVAL; 46237cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d is not a hairpin Rxq", 46337cd4501SBing Zhao dev->data->port_id, peer_queue); 46437cd4501SBing Zhao return -rte_errno; 46537cd4501SBing Zhao } 46637cd4501SBing Zhao if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { 46737cd4501SBing Zhao rte_errno = ENOMEM; 46837cd4501SBing Zhao DRV_LOG(ERR, "port %u no Rxq object found: %d", 46937cd4501SBing Zhao dev->data->port_id, peer_queue); 47037cd4501SBing Zhao return -rte_errno; 47137cd4501SBing Zhao } 47237cd4501SBing Zhao peer_info->qp_id = rxq_ctrl->obj->rq->id; 47337cd4501SBing Zhao peer_info->vhca_id = priv->config.hca_attr.vhca_id; 47444126bd9SXueming Li peer_info->peer_q = rxq->hairpin_conf.peers[0].queue; 47544126bd9SXueming Li peer_info->tx_explicit = rxq->hairpin_conf.tx_explicit; 47644126bd9SXueming Li peer_info->manual_bind = rxq->hairpin_conf.manual_bind; 47737cd4501SBing Zhao } 47837cd4501SBing Zhao return 0; 47937cd4501SBing Zhao } 48037cd4501SBing Zhao 48137cd4501SBing Zhao /* 48237cd4501SBing Zhao * Bind the hairpin queue with the peer HW information. 48337cd4501SBing Zhao * This needs to be called twice both for Tx and Rx queues of a pair. 48437cd4501SBing Zhao * If the queue is already bound, it is considered successful. 48537cd4501SBing Zhao * 48637cd4501SBing Zhao * @param dev 48737cd4501SBing Zhao * Pointer to Ethernet device structure. 48837cd4501SBing Zhao * @param cur_queue 48937cd4501SBing Zhao * Index of the queue to change the HW configuration to bind. 49037cd4501SBing Zhao * @param peer_info 49137cd4501SBing Zhao * Pointer to information of the peer queue. 49237cd4501SBing Zhao * @param direction 49337cd4501SBing Zhao * Positive to configure the TxQ, zero to configure the RxQ. 49437cd4501SBing Zhao * 49537cd4501SBing Zhao * @return 49637cd4501SBing Zhao * 0 on success, a negative errno value otherwise and rte_errno is set. 49737cd4501SBing Zhao */ 49837cd4501SBing Zhao int 49937cd4501SBing Zhao mlx5_hairpin_queue_peer_bind(struct rte_eth_dev *dev, uint16_t cur_queue, 50037cd4501SBing Zhao struct rte_hairpin_peer_info *peer_info, 50137cd4501SBing Zhao uint32_t direction) 50237cd4501SBing Zhao { 50337cd4501SBing Zhao int ret = 0; 50437cd4501SBing Zhao 50537cd4501SBing Zhao /* 50637cd4501SBing Zhao * Consistency checking of the peer queue: opposite direction is used 50737cd4501SBing Zhao * to get the peer queue info with ethdev port ID, no need to check. 50837cd4501SBing Zhao */ 50937cd4501SBing Zhao if (peer_info->peer_q != cur_queue) { 51037cd4501SBing Zhao rte_errno = EINVAL; 51137cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d and peer queue %d mismatch", 51237cd4501SBing Zhao dev->data->port_id, cur_queue, peer_info->peer_q); 51337cd4501SBing Zhao return -rte_errno; 51437cd4501SBing Zhao } 51537cd4501SBing Zhao if (direction != 0) { 51637cd4501SBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 51737cd4501SBing Zhao struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; 51837cd4501SBing Zhao 51937cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, cur_queue); 52037cd4501SBing Zhao if (txq_ctrl == NULL) { 52137cd4501SBing Zhao rte_errno = EINVAL; 52237cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Tx queue %d", 52337cd4501SBing Zhao dev->data->port_id, cur_queue); 52437cd4501SBing Zhao return -rte_errno; 52537cd4501SBing Zhao } 52637cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 52737cd4501SBing Zhao rte_errno = EINVAL; 52837cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d not a hairpin Txq", 52937cd4501SBing Zhao dev->data->port_id, cur_queue); 53037cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 53137cd4501SBing Zhao return -rte_errno; 53237cd4501SBing Zhao } 53337cd4501SBing Zhao if (txq_ctrl->obj == NULL || txq_ctrl->obj->sq == NULL) { 53437cd4501SBing Zhao rte_errno = ENOMEM; 53537cd4501SBing Zhao DRV_LOG(ERR, "port %u no Txq object found: %d", 53637cd4501SBing Zhao dev->data->port_id, cur_queue); 53737cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 53837cd4501SBing Zhao return -rte_errno; 53937cd4501SBing Zhao } 54037cd4501SBing Zhao if (txq_ctrl->hairpin_status != 0) { 54137cd4501SBing Zhao DRV_LOG(DEBUG, "port %u Tx queue %d is already bound", 54237cd4501SBing Zhao dev->data->port_id, cur_queue); 54337cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 54437cd4501SBing Zhao return 0; 54537cd4501SBing Zhao } 54637cd4501SBing Zhao /* 54737cd4501SBing Zhao * All queues' of one port consistency checking is done in the 54837cd4501SBing Zhao * bind() function, and that is optional. 54937cd4501SBing Zhao */ 55037cd4501SBing Zhao if (peer_info->tx_explicit != 55137cd4501SBing Zhao txq_ctrl->hairpin_conf.tx_explicit) { 55237cd4501SBing Zhao rte_errno = EINVAL; 55337cd4501SBing Zhao DRV_LOG(ERR, "port %u Tx queue %d and peer Tx rule mode" 55437cd4501SBing Zhao " mismatch", dev->data->port_id, cur_queue); 55537cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 55637cd4501SBing Zhao return -rte_errno; 55737cd4501SBing Zhao } 55837cd4501SBing Zhao if (peer_info->manual_bind != 55937cd4501SBing Zhao txq_ctrl->hairpin_conf.manual_bind) { 56037cd4501SBing Zhao rte_errno = EINVAL; 56137cd4501SBing Zhao DRV_LOG(ERR, "port %u Tx queue %d and peer binding mode" 56237cd4501SBing Zhao " mismatch", dev->data->port_id, cur_queue); 56337cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 56437cd4501SBing Zhao return -rte_errno; 56537cd4501SBing Zhao } 56637cd4501SBing Zhao sq_attr.state = MLX5_SQC_STATE_RDY; 56737cd4501SBing Zhao sq_attr.sq_state = MLX5_SQC_STATE_RST; 56837cd4501SBing Zhao sq_attr.hairpin_peer_rq = peer_info->qp_id; 56937cd4501SBing Zhao sq_attr.hairpin_peer_vhca = peer_info->vhca_id; 57037cd4501SBing Zhao ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr); 57137cd4501SBing Zhao if (ret == 0) 57237cd4501SBing Zhao txq_ctrl->hairpin_status = 1; 57337cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 57437cd4501SBing Zhao } else { 5750cedf34dSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, cur_queue); 57637cd4501SBing Zhao struct mlx5_rxq_ctrl *rxq_ctrl; 57737cd4501SBing Zhao struct mlx5_devx_modify_rq_attr rq_attr = { 0 }; 57837cd4501SBing Zhao 5790cedf34dSXueming Li if (rxq == NULL) { 58037cd4501SBing Zhao rte_errno = EINVAL; 58137cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Rx queue %d", 58237cd4501SBing Zhao dev->data->port_id, cur_queue); 58337cd4501SBing Zhao return -rte_errno; 58437cd4501SBing Zhao } 5850cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 58637cd4501SBing Zhao if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { 58737cd4501SBing Zhao rte_errno = EINVAL; 58837cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq", 58937cd4501SBing Zhao dev->data->port_id, cur_queue); 59037cd4501SBing Zhao return -rte_errno; 59137cd4501SBing Zhao } 59237cd4501SBing Zhao if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { 59337cd4501SBing Zhao rte_errno = ENOMEM; 59437cd4501SBing Zhao DRV_LOG(ERR, "port %u no Rxq object found: %d", 59537cd4501SBing Zhao dev->data->port_id, cur_queue); 59637cd4501SBing Zhao return -rte_errno; 59737cd4501SBing Zhao } 59844126bd9SXueming Li if (rxq->hairpin_status != 0) { 59937cd4501SBing Zhao DRV_LOG(DEBUG, "port %u Rx queue %d is already bound", 60037cd4501SBing Zhao dev->data->port_id, cur_queue); 60137cd4501SBing Zhao return 0; 60237cd4501SBing Zhao } 60337cd4501SBing Zhao if (peer_info->tx_explicit != 60444126bd9SXueming Li rxq->hairpin_conf.tx_explicit) { 60537cd4501SBing Zhao rte_errno = EINVAL; 60637cd4501SBing Zhao DRV_LOG(ERR, "port %u Rx queue %d and peer Tx rule mode" 60737cd4501SBing Zhao " mismatch", dev->data->port_id, cur_queue); 60837cd4501SBing Zhao return -rte_errno; 60937cd4501SBing Zhao } 61037cd4501SBing Zhao if (peer_info->manual_bind != 61144126bd9SXueming Li rxq->hairpin_conf.manual_bind) { 61237cd4501SBing Zhao rte_errno = EINVAL; 61337cd4501SBing Zhao DRV_LOG(ERR, "port %u Rx queue %d and peer binding mode" 61437cd4501SBing Zhao " mismatch", dev->data->port_id, cur_queue); 61537cd4501SBing Zhao return -rte_errno; 61637cd4501SBing Zhao } 61737cd4501SBing Zhao rq_attr.state = MLX5_SQC_STATE_RDY; 61837cd4501SBing Zhao rq_attr.rq_state = MLX5_SQC_STATE_RST; 61937cd4501SBing Zhao rq_attr.hairpin_peer_sq = peer_info->qp_id; 62037cd4501SBing Zhao rq_attr.hairpin_peer_vhca = peer_info->vhca_id; 62137cd4501SBing Zhao ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr); 62237cd4501SBing Zhao if (ret == 0) 62344126bd9SXueming Li rxq->hairpin_status = 1; 62437cd4501SBing Zhao } 62537cd4501SBing Zhao return ret; 62637cd4501SBing Zhao } 62737cd4501SBing Zhao 62837cd4501SBing Zhao /* 62937cd4501SBing Zhao * Unbind the hairpin queue and reset its HW configuration. 63037cd4501SBing Zhao * This needs to be called twice both for Tx and Rx queues of a pair. 63137cd4501SBing Zhao * If the queue is already unbound, it is considered successful. 63237cd4501SBing Zhao * 63337cd4501SBing Zhao * @param dev 63437cd4501SBing Zhao * Pointer to Ethernet device structure. 63537cd4501SBing Zhao * @param cur_queue 63637cd4501SBing Zhao * Index of the queue to change the HW configuration to unbind. 63737cd4501SBing Zhao * @param direction 63837cd4501SBing Zhao * Positive to reset the TxQ, zero to reset the RxQ. 63937cd4501SBing Zhao * 64037cd4501SBing Zhao * @return 64137cd4501SBing Zhao * 0 on success, a negative errno value otherwise and rte_errno is set. 64237cd4501SBing Zhao */ 64337cd4501SBing Zhao int 64437cd4501SBing Zhao mlx5_hairpin_queue_peer_unbind(struct rte_eth_dev *dev, uint16_t cur_queue, 64537cd4501SBing Zhao uint32_t direction) 64637cd4501SBing Zhao { 64737cd4501SBing Zhao int ret = 0; 64837cd4501SBing Zhao 64937cd4501SBing Zhao if (direction != 0) { 65037cd4501SBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 65137cd4501SBing Zhao struct mlx5_devx_modify_sq_attr sq_attr = { 0 }; 65237cd4501SBing Zhao 65337cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, cur_queue); 65437cd4501SBing Zhao if (txq_ctrl == NULL) { 65537cd4501SBing Zhao rte_errno = EINVAL; 65637cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Tx queue %d", 65737cd4501SBing Zhao dev->data->port_id, cur_queue); 65837cd4501SBing Zhao return -rte_errno; 65937cd4501SBing Zhao } 66037cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 66137cd4501SBing Zhao rte_errno = EINVAL; 66237cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d not a hairpin Txq", 66337cd4501SBing Zhao dev->data->port_id, cur_queue); 66437cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 66537cd4501SBing Zhao return -rte_errno; 66637cd4501SBing Zhao } 66737cd4501SBing Zhao /* Already unbound, return success before obj checking. */ 66837cd4501SBing Zhao if (txq_ctrl->hairpin_status == 0) { 66937cd4501SBing Zhao DRV_LOG(DEBUG, "port %u Tx queue %d is already unbound", 67037cd4501SBing Zhao dev->data->port_id, cur_queue); 67137cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 67237cd4501SBing Zhao return 0; 67337cd4501SBing Zhao } 67437cd4501SBing Zhao if (!txq_ctrl->obj || !txq_ctrl->obj->sq) { 67537cd4501SBing Zhao rte_errno = ENOMEM; 67637cd4501SBing Zhao DRV_LOG(ERR, "port %u no Txq object found: %d", 67737cd4501SBing Zhao dev->data->port_id, cur_queue); 67837cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 67937cd4501SBing Zhao return -rte_errno; 68037cd4501SBing Zhao } 68137cd4501SBing Zhao sq_attr.state = MLX5_SQC_STATE_RST; 68237cd4501SBing Zhao sq_attr.sq_state = MLX5_SQC_STATE_RST; 68337cd4501SBing Zhao ret = mlx5_devx_cmd_modify_sq(txq_ctrl->obj->sq, &sq_attr); 68437cd4501SBing Zhao if (ret == 0) 68537cd4501SBing Zhao txq_ctrl->hairpin_status = 0; 68637cd4501SBing Zhao mlx5_txq_release(dev, cur_queue); 68737cd4501SBing Zhao } else { 6880cedf34dSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, cur_queue); 68937cd4501SBing Zhao struct mlx5_rxq_ctrl *rxq_ctrl; 69037cd4501SBing Zhao struct mlx5_devx_modify_rq_attr rq_attr = { 0 }; 69137cd4501SBing Zhao 6920cedf34dSXueming Li if (rxq == NULL) { 69337cd4501SBing Zhao rte_errno = EINVAL; 69437cd4501SBing Zhao DRV_LOG(ERR, "Failed to get port %u Rx queue %d", 69537cd4501SBing Zhao dev->data->port_id, cur_queue); 69637cd4501SBing Zhao return -rte_errno; 69737cd4501SBing Zhao } 6980cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 69937cd4501SBing Zhao if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) { 70037cd4501SBing Zhao rte_errno = EINVAL; 70137cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d not a hairpin Rxq", 70237cd4501SBing Zhao dev->data->port_id, cur_queue); 70337cd4501SBing Zhao return -rte_errno; 70437cd4501SBing Zhao } 70544126bd9SXueming Li if (rxq->hairpin_status == 0) { 70637cd4501SBing Zhao DRV_LOG(DEBUG, "port %u Rx queue %d is already unbound", 70737cd4501SBing Zhao dev->data->port_id, cur_queue); 70837cd4501SBing Zhao return 0; 70937cd4501SBing Zhao } 71037cd4501SBing Zhao if (rxq_ctrl->obj == NULL || rxq_ctrl->obj->rq == NULL) { 71137cd4501SBing Zhao rte_errno = ENOMEM; 71237cd4501SBing Zhao DRV_LOG(ERR, "port %u no Rxq object found: %d", 71337cd4501SBing Zhao dev->data->port_id, cur_queue); 71437cd4501SBing Zhao return -rte_errno; 71537cd4501SBing Zhao } 71637cd4501SBing Zhao rq_attr.state = MLX5_SQC_STATE_RST; 71737cd4501SBing Zhao rq_attr.rq_state = MLX5_SQC_STATE_RST; 71837cd4501SBing Zhao ret = mlx5_devx_cmd_modify_rq(rxq_ctrl->obj->rq, &rq_attr); 71937cd4501SBing Zhao if (ret == 0) 72044126bd9SXueming Li rxq->hairpin_status = 0; 72137cd4501SBing Zhao } 72237cd4501SBing Zhao return ret; 72337cd4501SBing Zhao } 72437cd4501SBing Zhao 72537cd4501SBing Zhao /* 72637cd4501SBing Zhao * Bind the hairpin port pairs, from the Tx to the peer Rx. 72737cd4501SBing Zhao * This function only supports to bind the Tx to one Rx. 72837cd4501SBing Zhao * 72937cd4501SBing Zhao * @param dev 73037cd4501SBing Zhao * Pointer to Ethernet device structure. 73137cd4501SBing Zhao * @param rx_port 73237cd4501SBing Zhao * Port identifier of the Rx port. 73337cd4501SBing Zhao * 73437cd4501SBing Zhao * @return 73537cd4501SBing Zhao * 0 on success, a negative errno value otherwise and rte_errno is set. 73637cd4501SBing Zhao */ 73737cd4501SBing Zhao static int 73837cd4501SBing Zhao mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port) 73937cd4501SBing Zhao { 74037cd4501SBing Zhao struct mlx5_priv *priv = dev->data->dev_private; 74137cd4501SBing Zhao int ret = 0; 74237cd4501SBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 74337cd4501SBing Zhao uint32_t i; 74437cd4501SBing Zhao struct rte_hairpin_peer_info peer = {0xffffff}; 74537cd4501SBing Zhao struct rte_hairpin_peer_info cur; 74637cd4501SBing Zhao const struct rte_eth_hairpin_conf *conf; 74737cd4501SBing Zhao uint16_t num_q = 0; 74837cd4501SBing Zhao uint16_t local_port = priv->dev_data->port_id; 74937cd4501SBing Zhao uint32_t manual; 75037cd4501SBing Zhao uint32_t explicit; 75137cd4501SBing Zhao uint16_t rx_queue; 75237cd4501SBing Zhao 75356bb3c84SXueming Li if (mlx5_eth_find_next(rx_port, dev->device) != rx_port) { 75437cd4501SBing Zhao rte_errno = ENODEV; 75537cd4501SBing Zhao DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port); 75637cd4501SBing Zhao return -rte_errno; 75737cd4501SBing Zhao } 75837cd4501SBing Zhao /* 75937cd4501SBing Zhao * Before binding TxQ to peer RxQ, first round loop will be used for 76037cd4501SBing Zhao * checking the queues' configuration consistency. This would be a 76137cd4501SBing Zhao * little time consuming but better than doing the rollback. 76237cd4501SBing Zhao */ 76337cd4501SBing Zhao for (i = 0; i != priv->txqs_n; i++) { 76437cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 76537cd4501SBing Zhao if (txq_ctrl == NULL) 76637cd4501SBing Zhao continue; 76737cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 76837cd4501SBing Zhao mlx5_txq_release(dev, i); 76937cd4501SBing Zhao continue; 77037cd4501SBing Zhao } 77137cd4501SBing Zhao /* 77237cd4501SBing Zhao * All hairpin Tx queues of a single port that connected to the 77337cd4501SBing Zhao * same peer Rx port should have the same "auto binding" and 77437cd4501SBing Zhao * "implicit Tx flow" modes. 77537cd4501SBing Zhao * Peer consistency checking will be done in per queue binding. 77637cd4501SBing Zhao */ 77737cd4501SBing Zhao conf = &txq_ctrl->hairpin_conf; 77837cd4501SBing Zhao if (conf->peers[0].port == rx_port) { 77937cd4501SBing Zhao if (num_q == 0) { 78037cd4501SBing Zhao manual = conf->manual_bind; 78137cd4501SBing Zhao explicit = conf->tx_explicit; 78237cd4501SBing Zhao } else { 78337cd4501SBing Zhao if (manual != conf->manual_bind || 78437cd4501SBing Zhao explicit != conf->tx_explicit) { 78537cd4501SBing Zhao rte_errno = EINVAL; 78637cd4501SBing Zhao DRV_LOG(ERR, "port %u queue %d mode" 78737cd4501SBing Zhao " mismatch: %u %u, %u %u", 78837cd4501SBing Zhao local_port, i, manual, 78937cd4501SBing Zhao conf->manual_bind, explicit, 79037cd4501SBing Zhao conf->tx_explicit); 79137cd4501SBing Zhao mlx5_txq_release(dev, i); 79237cd4501SBing Zhao return -rte_errno; 79337cd4501SBing Zhao } 79437cd4501SBing Zhao } 79537cd4501SBing Zhao num_q++; 79637cd4501SBing Zhao } 79737cd4501SBing Zhao mlx5_txq_release(dev, i); 79837cd4501SBing Zhao } 79937cd4501SBing Zhao /* Once no queue is configured, success is returned directly. */ 80037cd4501SBing Zhao if (num_q == 0) 80137cd4501SBing Zhao return ret; 80237cd4501SBing Zhao /* All the hairpin TX queues need to be traversed again. */ 80337cd4501SBing Zhao for (i = 0; i != priv->txqs_n; i++) { 80437cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 80537cd4501SBing Zhao if (txq_ctrl == NULL) 80637cd4501SBing Zhao continue; 80737cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 80837cd4501SBing Zhao mlx5_txq_release(dev, i); 80937cd4501SBing Zhao continue; 81037cd4501SBing Zhao } 81137cd4501SBing Zhao if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) { 81237cd4501SBing Zhao mlx5_txq_release(dev, i); 81337cd4501SBing Zhao continue; 81437cd4501SBing Zhao } 81537cd4501SBing Zhao rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; 81637cd4501SBing Zhao /* 81737cd4501SBing Zhao * Fetch peer RxQ's information. 81837cd4501SBing Zhao * No need to pass the information of the current queue. 81937cd4501SBing Zhao */ 82037cd4501SBing Zhao ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue, 82137cd4501SBing Zhao NULL, &peer, 1); 82237cd4501SBing Zhao if (ret != 0) { 82337cd4501SBing Zhao mlx5_txq_release(dev, i); 82437cd4501SBing Zhao goto error; 82537cd4501SBing Zhao } 82637cd4501SBing Zhao /* Accessing its own device, inside mlx5 PMD. */ 82737cd4501SBing Zhao ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1); 82837cd4501SBing Zhao if (ret != 0) { 82937cd4501SBing Zhao mlx5_txq_release(dev, i); 83037cd4501SBing Zhao goto error; 83137cd4501SBing Zhao } 83237cd4501SBing Zhao /* Pass TxQ's information to peer RxQ and try binding. */ 83337cd4501SBing Zhao cur.peer_q = rx_queue; 83437cd4501SBing Zhao cur.qp_id = txq_ctrl->obj->sq->id; 83537cd4501SBing Zhao cur.vhca_id = priv->config.hca_attr.vhca_id; 83637cd4501SBing Zhao cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit; 83737cd4501SBing Zhao cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind; 83837cd4501SBing Zhao /* 83937cd4501SBing Zhao * In order to access another device in a proper way, RTE level 84037cd4501SBing Zhao * private function is needed. 84137cd4501SBing Zhao */ 84237cd4501SBing Zhao ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue, 84337cd4501SBing Zhao &cur, 0); 84437cd4501SBing Zhao if (ret != 0) { 84537cd4501SBing Zhao mlx5_txq_release(dev, i); 84637cd4501SBing Zhao goto error; 84737cd4501SBing Zhao } 84837cd4501SBing Zhao mlx5_txq_release(dev, i); 84937cd4501SBing Zhao } 85037cd4501SBing Zhao return 0; 85137cd4501SBing Zhao error: 85237cd4501SBing Zhao /* 85337cd4501SBing Zhao * Do roll-back process for the queues already bound. 85437cd4501SBing Zhao * No need to check the return value of the queue unbind function. 85537cd4501SBing Zhao */ 85637cd4501SBing Zhao do { 85737cd4501SBing Zhao /* No validation is needed here. */ 85837cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 85937cd4501SBing Zhao if (txq_ctrl == NULL) 86037cd4501SBing Zhao continue; 86137cd4501SBing Zhao rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; 86237cd4501SBing Zhao rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0); 86337cd4501SBing Zhao mlx5_hairpin_queue_peer_unbind(dev, i, 1); 86437cd4501SBing Zhao mlx5_txq_release(dev, i); 86537cd4501SBing Zhao } while (i--); 86637cd4501SBing Zhao return ret; 86737cd4501SBing Zhao } 86837cd4501SBing Zhao 86937cd4501SBing Zhao /* 87037cd4501SBing Zhao * Unbind the hairpin port pair, HW configuration of both devices will be clear 87137cd4501SBing Zhao * and status will be reset for all the queues used between the them. 87237cd4501SBing Zhao * This function only supports to unbind the Tx from one Rx. 87337cd4501SBing Zhao * 87437cd4501SBing Zhao * @param dev 87537cd4501SBing Zhao * Pointer to Ethernet device structure. 87637cd4501SBing Zhao * @param rx_port 87737cd4501SBing Zhao * Port identifier of the Rx port. 87837cd4501SBing Zhao * 87937cd4501SBing Zhao * @return 88037cd4501SBing Zhao * 0 on success, a negative errno value otherwise and rte_errno is set. 88137cd4501SBing Zhao */ 88237cd4501SBing Zhao static int 88337cd4501SBing Zhao mlx5_hairpin_unbind_single_port(struct rte_eth_dev *dev, uint16_t rx_port) 88437cd4501SBing Zhao { 88537cd4501SBing Zhao struct mlx5_priv *priv = dev->data->dev_private; 88637cd4501SBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 88737cd4501SBing Zhao uint32_t i; 88837cd4501SBing Zhao int ret; 88937cd4501SBing Zhao uint16_t cur_port = priv->dev_data->port_id; 89037cd4501SBing Zhao 89156bb3c84SXueming Li if (mlx5_eth_find_next(rx_port, dev->device) != rx_port) { 89237cd4501SBing Zhao rte_errno = ENODEV; 89337cd4501SBing Zhao DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port); 89437cd4501SBing Zhao return -rte_errno; 89537cd4501SBing Zhao } 89637cd4501SBing Zhao for (i = 0; i != priv->txqs_n; i++) { 89737cd4501SBing Zhao uint16_t rx_queue; 89837cd4501SBing Zhao 89937cd4501SBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 90037cd4501SBing Zhao if (txq_ctrl == NULL) 90137cd4501SBing Zhao continue; 90237cd4501SBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 90337cd4501SBing Zhao mlx5_txq_release(dev, i); 90437cd4501SBing Zhao continue; 90537cd4501SBing Zhao } 90637cd4501SBing Zhao if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) { 90737cd4501SBing Zhao mlx5_txq_release(dev, i); 90837cd4501SBing Zhao continue; 90937cd4501SBing Zhao } 91037cd4501SBing Zhao /* Indeed, only the first used queue needs to be checked. */ 91137cd4501SBing Zhao if (txq_ctrl->hairpin_conf.manual_bind == 0) { 91237cd4501SBing Zhao if (cur_port != rx_port) { 91337cd4501SBing Zhao rte_errno = EINVAL; 91437cd4501SBing Zhao DRV_LOG(ERR, "port %u and port %u are in" 91537cd4501SBing Zhao " auto-bind mode", cur_port, rx_port); 91637cd4501SBing Zhao mlx5_txq_release(dev, i); 91737cd4501SBing Zhao return -rte_errno; 91837cd4501SBing Zhao } else { 91937cd4501SBing Zhao return 0; 92037cd4501SBing Zhao } 92137cd4501SBing Zhao } 92237cd4501SBing Zhao rx_queue = txq_ctrl->hairpin_conf.peers[0].queue; 92337cd4501SBing Zhao mlx5_txq_release(dev, i); 92437cd4501SBing Zhao ret = rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0); 92537cd4501SBing Zhao if (ret) { 92637cd4501SBing Zhao DRV_LOG(ERR, "port %u Rx queue %d unbind - failure", 92737cd4501SBing Zhao rx_port, rx_queue); 92837cd4501SBing Zhao return ret; 92937cd4501SBing Zhao } 93037cd4501SBing Zhao ret = mlx5_hairpin_queue_peer_unbind(dev, i, 1); 93137cd4501SBing Zhao if (ret) { 93237cd4501SBing Zhao DRV_LOG(ERR, "port %u Tx queue %d unbind - failure", 93337cd4501SBing Zhao cur_port, i); 93437cd4501SBing Zhao return ret; 93537cd4501SBing Zhao } 93637cd4501SBing Zhao } 93737cd4501SBing Zhao return 0; 93837cd4501SBing Zhao } 93937cd4501SBing Zhao 94037cd4501SBing Zhao /* 94137cd4501SBing Zhao * Bind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS. 94237cd4501SBing Zhao * @see mlx5_hairpin_bind_single_port() 94337cd4501SBing Zhao */ 94437cd4501SBing Zhao int 94537cd4501SBing Zhao mlx5_hairpin_bind(struct rte_eth_dev *dev, uint16_t rx_port) 94637cd4501SBing Zhao { 94737cd4501SBing Zhao int ret = 0; 94837cd4501SBing Zhao uint16_t p, pp; 94937cd4501SBing Zhao 95037cd4501SBing Zhao /* 95137cd4501SBing Zhao * If the Rx port has no hairpin configuration with the current port, 95237cd4501SBing Zhao * the binding will be skipped in the called function of single port. 95337cd4501SBing Zhao * Device started status will be checked only before the queue 95437cd4501SBing Zhao * information updating. 95537cd4501SBing Zhao */ 95637cd4501SBing Zhao if (rx_port == RTE_MAX_ETHPORTS) { 95756bb3c84SXueming Li MLX5_ETH_FOREACH_DEV(p, dev->device) { 95837cd4501SBing Zhao ret = mlx5_hairpin_bind_single_port(dev, p); 95937cd4501SBing Zhao if (ret != 0) 96037cd4501SBing Zhao goto unbind; 96137cd4501SBing Zhao } 96237cd4501SBing Zhao return ret; 96337cd4501SBing Zhao } else { 96437cd4501SBing Zhao return mlx5_hairpin_bind_single_port(dev, rx_port); 96537cd4501SBing Zhao } 96637cd4501SBing Zhao unbind: 96756bb3c84SXueming Li MLX5_ETH_FOREACH_DEV(pp, dev->device) 96837cd4501SBing Zhao if (pp < p) 96937cd4501SBing Zhao mlx5_hairpin_unbind_single_port(dev, pp); 97037cd4501SBing Zhao return ret; 97137cd4501SBing Zhao } 97237cd4501SBing Zhao 97337cd4501SBing Zhao /* 97437cd4501SBing Zhao * Unbind hairpin ports, Rx could be all ports when using RTE_MAX_ETHPORTS. 97537cd4501SBing Zhao * @see mlx5_hairpin_unbind_single_port() 97637cd4501SBing Zhao */ 97737cd4501SBing Zhao int 97837cd4501SBing Zhao mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port) 97937cd4501SBing Zhao { 98037cd4501SBing Zhao int ret = 0; 98137cd4501SBing Zhao uint16_t p; 98237cd4501SBing Zhao 98337cd4501SBing Zhao if (rx_port == RTE_MAX_ETHPORTS) 98456bb3c84SXueming Li MLX5_ETH_FOREACH_DEV(p, dev->device) { 98537cd4501SBing Zhao ret = mlx5_hairpin_unbind_single_port(dev, p); 98637cd4501SBing Zhao if (ret != 0) 98737cd4501SBing Zhao return ret; 98837cd4501SBing Zhao } 98937cd4501SBing Zhao else 9900746dcabSBing Zhao ret = mlx5_hairpin_unbind_single_port(dev, rx_port); 99137cd4501SBing Zhao return ret; 99237cd4501SBing Zhao } 99337cd4501SBing Zhao 99402109eaeSBing Zhao /* 99502109eaeSBing Zhao * DPDK callback to get the hairpin peer ports list. 99602109eaeSBing Zhao * This will return the actual number of peer ports and save the identifiers 99702109eaeSBing Zhao * into the array (sorted, may be different from that when setting up the 99802109eaeSBing Zhao * hairpin peer queues). 99902109eaeSBing Zhao * The peer port ID could be the same as the port ID of the current device. 100002109eaeSBing Zhao * 100102109eaeSBing Zhao * @param dev 100202109eaeSBing Zhao * Pointer to Ethernet device structure. 100302109eaeSBing Zhao * @param peer_ports 100402109eaeSBing Zhao * Pointer to array to save the port identifiers. 100502109eaeSBing Zhao * @param len 100602109eaeSBing Zhao * The length of the array. 100702109eaeSBing Zhao * @param direction 100802109eaeSBing Zhao * Current port to peer port direction. 100902109eaeSBing Zhao * positive - current used as Tx to get all peer Rx ports. 101002109eaeSBing Zhao * zero - current used as Rx to get all peer Tx ports. 101102109eaeSBing Zhao * 101202109eaeSBing Zhao * @return 101302109eaeSBing Zhao * 0 or positive value on success, actual number of peer ports. 101402109eaeSBing Zhao * a negative errno value otherwise and rte_errno is set. 101502109eaeSBing Zhao */ 101602109eaeSBing Zhao int 101702109eaeSBing Zhao mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports, 101802109eaeSBing Zhao size_t len, uint32_t direction) 101902109eaeSBing Zhao { 102002109eaeSBing Zhao struct mlx5_priv *priv = dev->data->dev_private; 102102109eaeSBing Zhao struct mlx5_txq_ctrl *txq_ctrl; 102202109eaeSBing Zhao uint32_t i; 102302109eaeSBing Zhao uint16_t pp; 102402109eaeSBing Zhao uint32_t bits[(RTE_MAX_ETHPORTS + 31) / 32] = {0}; 102502109eaeSBing Zhao int ret = 0; 102602109eaeSBing Zhao 102702109eaeSBing Zhao if (direction) { 102802109eaeSBing Zhao for (i = 0; i < priv->txqs_n; i++) { 102902109eaeSBing Zhao txq_ctrl = mlx5_txq_get(dev, i); 103002109eaeSBing Zhao if (!txq_ctrl) 103102109eaeSBing Zhao continue; 103202109eaeSBing Zhao if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) { 103302109eaeSBing Zhao mlx5_txq_release(dev, i); 103402109eaeSBing Zhao continue; 103502109eaeSBing Zhao } 103602109eaeSBing Zhao pp = txq_ctrl->hairpin_conf.peers[0].port; 103702109eaeSBing Zhao if (pp >= RTE_MAX_ETHPORTS) { 103802109eaeSBing Zhao rte_errno = ERANGE; 103902109eaeSBing Zhao mlx5_txq_release(dev, i); 104002109eaeSBing Zhao DRV_LOG(ERR, "port %hu queue %u peer port " 104102109eaeSBing Zhao "out of range %hu", 104202109eaeSBing Zhao priv->dev_data->port_id, i, pp); 104302109eaeSBing Zhao return -rte_errno; 104402109eaeSBing Zhao } 104502109eaeSBing Zhao bits[pp / 32] |= 1 << (pp % 32); 104602109eaeSBing Zhao mlx5_txq_release(dev, i); 104702109eaeSBing Zhao } 104802109eaeSBing Zhao } else { 104902109eaeSBing Zhao for (i = 0; i < priv->rxqs_n; i++) { 10500cedf34dSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, i); 10510cedf34dSXueming Li struct mlx5_rxq_ctrl *rxq_ctrl; 10520cedf34dSXueming Li 10530cedf34dSXueming Li if (rxq == NULL) 105402109eaeSBing Zhao continue; 10550cedf34dSXueming Li rxq_ctrl = rxq->ctrl; 10560cedf34dSXueming Li if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) 105702109eaeSBing Zhao continue; 105844126bd9SXueming Li pp = rxq->hairpin_conf.peers[0].port; 105902109eaeSBing Zhao if (pp >= RTE_MAX_ETHPORTS) { 106002109eaeSBing Zhao rte_errno = ERANGE; 106102109eaeSBing Zhao DRV_LOG(ERR, "port %hu queue %u peer port " 106202109eaeSBing Zhao "out of range %hu", 106302109eaeSBing Zhao priv->dev_data->port_id, i, pp); 106402109eaeSBing Zhao return -rte_errno; 106502109eaeSBing Zhao } 106602109eaeSBing Zhao bits[pp / 32] |= 1 << (pp % 32); 106702109eaeSBing Zhao } 106802109eaeSBing Zhao } 106902109eaeSBing Zhao for (i = 0; i < RTE_MAX_ETHPORTS; i++) { 107002109eaeSBing Zhao if (bits[i / 32] & (1 << (i % 32))) { 107102109eaeSBing Zhao if ((size_t)ret >= len) { 107202109eaeSBing Zhao rte_errno = E2BIG; 107302109eaeSBing Zhao return -rte_errno; 107402109eaeSBing Zhao } 107502109eaeSBing Zhao peer_ports[ret++] = i; 107602109eaeSBing Zhao } 107702109eaeSBing Zhao } 107802109eaeSBing Zhao return ret; 107902109eaeSBing Zhao } 108002109eaeSBing Zhao 10816a338ad4SOri Kam /** 1082e60fbd5bSAdrien Mazarguil * DPDK callback to start the device. 1083e60fbd5bSAdrien Mazarguil * 1084e60fbd5bSAdrien Mazarguil * Simulate device start by attaching all configured flows. 1085e60fbd5bSAdrien Mazarguil * 1086e60fbd5bSAdrien Mazarguil * @param dev 1087e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 1088e60fbd5bSAdrien Mazarguil * 1089e60fbd5bSAdrien Mazarguil * @return 1090a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 1091e60fbd5bSAdrien Mazarguil */ 1092e60fbd5bSAdrien Mazarguil int 1093e60fbd5bSAdrien Mazarguil mlx5_dev_start(struct rte_eth_dev *dev) 1094e60fbd5bSAdrien Mazarguil { 109533860cfaSSuanming Mou struct mlx5_priv *priv = dev->data->dev_private; 1096a6d83b6aSNélio Laranjeiro int ret; 1097efa79e68SOri Kam int fine_inline; 1098e60fbd5bSAdrien Mazarguil 109924f653a7SYongseok Koh DRV_LOG(DEBUG, "port %u starting device", dev->data->port_id); 1100efa79e68SOri Kam fine_inline = rte_mbuf_dynflag_lookup 1101efa79e68SOri Kam (RTE_PMD_MLX5_FINE_GRANULARITY_INLINE, NULL); 1102042540e4SThomas Monjalon if (fine_inline >= 0) 1103efa79e68SOri Kam rte_net_mlx5_dynf_inline_mask = 1UL << fine_inline; 1104efa79e68SOri Kam else 1105efa79e68SOri Kam rte_net_mlx5_dynf_inline_mask = 0; 1106606d6905SShiri Kuzin if (dev->data->nb_rx_queues > 0) { 110763bd1629SOri Kam ret = mlx5_dev_configure_rss_reta(dev); 110863bd1629SOri Kam if (ret) { 110963bd1629SOri Kam DRV_LOG(ERR, "port %u reta config failed: %s", 111063bd1629SOri Kam dev->data->port_id, strerror(rte_errno)); 111163bd1629SOri Kam return -rte_errno; 111263bd1629SOri Kam } 1113606d6905SShiri Kuzin } 1114d133f4cdSViacheslav Ovsiienko ret = mlx5_txpp_start(dev); 1115d133f4cdSViacheslav Ovsiienko if (ret) { 1116d133f4cdSViacheslav Ovsiienko DRV_LOG(ERR, "port %u Tx packet pacing init failed: %s", 1117d133f4cdSViacheslav Ovsiienko dev->data->port_id, strerror(rte_errno)); 1118d133f4cdSViacheslav Ovsiienko goto error; 1119d133f4cdSViacheslav Ovsiienko } 11205bc38358SMichael Baum if ((priv->sh->devx && priv->config.dv_flow_en && 112123233fd6SBing Zhao priv->config.dest_tir) && priv->obj_ops.lb_dummy_queue_create) { 112223233fd6SBing Zhao ret = priv->obj_ops.lb_dummy_queue_create(dev); 112323233fd6SBing Zhao if (ret) 112423233fd6SBing Zhao goto error; 112523233fd6SBing Zhao } 1126a6d83b6aSNélio Laranjeiro ret = mlx5_txq_start(dev); 1127a6d83b6aSNélio Laranjeiro if (ret) { 1128a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u Tx queue allocation failed: %s", 11290f99970bSNélio Laranjeiro dev->data->port_id, strerror(rte_errno)); 1130d133f4cdSViacheslav Ovsiienko goto error; 11316e78005aSNélio Laranjeiro } 1132e8482187SBing Zhao if (priv->config.std_delay_drop || priv->config.hp_delay_drop) { 1133e8482187SBing Zhao if (!priv->config.vf && !priv->config.sf && 1134e8482187SBing Zhao !priv->representor) { 1135e8482187SBing Zhao ret = mlx5_get_flag_dropless_rq(dev); 1136e8482187SBing Zhao if (ret < 0) 1137e8482187SBing Zhao DRV_LOG(WARNING, 1138e8482187SBing Zhao "port %u cannot query dropless flag", 1139e8482187SBing Zhao dev->data->port_id); 1140e8482187SBing Zhao else if (!ret) 1141e8482187SBing Zhao DRV_LOG(WARNING, 1142e8482187SBing Zhao "port %u dropless_rq OFF, no rearming", 1143e8482187SBing Zhao dev->data->port_id); 1144e8482187SBing Zhao } else { 1145e8482187SBing Zhao DRV_LOG(DEBUG, 1146e8482187SBing Zhao "port %u doesn't support dropless_rq flag", 1147e8482187SBing Zhao dev->data->port_id); 1148e8482187SBing Zhao } 1149e8482187SBing Zhao } 1150a6d83b6aSNélio Laranjeiro ret = mlx5_rxq_start(dev); 1151a6d83b6aSNélio Laranjeiro if (ret) { 1152a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u Rx queue allocation failed: %s", 11530f99970bSNélio Laranjeiro dev->data->port_id, strerror(rte_errno)); 1154d133f4cdSViacheslav Ovsiienko goto error; 1155a1366b1aSNélio Laranjeiro } 1156aa8bea0eSBing Zhao /* 1157aa8bea0eSBing Zhao * Such step will be skipped if there is no hairpin TX queue configured 1158aa8bea0eSBing Zhao * with RX peer queue from the same device. 1159aa8bea0eSBing Zhao */ 116037cd4501SBing Zhao ret = mlx5_hairpin_auto_bind(dev); 11616a338ad4SOri Kam if (ret) { 1162aa8bea0eSBing Zhao DRV_LOG(ERR, "port %u hairpin auto binding failed: %s", 11636a338ad4SOri Kam dev->data->port_id, strerror(rte_errno)); 1164d133f4cdSViacheslav Ovsiienko goto error; 11656a338ad4SOri Kam } 1166e7bfa359SBing Zhao /* Set started flag here for the following steps like control flow. */ 116724f653a7SYongseok Koh dev->data->dev_started = 1; 1168a6d83b6aSNélio Laranjeiro ret = mlx5_rx_intr_vec_enable(dev); 1169a6d83b6aSNélio Laranjeiro if (ret) { 1170a170a30dSNélio Laranjeiro DRV_LOG(ERR, "port %u Rx interrupt vector creation failed", 11710f99970bSNélio Laranjeiro dev->data->port_id); 1172e1016cb7SAdrien Mazarguil goto error; 11733c7d44afSShahaf Shuler } 117473bf9235SOphir Munk mlx5_os_stats_init(dev); 11757ba5320bSNélio Laranjeiro ret = mlx5_traffic_enable(dev); 1176a6d83b6aSNélio Laranjeiro if (ret) { 11778db7e3b6SBing Zhao DRV_LOG(ERR, "port %u failed to set defaults flows", 1178e313ef4cSShahaf Shuler dev->data->port_id); 1179e313ef4cSShahaf Shuler goto error; 1180e313ef4cSShahaf Shuler } 1181a2854c4dSViacheslav Ovsiienko /* Set a mask and offset of dynamic metadata flows into Rx queues. */ 11826c55b622SAlexander Kozyrev mlx5_flow_rxq_dynf_metadata_set(dev); 1183a2854c4dSViacheslav Ovsiienko /* Set flags and context to convert Rx timestamps. */ 1184a2854c4dSViacheslav Ovsiienko mlx5_rxq_timestamp_set(dev); 1185a2854c4dSViacheslav Ovsiienko /* Set a mask and offset of scheduling on timestamp into Tx queues. */ 11863172c471SViacheslav Ovsiienko mlx5_txq_dynf_timestamp_set(dev); 1187ec4e11d4SDmitry Kozlyuk /* Attach indirection table objects detached on port stop. */ 1188ec4e11d4SDmitry Kozlyuk ret = mlx5_action_handle_attach(dev); 1189ec4e11d4SDmitry Kozlyuk if (ret) { 1190ec4e11d4SDmitry Kozlyuk DRV_LOG(ERR, 1191ec4e11d4SDmitry Kozlyuk "port %u failed to attach indirect actions: %s", 1192ec4e11d4SDmitry Kozlyuk dev->data->port_id, rte_strerror(rte_errno)); 1193ec4e11d4SDmitry Kozlyuk goto error; 1194ec4e11d4SDmitry Kozlyuk } 11958db7e3b6SBing Zhao /* 11968db7e3b6SBing Zhao * In non-cached mode, it only needs to start the default mreg copy 11978db7e3b6SBing Zhao * action and no flow created by application exists anymore. 11988db7e3b6SBing Zhao * But it is worth wrapping the interface for further usage. 11998db7e3b6SBing Zhao */ 12008db7e3b6SBing Zhao ret = mlx5_flow_start_default(dev); 12017ba5320bSNélio Laranjeiro if (ret) { 12028db7e3b6SBing Zhao DRV_LOG(DEBUG, "port %u failed to start default actions: %s", 12038db7e3b6SBing Zhao dev->data->port_id, strerror(rte_errno)); 12047ba5320bSNélio Laranjeiro goto error; 12057ba5320bSNélio Laranjeiro } 1206fec28ca0SDmitry Kozlyuk if (mlx5_dev_ctx_shared_mempool_subscribe(dev) != 0) { 1207fec28ca0SDmitry Kozlyuk DRV_LOG(ERR, "port %u failed to subscribe for mempool life cycle: %s", 1208fec28ca0SDmitry Kozlyuk dev->data->port_id, rte_strerror(rte_errno)); 1209fec28ca0SDmitry Kozlyuk goto error; 1210fec28ca0SDmitry Kozlyuk } 12112aac5b5dSYongseok Koh rte_wmb(); 12127ba5320bSNélio Laranjeiro dev->tx_pkt_burst = mlx5_select_tx_function(dev); 12137ba5320bSNélio Laranjeiro dev->rx_pkt_burst = mlx5_select_rx_function(dev); 12142aac5b5dSYongseok Koh /* Enable datapath on secondary process. */ 12152e86c4e5SOphir Munk mlx5_mp_os_req_start_rxtx(dev); 1216d61138d4SHarman Kalra if (rte_intr_fd_get(priv->sh->intr_handle) >= 0) { 121791389890SOphir Munk priv->sh->port[priv->dev_port - 1].ih_port_id = 121833860cfaSSuanming Mou (uint32_t)dev->data->port_id; 121933860cfaSSuanming Mou } else { 122033860cfaSSuanming Mou DRV_LOG(INFO, "port %u starts without LSC and RMV interrupts.", 122133860cfaSSuanming Mou dev->data->port_id); 122233860cfaSSuanming Mou dev->data->dev_conf.intr_conf.lsc = 0; 122333860cfaSSuanming Mou dev->data->dev_conf.intr_conf.rmv = 0; 122433860cfaSSuanming Mou } 1225d61138d4SHarman Kalra if (rte_intr_fd_get(priv->sh->intr_handle_devx) >= 0) 122691389890SOphir Munk priv->sh->port[priv->dev_port - 1].devx_ih_port_id = 122733860cfaSSuanming Mou (uint32_t)dev->data->port_id; 1228c8d4ee50SNélio Laranjeiro return 0; 1229c8d4ee50SNélio Laranjeiro error: 1230a6d83b6aSNélio Laranjeiro ret = rte_errno; /* Save rte_errno before cleanup. */ 1231e60fbd5bSAdrien Mazarguil /* Rollback. */ 1232272733b5SNélio Laranjeiro dev->data->dev_started = 0; 12338db7e3b6SBing Zhao mlx5_flow_stop_default(dev); 1234af4f09f2SNélio Laranjeiro mlx5_traffic_disable(dev); 1235af4f09f2SNélio Laranjeiro mlx5_txq_stop(dev); 1236af4f09f2SNélio Laranjeiro mlx5_rxq_stop(dev); 123723233fd6SBing Zhao if (priv->obj_ops.lb_dummy_queue_release) 123823233fd6SBing Zhao priv->obj_ops.lb_dummy_queue_release(dev); 1239d133f4cdSViacheslav Ovsiienko mlx5_txpp_stop(dev); /* Stop last. */ 1240a6d83b6aSNélio Laranjeiro rte_errno = ret; /* Restore rte_errno. */ 1241a6d83b6aSNélio Laranjeiro return -rte_errno; 1242e60fbd5bSAdrien Mazarguil } 1243e60fbd5bSAdrien Mazarguil 1244e60fbd5bSAdrien Mazarguil /** 1245e60fbd5bSAdrien Mazarguil * DPDK callback to stop the device. 1246e60fbd5bSAdrien Mazarguil * 1247e60fbd5bSAdrien Mazarguil * Simulate device stop by detaching all configured flows. 1248e60fbd5bSAdrien Mazarguil * 1249e60fbd5bSAdrien Mazarguil * @param dev 1250e60fbd5bSAdrien Mazarguil * Pointer to Ethernet device structure. 1251e60fbd5bSAdrien Mazarguil */ 125262024eb8SIvan Ilchenko int 1253e60fbd5bSAdrien Mazarguil mlx5_dev_stop(struct rte_eth_dev *dev) 1254e60fbd5bSAdrien Mazarguil { 1255dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 1256e60fbd5bSAdrien Mazarguil 12573f2fe392SNélio Laranjeiro dev->data->dev_started = 0; 12583f2fe392SNélio Laranjeiro /* Prevent crashes when queues are still in use. */ 12593f2fe392SNélio Laranjeiro dev->rx_pkt_burst = removed_rx_burst; 12603f2fe392SNélio Laranjeiro dev->tx_pkt_burst = removed_tx_burst; 12613f2fe392SNélio Laranjeiro rte_wmb(); 12622aac5b5dSYongseok Koh /* Disable datapath on secondary process. */ 12632e86c4e5SOphir Munk mlx5_mp_os_req_stop_rxtx(dev); 126420698c9fSOphir Munk rte_delay_us_sleep(1000 * priv->rxqs_n); 126524f653a7SYongseok Koh DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id); 12668db7e3b6SBing Zhao mlx5_flow_stop_default(dev); 12678db7e3b6SBing Zhao /* Control flows for default traffic can be removed firstly. */ 1268af4f09f2SNélio Laranjeiro mlx5_traffic_disable(dev); 12698db7e3b6SBing Zhao /* All RX queue flags will be cleared in the flush interface. */ 1270b4edeaf3SSuanming Mou mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_GEN, true); 1271ec962badSLi Zhang mlx5_flow_meter_rxq_flush(dev); 1272ec4e11d4SDmitry Kozlyuk mlx5_action_handle_detach(dev); 1273af4f09f2SNélio Laranjeiro mlx5_rx_intr_vec_disable(dev); 127491389890SOphir Munk priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS; 127591389890SOphir Munk priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS; 1276af4f09f2SNélio Laranjeiro mlx5_txq_stop(dev); 1277af4f09f2SNélio Laranjeiro mlx5_rxq_stop(dev); 127823233fd6SBing Zhao if (priv->obj_ops.lb_dummy_queue_release) 127923233fd6SBing Zhao priv->obj_ops.lb_dummy_queue_release(dev); 1280d133f4cdSViacheslav Ovsiienko mlx5_txpp_stop(dev); 128162024eb8SIvan Ilchenko 128262024eb8SIvan Ilchenko return 0; 1283e60fbd5bSAdrien Mazarguil } 1284272733b5SNélio Laranjeiro 1285272733b5SNélio Laranjeiro /** 1286272733b5SNélio Laranjeiro * Enable traffic flows configured by control plane 1287272733b5SNélio Laranjeiro * 1288af4f09f2SNélio Laranjeiro * @param dev 1289272733b5SNélio Laranjeiro * Pointer to Ethernet device private data. 1290272733b5SNélio Laranjeiro * @param dev 1291272733b5SNélio Laranjeiro * Pointer to Ethernet device structure. 1292272733b5SNélio Laranjeiro * 1293272733b5SNélio Laranjeiro * @return 1294a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 1295272733b5SNélio Laranjeiro */ 1296272733b5SNélio Laranjeiro int 1297af4f09f2SNélio Laranjeiro mlx5_traffic_enable(struct rte_eth_dev *dev) 1298272733b5SNélio Laranjeiro { 1299dbeba4cfSThomas Monjalon struct mlx5_priv *priv = dev->data->dev_private; 1300272733b5SNélio Laranjeiro struct rte_flow_item_eth bcast = { 1301272733b5SNélio Laranjeiro .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 1302272733b5SNélio Laranjeiro }; 1303272733b5SNélio Laranjeiro struct rte_flow_item_eth ipv6_multi_spec = { 1304272733b5SNélio Laranjeiro .dst.addr_bytes = "\x33\x33\x00\x00\x00\x00", 1305272733b5SNélio Laranjeiro }; 1306272733b5SNélio Laranjeiro struct rte_flow_item_eth ipv6_multi_mask = { 1307272733b5SNélio Laranjeiro .dst.addr_bytes = "\xff\xff\x00\x00\x00\x00", 1308272733b5SNélio Laranjeiro }; 1309272733b5SNélio Laranjeiro struct rte_flow_item_eth unicast = { 1310272733b5SNélio Laranjeiro .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 1311272733b5SNélio Laranjeiro }; 1312272733b5SNélio Laranjeiro struct rte_flow_item_eth unicast_mask = { 1313272733b5SNélio Laranjeiro .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 1314272733b5SNélio Laranjeiro }; 1315272733b5SNélio Laranjeiro const unsigned int vlan_filter_n = priv->vlan_filter_n; 13166d13ea8eSOlivier Matz const struct rte_ether_addr cmp = { 1317272733b5SNélio Laranjeiro .addr_bytes = "\x00\x00\x00\x00\x00\x00", 1318272733b5SNélio Laranjeiro }; 1319272733b5SNélio Laranjeiro unsigned int i; 1320272733b5SNélio Laranjeiro unsigned int j; 1321272733b5SNélio Laranjeiro int ret; 1322272733b5SNélio Laranjeiro 13233c84f34eSOri Kam /* 13243c84f34eSOri Kam * Hairpin txq default flow should be created no matter if it is 13253c84f34eSOri Kam * isolation mode. Or else all the packets to be sent will be sent 13263c84f34eSOri Kam * out directly without the TX flow actions, e.g. encapsulation. 13273c84f34eSOri Kam */ 13283c84f34eSOri Kam for (i = 0; i != priv->txqs_n; ++i) { 13293c84f34eSOri Kam struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i); 13303c84f34eSOri Kam if (!txq_ctrl) 13313c84f34eSOri Kam continue; 1332aa8bea0eSBing Zhao /* Only Tx implicit mode requires the default Tx flow. */ 1333aa8bea0eSBing Zhao if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN && 1334aa8bea0eSBing Zhao txq_ctrl->hairpin_conf.tx_explicit == 0 && 1335aa8bea0eSBing Zhao txq_ctrl->hairpin_conf.peers[0].port == 1336aa8bea0eSBing Zhao priv->dev_data->port_id) { 13373c84f34eSOri Kam ret = mlx5_ctrl_flow_source_queue(dev, i); 13383c84f34eSOri Kam if (ret) { 13393c84f34eSOri Kam mlx5_txq_release(dev, i); 13403c84f34eSOri Kam goto error; 13413c84f34eSOri Kam } 13423c84f34eSOri Kam } 1343686d05b6SXueming Li if ((priv->representor || priv->master) && 1344686d05b6SXueming Li priv->config.dv_esw_en) { 1345686d05b6SXueming Li if (mlx5_flow_create_devx_sq_miss_flow(dev, i) == 0) { 1346686d05b6SXueming Li DRV_LOG(ERR, 1347686d05b6SXueming Li "Port %u Tx queue %u SQ create representor devx default miss rule failed.", 1348686d05b6SXueming Li dev->data->port_id, i); 1349686d05b6SXueming Li goto error; 1350686d05b6SXueming Li } 1351686d05b6SXueming Li } 13523c84f34eSOri Kam mlx5_txq_release(dev, i); 13533c84f34eSOri Kam } 1354686d05b6SXueming Li if ((priv->master || priv->representor) && priv->config.dv_esw_en) { 1355fbde4331SMatan Azrad if (mlx5_flow_create_esw_table_zero_flow(dev)) 1356fbde4331SMatan Azrad priv->fdb_def_rule = 1; 1357fbde4331SMatan Azrad else 1358fbde4331SMatan Azrad DRV_LOG(INFO, "port %u FDB default rule cannot be" 1359fbde4331SMatan Azrad " configured - only Eswitch group 0 flows are" 1360fbde4331SMatan Azrad " supported.", dev->data->port_id); 1361fbde4331SMatan Azrad } 13620f0ae73aSShiri Kuzin if (!priv->config.lacp_by_user && priv->pf_bond >= 0) { 13630f0ae73aSShiri Kuzin ret = mlx5_flow_lacp_miss(dev); 13640f0ae73aSShiri Kuzin if (ret) 13650f0ae73aSShiri Kuzin DRV_LOG(INFO, "port %u LACP rule cannot be created - " 13660f0ae73aSShiri Kuzin "forward LACP to kernel.", dev->data->port_id); 13670f0ae73aSShiri Kuzin else 13680f0ae73aSShiri Kuzin DRV_LOG(INFO, "LACP traffic will be missed in port %u." 13690f0ae73aSShiri Kuzin , dev->data->port_id); 13700f0ae73aSShiri Kuzin } 1371f8cb4b57SNélio Laranjeiro if (priv->isolated) 1372f8cb4b57SNélio Laranjeiro return 0; 1373f8cb4b57SNélio Laranjeiro if (dev->data->promiscuous) { 1374f8cb4b57SNélio Laranjeiro struct rte_flow_item_eth promisc = { 1375f8cb4b57SNélio Laranjeiro .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00", 1376f8cb4b57SNélio Laranjeiro .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 1377f8cb4b57SNélio Laranjeiro .type = 0, 1378f8cb4b57SNélio Laranjeiro }; 1379f8cb4b57SNélio Laranjeiro 1380a6d83b6aSNélio Laranjeiro ret = mlx5_ctrl_flow(dev, &promisc, &promisc); 1381a6d83b6aSNélio Laranjeiro if (ret) 1382a6d83b6aSNélio Laranjeiro goto error; 1383f8cb4b57SNélio Laranjeiro } 1384f8cb4b57SNélio Laranjeiro if (dev->data->all_multicast) { 1385f8cb4b57SNélio Laranjeiro struct rte_flow_item_eth multicast = { 1386f8cb4b57SNélio Laranjeiro .dst.addr_bytes = "\x01\x00\x00\x00\x00\x00", 1387f8cb4b57SNélio Laranjeiro .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 1388f8cb4b57SNélio Laranjeiro .type = 0, 1389f8cb4b57SNélio Laranjeiro }; 1390f8cb4b57SNélio Laranjeiro 1391a6d83b6aSNélio Laranjeiro ret = mlx5_ctrl_flow(dev, &multicast, &multicast); 1392a6d83b6aSNélio Laranjeiro if (ret) 1393a6d83b6aSNélio Laranjeiro goto error; 1394f8cb4b57SNélio Laranjeiro } else { 1395f8cb4b57SNélio Laranjeiro /* Add broadcast/multicast flows. */ 1396f8cb4b57SNélio Laranjeiro for (i = 0; i != vlan_filter_n; ++i) { 1397f8cb4b57SNélio Laranjeiro uint16_t vlan = priv->vlan_filter[i]; 1398f8cb4b57SNélio Laranjeiro 1399f8cb4b57SNélio Laranjeiro struct rte_flow_item_vlan vlan_spec = { 1400f8cb4b57SNélio Laranjeiro .tci = rte_cpu_to_be_16(vlan), 1401f8cb4b57SNélio Laranjeiro }; 14022bc98393SNelio Laranjeiro struct rte_flow_item_vlan vlan_mask = 14032bc98393SNelio Laranjeiro rte_flow_item_vlan_mask; 1404f8cb4b57SNélio Laranjeiro 1405f8cb4b57SNélio Laranjeiro ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast, 1406f8cb4b57SNélio Laranjeiro &vlan_spec, &vlan_mask); 1407f8cb4b57SNélio Laranjeiro if (ret) 1408f8cb4b57SNélio Laranjeiro goto error; 1409f8cb4b57SNélio Laranjeiro ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec, 1410f8cb4b57SNélio Laranjeiro &ipv6_multi_mask, 1411f8cb4b57SNélio Laranjeiro &vlan_spec, &vlan_mask); 1412f8cb4b57SNélio Laranjeiro if (ret) 1413f8cb4b57SNélio Laranjeiro goto error; 1414f8cb4b57SNélio Laranjeiro } 1415f8cb4b57SNélio Laranjeiro if (!vlan_filter_n) { 1416f8cb4b57SNélio Laranjeiro ret = mlx5_ctrl_flow(dev, &bcast, &bcast); 1417f8cb4b57SNélio Laranjeiro if (ret) 1418f8cb4b57SNélio Laranjeiro goto error; 1419f8cb4b57SNélio Laranjeiro ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec, 1420f8cb4b57SNélio Laranjeiro &ipv6_multi_mask); 1421084de7a1STal Shnaiderman if (ret) { 1422084de7a1STal Shnaiderman /* Do not fail on IPv6 broadcast creation failure. */ 1423084de7a1STal Shnaiderman DRV_LOG(WARNING, 1424084de7a1STal Shnaiderman "IPv6 broadcast is not supported"); 1425084de7a1STal Shnaiderman ret = 0; 1426084de7a1STal Shnaiderman } 1427f8cb4b57SNélio Laranjeiro } 1428f8cb4b57SNélio Laranjeiro } 1429f8cb4b57SNélio Laranjeiro /* Add MAC address flows. */ 1430272733b5SNélio Laranjeiro for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) { 14316d13ea8eSOlivier Matz struct rte_ether_addr *mac = &dev->data->mac_addrs[i]; 1432272733b5SNélio Laranjeiro 1433272733b5SNélio Laranjeiro if (!memcmp(mac, &cmp, sizeof(*mac))) 1434272733b5SNélio Laranjeiro continue; 1435272733b5SNélio Laranjeiro memcpy(&unicast.dst.addr_bytes, 1436272733b5SNélio Laranjeiro mac->addr_bytes, 143735b2d13fSOlivier Matz RTE_ETHER_ADDR_LEN); 1438272733b5SNélio Laranjeiro for (j = 0; j != vlan_filter_n; ++j) { 1439272733b5SNélio Laranjeiro uint16_t vlan = priv->vlan_filter[j]; 1440272733b5SNélio Laranjeiro 1441272733b5SNélio Laranjeiro struct rte_flow_item_vlan vlan_spec = { 1442272733b5SNélio Laranjeiro .tci = rte_cpu_to_be_16(vlan), 1443272733b5SNélio Laranjeiro }; 14442bc98393SNelio Laranjeiro struct rte_flow_item_vlan vlan_mask = 14452bc98393SNelio Laranjeiro rte_flow_item_vlan_mask; 1446272733b5SNélio Laranjeiro 1447272733b5SNélio Laranjeiro ret = mlx5_ctrl_flow_vlan(dev, &unicast, 1448272733b5SNélio Laranjeiro &unicast_mask, 1449272733b5SNélio Laranjeiro &vlan_spec, 1450272733b5SNélio Laranjeiro &vlan_mask); 1451272733b5SNélio Laranjeiro if (ret) 1452272733b5SNélio Laranjeiro goto error; 1453272733b5SNélio Laranjeiro } 1454272733b5SNélio Laranjeiro if (!vlan_filter_n) { 1455a6d83b6aSNélio Laranjeiro ret = mlx5_ctrl_flow(dev, &unicast, &unicast_mask); 1456272733b5SNélio Laranjeiro if (ret) 1457272733b5SNélio Laranjeiro goto error; 1458272733b5SNélio Laranjeiro } 1459272733b5SNélio Laranjeiro } 1460272733b5SNélio Laranjeiro return 0; 1461272733b5SNélio Laranjeiro error: 1462a6d83b6aSNélio Laranjeiro ret = rte_errno; /* Save rte_errno before cleanup. */ 1463b4edeaf3SSuanming Mou mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false); 1464a6d83b6aSNélio Laranjeiro rte_errno = ret; /* Restore rte_errno. */ 1465a6d83b6aSNélio Laranjeiro return -rte_errno; 1466272733b5SNélio Laranjeiro } 1467272733b5SNélio Laranjeiro 1468272733b5SNélio Laranjeiro 1469272733b5SNélio Laranjeiro /** 1470272733b5SNélio Laranjeiro * Disable traffic flows configured by control plane 1471272733b5SNélio Laranjeiro * 1472272733b5SNélio Laranjeiro * @param dev 1473af4f09f2SNélio Laranjeiro * Pointer to Ethernet device private data. 1474272733b5SNélio Laranjeiro */ 1475925061b5SNélio Laranjeiro void 1476af4f09f2SNélio Laranjeiro mlx5_traffic_disable(struct rte_eth_dev *dev) 1477272733b5SNélio Laranjeiro { 1478b4edeaf3SSuanming Mou mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false); 1479272733b5SNélio Laranjeiro } 1480272733b5SNélio Laranjeiro 1481272733b5SNélio Laranjeiro /** 1482272733b5SNélio Laranjeiro * Restart traffic flows configured by control plane 1483272733b5SNélio Laranjeiro * 1484272733b5SNélio Laranjeiro * @param dev 1485af4f09f2SNélio Laranjeiro * Pointer to Ethernet device private data. 1486272733b5SNélio Laranjeiro * 1487272733b5SNélio Laranjeiro * @return 1488a6d83b6aSNélio Laranjeiro * 0 on success, a negative errno value otherwise and rte_errno is set. 1489272733b5SNélio Laranjeiro */ 1490272733b5SNélio Laranjeiro int 1491272733b5SNélio Laranjeiro mlx5_traffic_restart(struct rte_eth_dev *dev) 1492272733b5SNélio Laranjeiro { 1493af4f09f2SNélio Laranjeiro if (dev->data->dev_started) { 1494af4f09f2SNélio Laranjeiro mlx5_traffic_disable(dev); 1495a6d83b6aSNélio Laranjeiro return mlx5_traffic_enable(dev); 1496af4f09f2SNélio Laranjeiro } 1497272733b5SNélio Laranjeiro return 0; 1498272733b5SNélio Laranjeiro } 1499