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