1a9643ea8Slogwang /*- 2a9643ea8Slogwang * BSD LICENSE 3a9643ea8Slogwang * 4a9643ea8Slogwang * Copyright 2015 6WIND S.A. 5a9643ea8Slogwang * Copyright 2015 Mellanox. 6a9643ea8Slogwang * 7a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without 8a9643ea8Slogwang * modification, are permitted provided that the following conditions 9a9643ea8Slogwang * are met: 10a9643ea8Slogwang * 11a9643ea8Slogwang * * Redistributions of source code must retain the above copyright 12a9643ea8Slogwang * notice, this list of conditions and the following disclaimer. 13a9643ea8Slogwang * * Redistributions in binary form must reproduce the above copyright 14a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in 15a9643ea8Slogwang * the documentation and/or other materials provided with the 16a9643ea8Slogwang * distribution. 17a9643ea8Slogwang * * Neither the name of 6WIND S.A. nor the names of its 18a9643ea8Slogwang * contributors may be used to endorse or promote products derived 19a9643ea8Slogwang * from this software without specific prior written permission. 20a9643ea8Slogwang * 21a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22a9643ea8Slogwang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23a9643ea8Slogwang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24a9643ea8Slogwang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25a9643ea8Slogwang * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26a9643ea8Slogwang * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27a9643ea8Slogwang * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28a9643ea8Slogwang * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29a9643ea8Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30a9643ea8Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31a9643ea8Slogwang * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32a9643ea8Slogwang */ 33*2bfe3f2eSlogwang #include <unistd.h> 34a9643ea8Slogwang 35a9643ea8Slogwang #include <rte_ether.h> 36a9643ea8Slogwang #include <rte_ethdev.h> 37a9643ea8Slogwang #include <rte_interrupts.h> 38a9643ea8Slogwang #include <rte_alarm.h> 39a9643ea8Slogwang 40a9643ea8Slogwang #include "mlx5.h" 41a9643ea8Slogwang #include "mlx5_rxtx.h" 42a9643ea8Slogwang #include "mlx5_utils.h" 43a9643ea8Slogwang 44*2bfe3f2eSlogwang static void 45*2bfe3f2eSlogwang priv_txq_stop(struct priv *priv) 46*2bfe3f2eSlogwang { 47*2bfe3f2eSlogwang unsigned int i; 48*2bfe3f2eSlogwang 49*2bfe3f2eSlogwang for (i = 0; i != priv->txqs_n; ++i) 50*2bfe3f2eSlogwang mlx5_priv_txq_release(priv, i); 51*2bfe3f2eSlogwang } 52*2bfe3f2eSlogwang 53*2bfe3f2eSlogwang static int 54*2bfe3f2eSlogwang priv_txq_start(struct priv *priv) 55*2bfe3f2eSlogwang { 56*2bfe3f2eSlogwang unsigned int i; 57*2bfe3f2eSlogwang int ret = 0; 58*2bfe3f2eSlogwang 59*2bfe3f2eSlogwang /* Add memory regions to Tx queues. */ 60*2bfe3f2eSlogwang for (i = 0; i != priv->txqs_n; ++i) { 61*2bfe3f2eSlogwang unsigned int idx = 0; 62*2bfe3f2eSlogwang struct mlx5_mr *mr; 63*2bfe3f2eSlogwang struct mlx5_txq_ctrl *txq_ctrl = mlx5_priv_txq_get(priv, i); 64*2bfe3f2eSlogwang 65*2bfe3f2eSlogwang if (!txq_ctrl) 66*2bfe3f2eSlogwang continue; 67*2bfe3f2eSlogwang LIST_FOREACH(mr, &priv->mr, next) { 68*2bfe3f2eSlogwang priv_txq_mp2mr_reg(priv, &txq_ctrl->txq, mr->mp, idx++); 69*2bfe3f2eSlogwang if (idx == MLX5_PMD_TX_MP_CACHE) 70*2bfe3f2eSlogwang break; 71*2bfe3f2eSlogwang } 72*2bfe3f2eSlogwang txq_alloc_elts(txq_ctrl); 73*2bfe3f2eSlogwang txq_ctrl->ibv = mlx5_priv_txq_ibv_new(priv, i); 74*2bfe3f2eSlogwang if (!txq_ctrl->ibv) { 75*2bfe3f2eSlogwang ret = ENOMEM; 76*2bfe3f2eSlogwang goto error; 77*2bfe3f2eSlogwang } 78*2bfe3f2eSlogwang } 79*2bfe3f2eSlogwang return -ret; 80*2bfe3f2eSlogwang error: 81*2bfe3f2eSlogwang priv_txq_stop(priv); 82*2bfe3f2eSlogwang return -ret; 83*2bfe3f2eSlogwang } 84*2bfe3f2eSlogwang 85*2bfe3f2eSlogwang static void 86*2bfe3f2eSlogwang priv_rxq_stop(struct priv *priv) 87*2bfe3f2eSlogwang { 88*2bfe3f2eSlogwang unsigned int i; 89*2bfe3f2eSlogwang 90*2bfe3f2eSlogwang for (i = 0; i != priv->rxqs_n; ++i) 91*2bfe3f2eSlogwang mlx5_priv_rxq_release(priv, i); 92*2bfe3f2eSlogwang } 93*2bfe3f2eSlogwang 94*2bfe3f2eSlogwang static int 95*2bfe3f2eSlogwang priv_rxq_start(struct priv *priv) 96*2bfe3f2eSlogwang { 97*2bfe3f2eSlogwang unsigned int i; 98*2bfe3f2eSlogwang int ret = 0; 99*2bfe3f2eSlogwang 100*2bfe3f2eSlogwang for (i = 0; i != priv->rxqs_n; ++i) { 101*2bfe3f2eSlogwang struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_priv_rxq_get(priv, i); 102*2bfe3f2eSlogwang 103*2bfe3f2eSlogwang if (!rxq_ctrl) 104*2bfe3f2eSlogwang continue; 105*2bfe3f2eSlogwang ret = rxq_alloc_elts(rxq_ctrl); 106*2bfe3f2eSlogwang if (ret) 107*2bfe3f2eSlogwang goto error; 108*2bfe3f2eSlogwang rxq_ctrl->ibv = mlx5_priv_rxq_ibv_new(priv, i); 109*2bfe3f2eSlogwang if (!rxq_ctrl->ibv) { 110*2bfe3f2eSlogwang ret = ENOMEM; 111*2bfe3f2eSlogwang goto error; 112*2bfe3f2eSlogwang } 113*2bfe3f2eSlogwang } 114*2bfe3f2eSlogwang return -ret; 115*2bfe3f2eSlogwang error: 116*2bfe3f2eSlogwang priv_rxq_stop(priv); 117*2bfe3f2eSlogwang return -ret; 118*2bfe3f2eSlogwang } 119*2bfe3f2eSlogwang 120a9643ea8Slogwang /** 121a9643ea8Slogwang * DPDK callback to start the device. 122a9643ea8Slogwang * 123a9643ea8Slogwang * Simulate device start by attaching all configured flows. 124a9643ea8Slogwang * 125a9643ea8Slogwang * @param dev 126a9643ea8Slogwang * Pointer to Ethernet device structure. 127a9643ea8Slogwang * 128a9643ea8Slogwang * @return 129a9643ea8Slogwang * 0 on success, negative errno value on failure. 130a9643ea8Slogwang */ 131a9643ea8Slogwang int 132a9643ea8Slogwang mlx5_dev_start(struct rte_eth_dev *dev) 133a9643ea8Slogwang { 134a9643ea8Slogwang struct priv *priv = dev->data->dev_private; 135*2bfe3f2eSlogwang struct mlx5_mr *mr = NULL; 136a9643ea8Slogwang int err; 137a9643ea8Slogwang 138*2bfe3f2eSlogwang dev->data->dev_started = 1; 139a9643ea8Slogwang priv_lock(priv); 140*2bfe3f2eSlogwang err = priv_flow_create_drop_queue(priv); 141*2bfe3f2eSlogwang if (err) { 142*2bfe3f2eSlogwang ERROR("%p: Drop queue allocation failed: %s", 143*2bfe3f2eSlogwang (void *)dev, strerror(err)); 144*2bfe3f2eSlogwang goto error; 145a9643ea8Slogwang } 146a9643ea8Slogwang DEBUG("%p: allocating and configuring hash RX queues", (void *)dev); 147*2bfe3f2eSlogwang rte_mempool_walk(mlx5_mp2mr_iter, priv); 148*2bfe3f2eSlogwang err = priv_txq_start(priv); 149*2bfe3f2eSlogwang if (err) { 150*2bfe3f2eSlogwang ERROR("%p: TXQ allocation failed: %s", 151*2bfe3f2eSlogwang (void *)dev, strerror(err)); 152*2bfe3f2eSlogwang goto error; 153a9643ea8Slogwang } 154*2bfe3f2eSlogwang err = priv_rxq_start(priv); 155*2bfe3f2eSlogwang if (err) { 156*2bfe3f2eSlogwang ERROR("%p: RXQ allocation failed: %s", 157*2bfe3f2eSlogwang (void *)dev, strerror(err)); 158*2bfe3f2eSlogwang goto error; 159*2bfe3f2eSlogwang } 160*2bfe3f2eSlogwang err = priv_rx_intr_vec_enable(priv); 161*2bfe3f2eSlogwang if (err) { 162*2bfe3f2eSlogwang ERROR("%p: RX interrupt vector creation failed", 163*2bfe3f2eSlogwang (void *)priv); 164*2bfe3f2eSlogwang goto error; 165*2bfe3f2eSlogwang } 166*2bfe3f2eSlogwang priv_xstats_init(priv); 167*2bfe3f2eSlogwang /* Update link status and Tx/Rx callbacks for the first time. */ 168*2bfe3f2eSlogwang memset(&dev->data->dev_link, 0, sizeof(struct rte_eth_link)); 169*2bfe3f2eSlogwang INFO("Forcing port %u link to be up", dev->data->port_id); 170*2bfe3f2eSlogwang err = priv_force_link_status_change(priv, ETH_LINK_UP); 171*2bfe3f2eSlogwang if (err) { 172*2bfe3f2eSlogwang DEBUG("Failed to set port %u link to be up", 173*2bfe3f2eSlogwang dev->data->port_id); 174*2bfe3f2eSlogwang goto error; 175*2bfe3f2eSlogwang } 176a9643ea8Slogwang priv_dev_interrupt_handler_install(priv, dev); 177a9643ea8Slogwang priv_unlock(priv); 178*2bfe3f2eSlogwang return 0; 179*2bfe3f2eSlogwang error: 180*2bfe3f2eSlogwang /* Rollback. */ 181*2bfe3f2eSlogwang dev->data->dev_started = 0; 182*2bfe3f2eSlogwang for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) 183*2bfe3f2eSlogwang priv_mr_release(priv, mr); 184*2bfe3f2eSlogwang priv_flow_stop(priv, &priv->flows); 185*2bfe3f2eSlogwang priv_dev_traffic_disable(priv, dev); 186*2bfe3f2eSlogwang priv_txq_stop(priv); 187*2bfe3f2eSlogwang priv_rxq_stop(priv); 188*2bfe3f2eSlogwang priv_flow_delete_drop_queue(priv); 189*2bfe3f2eSlogwang priv_unlock(priv); 190*2bfe3f2eSlogwang return err; 191a9643ea8Slogwang } 192a9643ea8Slogwang 193a9643ea8Slogwang /** 194a9643ea8Slogwang * DPDK callback to stop the device. 195a9643ea8Slogwang * 196a9643ea8Slogwang * Simulate device stop by detaching all configured flows. 197a9643ea8Slogwang * 198a9643ea8Slogwang * @param dev 199a9643ea8Slogwang * Pointer to Ethernet device structure. 200a9643ea8Slogwang */ 201a9643ea8Slogwang void 202a9643ea8Slogwang mlx5_dev_stop(struct rte_eth_dev *dev) 203a9643ea8Slogwang { 204a9643ea8Slogwang struct priv *priv = dev->data->dev_private; 205*2bfe3f2eSlogwang struct mlx5_mr *mr; 206a9643ea8Slogwang 207a9643ea8Slogwang priv_lock(priv); 208*2bfe3f2eSlogwang dev->data->dev_started = 0; 209*2bfe3f2eSlogwang /* Prevent crashes when queues are still in use. */ 210*2bfe3f2eSlogwang dev->rx_pkt_burst = removed_rx_burst; 211*2bfe3f2eSlogwang dev->tx_pkt_burst = removed_tx_burst; 212*2bfe3f2eSlogwang rte_wmb(); 213*2bfe3f2eSlogwang usleep(1000 * priv->rxqs_n); 214a9643ea8Slogwang DEBUG("%p: cleaning up and destroying hash RX queues", (void *)dev); 215*2bfe3f2eSlogwang priv_flow_stop(priv, &priv->flows); 216*2bfe3f2eSlogwang priv_dev_traffic_disable(priv, dev); 217*2bfe3f2eSlogwang priv_rx_intr_vec_disable(priv); 218a9643ea8Slogwang priv_dev_interrupt_handler_uninstall(priv, dev); 219*2bfe3f2eSlogwang priv_txq_stop(priv); 220*2bfe3f2eSlogwang priv_rxq_stop(priv); 221*2bfe3f2eSlogwang for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) 222*2bfe3f2eSlogwang priv_mr_release(priv, mr); 223*2bfe3f2eSlogwang priv_flow_delete_drop_queue(priv); 224a9643ea8Slogwang priv_unlock(priv); 225a9643ea8Slogwang } 226*2bfe3f2eSlogwang 227*2bfe3f2eSlogwang /** 228*2bfe3f2eSlogwang * Enable traffic flows configured by control plane 229*2bfe3f2eSlogwang * 230*2bfe3f2eSlogwang * @param priv 231*2bfe3f2eSlogwang * Pointer to Ethernet device private data. 232*2bfe3f2eSlogwang * @param dev 233*2bfe3f2eSlogwang * Pointer to Ethernet device structure. 234*2bfe3f2eSlogwang * 235*2bfe3f2eSlogwang * @return 236*2bfe3f2eSlogwang * 0 on success. 237*2bfe3f2eSlogwang */ 238*2bfe3f2eSlogwang int 239*2bfe3f2eSlogwang priv_dev_traffic_enable(struct priv *priv, struct rte_eth_dev *dev) 240*2bfe3f2eSlogwang { 241*2bfe3f2eSlogwang struct rte_flow_item_eth bcast = { 242*2bfe3f2eSlogwang .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 243*2bfe3f2eSlogwang }; 244*2bfe3f2eSlogwang struct rte_flow_item_eth ipv6_multi_spec = { 245*2bfe3f2eSlogwang .dst.addr_bytes = "\x33\x33\x00\x00\x00\x00", 246*2bfe3f2eSlogwang }; 247*2bfe3f2eSlogwang struct rte_flow_item_eth ipv6_multi_mask = { 248*2bfe3f2eSlogwang .dst.addr_bytes = "\xff\xff\x00\x00\x00\x00", 249*2bfe3f2eSlogwang }; 250*2bfe3f2eSlogwang struct rte_flow_item_eth unicast = { 251*2bfe3f2eSlogwang .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 252*2bfe3f2eSlogwang }; 253*2bfe3f2eSlogwang struct rte_flow_item_eth unicast_mask = { 254*2bfe3f2eSlogwang .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 255*2bfe3f2eSlogwang }; 256*2bfe3f2eSlogwang const unsigned int vlan_filter_n = priv->vlan_filter_n; 257*2bfe3f2eSlogwang const struct ether_addr cmp = { 258*2bfe3f2eSlogwang .addr_bytes = "\x00\x00\x00\x00\x00\x00", 259*2bfe3f2eSlogwang }; 260*2bfe3f2eSlogwang unsigned int i; 261*2bfe3f2eSlogwang unsigned int j; 262*2bfe3f2eSlogwang int ret; 263*2bfe3f2eSlogwang 264*2bfe3f2eSlogwang if (priv->isolated) 265*2bfe3f2eSlogwang return 0; 266*2bfe3f2eSlogwang if (dev->data->promiscuous) { 267*2bfe3f2eSlogwang struct rte_flow_item_eth promisc = { 268*2bfe3f2eSlogwang .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00", 269*2bfe3f2eSlogwang .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 270*2bfe3f2eSlogwang .type = 0, 271*2bfe3f2eSlogwang }; 272*2bfe3f2eSlogwang 273*2bfe3f2eSlogwang claim_zero(mlx5_ctrl_flow(dev, &promisc, &promisc)); 274*2bfe3f2eSlogwang return 0; 275*2bfe3f2eSlogwang } 276*2bfe3f2eSlogwang if (dev->data->all_multicast) { 277*2bfe3f2eSlogwang struct rte_flow_item_eth multicast = { 278*2bfe3f2eSlogwang .dst.addr_bytes = "\x01\x00\x00\x00\x00\x00", 279*2bfe3f2eSlogwang .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 280*2bfe3f2eSlogwang .type = 0, 281*2bfe3f2eSlogwang }; 282*2bfe3f2eSlogwang 283*2bfe3f2eSlogwang claim_zero(mlx5_ctrl_flow(dev, &multicast, &multicast)); 284*2bfe3f2eSlogwang } else { 285*2bfe3f2eSlogwang /* Add broadcast/multicast flows. */ 286*2bfe3f2eSlogwang for (i = 0; i != vlan_filter_n; ++i) { 287*2bfe3f2eSlogwang uint16_t vlan = priv->vlan_filter[i]; 288*2bfe3f2eSlogwang 289*2bfe3f2eSlogwang struct rte_flow_item_vlan vlan_spec = { 290*2bfe3f2eSlogwang .tci = rte_cpu_to_be_16(vlan), 291*2bfe3f2eSlogwang }; 292*2bfe3f2eSlogwang struct rte_flow_item_vlan vlan_mask = { 293*2bfe3f2eSlogwang .tci = 0xffff, 294*2bfe3f2eSlogwang }; 295*2bfe3f2eSlogwang 296*2bfe3f2eSlogwang ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast, 297*2bfe3f2eSlogwang &vlan_spec, &vlan_mask); 298*2bfe3f2eSlogwang if (ret) 299*2bfe3f2eSlogwang goto error; 300*2bfe3f2eSlogwang ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec, 301*2bfe3f2eSlogwang &ipv6_multi_mask, 302*2bfe3f2eSlogwang &vlan_spec, &vlan_mask); 303*2bfe3f2eSlogwang if (ret) 304*2bfe3f2eSlogwang goto error; 305*2bfe3f2eSlogwang } 306*2bfe3f2eSlogwang if (!vlan_filter_n) { 307*2bfe3f2eSlogwang ret = mlx5_ctrl_flow(dev, &bcast, &bcast); 308*2bfe3f2eSlogwang if (ret) 309*2bfe3f2eSlogwang goto error; 310*2bfe3f2eSlogwang ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec, 311*2bfe3f2eSlogwang &ipv6_multi_mask); 312*2bfe3f2eSlogwang if (ret) 313*2bfe3f2eSlogwang goto error; 314*2bfe3f2eSlogwang } 315*2bfe3f2eSlogwang } 316*2bfe3f2eSlogwang /* Add MAC address flows. */ 317*2bfe3f2eSlogwang for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) { 318*2bfe3f2eSlogwang struct ether_addr *mac = &dev->data->mac_addrs[i]; 319*2bfe3f2eSlogwang 320*2bfe3f2eSlogwang if (!memcmp(mac, &cmp, sizeof(*mac))) 321*2bfe3f2eSlogwang continue; 322*2bfe3f2eSlogwang memcpy(&unicast.dst.addr_bytes, 323*2bfe3f2eSlogwang mac->addr_bytes, 324*2bfe3f2eSlogwang ETHER_ADDR_LEN); 325*2bfe3f2eSlogwang for (j = 0; j != vlan_filter_n; ++j) { 326*2bfe3f2eSlogwang uint16_t vlan = priv->vlan_filter[j]; 327*2bfe3f2eSlogwang 328*2bfe3f2eSlogwang struct rte_flow_item_vlan vlan_spec = { 329*2bfe3f2eSlogwang .tci = rte_cpu_to_be_16(vlan), 330*2bfe3f2eSlogwang }; 331*2bfe3f2eSlogwang struct rte_flow_item_vlan vlan_mask = { 332*2bfe3f2eSlogwang .tci = 0xffff, 333*2bfe3f2eSlogwang }; 334*2bfe3f2eSlogwang 335*2bfe3f2eSlogwang ret = mlx5_ctrl_flow_vlan(dev, &unicast, 336*2bfe3f2eSlogwang &unicast_mask, 337*2bfe3f2eSlogwang &vlan_spec, 338*2bfe3f2eSlogwang &vlan_mask); 339*2bfe3f2eSlogwang if (ret) 340*2bfe3f2eSlogwang goto error; 341*2bfe3f2eSlogwang } 342*2bfe3f2eSlogwang if (!vlan_filter_n) { 343*2bfe3f2eSlogwang ret = mlx5_ctrl_flow(dev, &unicast, 344*2bfe3f2eSlogwang &unicast_mask); 345*2bfe3f2eSlogwang if (ret) 346*2bfe3f2eSlogwang goto error; 347*2bfe3f2eSlogwang } 348*2bfe3f2eSlogwang } 349*2bfe3f2eSlogwang return 0; 350*2bfe3f2eSlogwang error: 351*2bfe3f2eSlogwang return rte_errno; 352*2bfe3f2eSlogwang } 353*2bfe3f2eSlogwang 354*2bfe3f2eSlogwang 355*2bfe3f2eSlogwang /** 356*2bfe3f2eSlogwang * Disable traffic flows configured by control plane 357*2bfe3f2eSlogwang * 358*2bfe3f2eSlogwang * @param priv 359*2bfe3f2eSlogwang * Pointer to Ethernet device private data. 360*2bfe3f2eSlogwang * @param dev 361*2bfe3f2eSlogwang * Pointer to Ethernet device structure. 362*2bfe3f2eSlogwang * 363*2bfe3f2eSlogwang * @return 364*2bfe3f2eSlogwang * 0 on success. 365*2bfe3f2eSlogwang */ 366*2bfe3f2eSlogwang int 367*2bfe3f2eSlogwang priv_dev_traffic_disable(struct priv *priv, struct rte_eth_dev *dev) 368*2bfe3f2eSlogwang { 369*2bfe3f2eSlogwang (void)dev; 370*2bfe3f2eSlogwang priv_flow_flush(priv, &priv->ctrl_flows); 371*2bfe3f2eSlogwang return 0; 372*2bfe3f2eSlogwang } 373*2bfe3f2eSlogwang 374*2bfe3f2eSlogwang /** 375*2bfe3f2eSlogwang * Restart traffic flows configured by control plane 376*2bfe3f2eSlogwang * 377*2bfe3f2eSlogwang * @param priv 378*2bfe3f2eSlogwang * Pointer to Ethernet device private data. 379*2bfe3f2eSlogwang * @param dev 380*2bfe3f2eSlogwang * Pointer to Ethernet device structure. 381*2bfe3f2eSlogwang * 382*2bfe3f2eSlogwang * @return 383*2bfe3f2eSlogwang * 0 on success. 384*2bfe3f2eSlogwang */ 385*2bfe3f2eSlogwang int 386*2bfe3f2eSlogwang priv_dev_traffic_restart(struct priv *priv, struct rte_eth_dev *dev) 387*2bfe3f2eSlogwang { 388*2bfe3f2eSlogwang if (dev->data->dev_started) { 389*2bfe3f2eSlogwang priv_dev_traffic_disable(priv, dev); 390*2bfe3f2eSlogwang priv_dev_traffic_enable(priv, dev); 391*2bfe3f2eSlogwang } 392*2bfe3f2eSlogwang return 0; 393*2bfe3f2eSlogwang } 394*2bfe3f2eSlogwang 395*2bfe3f2eSlogwang /** 396*2bfe3f2eSlogwang * Restart traffic flows configured by control plane 397*2bfe3f2eSlogwang * 398*2bfe3f2eSlogwang * @param dev 399*2bfe3f2eSlogwang * Pointer to Ethernet device structure. 400*2bfe3f2eSlogwang * 401*2bfe3f2eSlogwang * @return 402*2bfe3f2eSlogwang * 0 on success. 403*2bfe3f2eSlogwang */ 404*2bfe3f2eSlogwang int 405*2bfe3f2eSlogwang mlx5_traffic_restart(struct rte_eth_dev *dev) 406*2bfe3f2eSlogwang { 407*2bfe3f2eSlogwang struct priv *priv = dev->data->dev_private; 408*2bfe3f2eSlogwang 409*2bfe3f2eSlogwang priv_lock(priv); 410*2bfe3f2eSlogwang priv_dev_traffic_restart(priv, dev); 411*2bfe3f2eSlogwang priv_unlock(priv); 412*2bfe3f2eSlogwang return 0; 413*2bfe3f2eSlogwang } 414