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