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 priv_link_update(priv, 1); 170 priv_dev_interrupt_handler_install(priv, dev); 171 priv_unlock(priv); 172 return 0; 173 error: 174 /* Rollback. */ 175 dev->data->dev_started = 0; 176 for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) 177 priv_mr_release(priv, mr); 178 priv_flow_stop(priv, &priv->flows); 179 priv_dev_traffic_disable(priv, dev); 180 priv_txq_stop(priv); 181 priv_rxq_stop(priv); 182 priv_flow_delete_drop_queue(priv); 183 priv_unlock(priv); 184 return -err; 185 } 186 187 /** 188 * DPDK callback to stop the device. 189 * 190 * Simulate device stop by detaching all configured flows. 191 * 192 * @param dev 193 * Pointer to Ethernet device structure. 194 */ 195 void 196 mlx5_dev_stop(struct rte_eth_dev *dev) 197 { 198 struct priv *priv = dev->data->dev_private; 199 struct mlx5_mr *mr; 200 201 priv_lock(priv); 202 dev->data->dev_started = 0; 203 /* Prevent crashes when queues are still in use. */ 204 dev->rx_pkt_burst = removed_rx_burst; 205 dev->tx_pkt_burst = removed_tx_burst; 206 rte_wmb(); 207 usleep(1000 * priv->rxqs_n); 208 DEBUG("%p: cleaning up and destroying hash RX queues", (void *)dev); 209 priv_flow_stop(priv, &priv->flows); 210 priv_dev_traffic_disable(priv, dev); 211 priv_rx_intr_vec_disable(priv); 212 priv_dev_interrupt_handler_uninstall(priv, dev); 213 priv_txq_stop(priv); 214 priv_rxq_stop(priv); 215 for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) 216 priv_mr_release(priv, mr); 217 priv_flow_delete_drop_queue(priv); 218 priv_unlock(priv); 219 } 220 221 /** 222 * Enable traffic flows configured by control plane 223 * 224 * @param priv 225 * Pointer to Ethernet device private data. 226 * @param dev 227 * Pointer to Ethernet device structure. 228 * 229 * @return 230 * 0 on success. 231 */ 232 int 233 priv_dev_traffic_enable(struct priv *priv, struct rte_eth_dev *dev) 234 { 235 struct rte_flow_item_eth bcast = { 236 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 237 }; 238 struct rte_flow_item_eth ipv6_multi_spec = { 239 .dst.addr_bytes = "\x33\x33\x00\x00\x00\x00", 240 }; 241 struct rte_flow_item_eth ipv6_multi_mask = { 242 .dst.addr_bytes = "\xff\xff\x00\x00\x00\x00", 243 }; 244 struct rte_flow_item_eth unicast = { 245 .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 246 }; 247 struct rte_flow_item_eth unicast_mask = { 248 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff", 249 }; 250 const unsigned int vlan_filter_n = priv->vlan_filter_n; 251 const struct ether_addr cmp = { 252 .addr_bytes = "\x00\x00\x00\x00\x00\x00", 253 }; 254 unsigned int i; 255 unsigned int j; 256 int ret; 257 258 if (priv->isolated) 259 return 0; 260 if (dev->data->promiscuous) { 261 struct rte_flow_item_eth promisc = { 262 .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00", 263 .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 264 .type = 0, 265 }; 266 267 claim_zero(mlx5_ctrl_flow(dev, &promisc, &promisc)); 268 return 0; 269 } 270 if (dev->data->all_multicast) { 271 struct rte_flow_item_eth multicast = { 272 .dst.addr_bytes = "\x01\x00\x00\x00\x00\x00", 273 .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", 274 .type = 0, 275 }; 276 277 claim_zero(mlx5_ctrl_flow(dev, &multicast, &multicast)); 278 } else { 279 /* Add broadcast/multicast flows. */ 280 for (i = 0; i != vlan_filter_n; ++i) { 281 uint16_t vlan = priv->vlan_filter[i]; 282 283 struct rte_flow_item_vlan vlan_spec = { 284 .tci = rte_cpu_to_be_16(vlan), 285 }; 286 struct rte_flow_item_vlan vlan_mask = { 287 .tci = 0xffff, 288 }; 289 290 ret = mlx5_ctrl_flow_vlan(dev, &bcast, &bcast, 291 &vlan_spec, &vlan_mask); 292 if (ret) 293 goto error; 294 ret = mlx5_ctrl_flow_vlan(dev, &ipv6_multi_spec, 295 &ipv6_multi_mask, 296 &vlan_spec, &vlan_mask); 297 if (ret) 298 goto error; 299 } 300 if (!vlan_filter_n) { 301 ret = mlx5_ctrl_flow(dev, &bcast, &bcast); 302 if (ret) 303 goto error; 304 ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec, 305 &ipv6_multi_mask); 306 if (ret) 307 goto error; 308 } 309 } 310 /* Add MAC address flows. */ 311 for (i = 0; i != MLX5_MAX_MAC_ADDRESSES; ++i) { 312 struct ether_addr *mac = &dev->data->mac_addrs[i]; 313 314 if (!memcmp(mac, &cmp, sizeof(*mac))) 315 continue; 316 memcpy(&unicast.dst.addr_bytes, 317 mac->addr_bytes, 318 ETHER_ADDR_LEN); 319 for (j = 0; j != vlan_filter_n; ++j) { 320 uint16_t vlan = priv->vlan_filter[j]; 321 322 struct rte_flow_item_vlan vlan_spec = { 323 .tci = rte_cpu_to_be_16(vlan), 324 }; 325 struct rte_flow_item_vlan vlan_mask = { 326 .tci = 0xffff, 327 }; 328 329 ret = mlx5_ctrl_flow_vlan(dev, &unicast, 330 &unicast_mask, 331 &vlan_spec, 332 &vlan_mask); 333 if (ret) 334 goto error; 335 } 336 if (!vlan_filter_n) { 337 ret = mlx5_ctrl_flow(dev, &unicast, 338 &unicast_mask); 339 if (ret) 340 goto error; 341 } 342 } 343 return 0; 344 error: 345 return rte_errno; 346 } 347 348 349 /** 350 * Disable traffic flows configured by control plane 351 * 352 * @param priv 353 * Pointer to Ethernet device private data. 354 * @param dev 355 * Pointer to Ethernet device structure. 356 * 357 * @return 358 * 0 on success. 359 */ 360 int 361 priv_dev_traffic_disable(struct priv *priv, struct rte_eth_dev *dev) 362 { 363 (void)dev; 364 priv_flow_flush(priv, &priv->ctrl_flows); 365 return 0; 366 } 367 368 /** 369 * Restart traffic flows configured by control plane 370 * 371 * @param priv 372 * Pointer to Ethernet device private data. 373 * @param dev 374 * Pointer to Ethernet device structure. 375 * 376 * @return 377 * 0 on success. 378 */ 379 int 380 priv_dev_traffic_restart(struct priv *priv, struct rte_eth_dev *dev) 381 { 382 if (dev->data->dev_started) { 383 priv_dev_traffic_disable(priv, dev); 384 priv_dev_traffic_enable(priv, dev); 385 } 386 return 0; 387 } 388 389 /** 390 * Restart traffic flows configured by control plane 391 * 392 * @param dev 393 * Pointer to Ethernet device structure. 394 * 395 * @return 396 * 0 on success. 397 */ 398 int 399 mlx5_traffic_restart(struct rte_eth_dev *dev) 400 { 401 struct priv *priv = dev->data->dev_private; 402 403 priv_lock(priv); 404 priv_dev_traffic_restart(priv, dev); 405 priv_unlock(priv); 406 return 0; 407 } 408