aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMoni Shoua <monis@mellanox.com>2015-02-03 09:48:34 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-04 19:14:25 -0500
commit5da0354726e4a6ae2e25c1fa2feb77585d997b05 (patch)
tree4a3820ca69e109f78f71d5e7c02c62609cfead1e
parent53f33ae295a5098f12218da1400f55ad7df7447c (diff)
net/mlx4_en: Port aggregation configuration
Capture NETDEV events generated by the bonding driver and based on that make decisions of how to configure port aggregation in the mlx4 core driver. This includes setting the V2P port table and re-creating the interested interfaces in bonded/non-bonded mode. Signed-off-by: Moni Shoua <monis@mellanox.com> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c176
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h5
3 files changed, 189 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index c643d2bbb7b9..58d5a07d0ff4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -214,6 +214,8 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
214 iounmap(mdev->uar_map); 214 iounmap(mdev->uar_map);
215 mlx4_uar_free(dev, &mdev->priv_uar); 215 mlx4_uar_free(dev, &mdev->priv_uar);
216 mlx4_pd_free(dev, mdev->priv_pdn); 216 mlx4_pd_free(dev, mdev->priv_pdn);
217 if (mdev->nb.notifier_call)
218 unregister_netdevice_notifier(&mdev->nb);
217 kfree(mdev); 219 kfree(mdev);
218} 220}
219 221
@@ -298,6 +300,12 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
298 if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) 300 if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
299 mdev->pndev[i] = NULL; 301 mdev->pndev[i] = NULL;
300 } 302 }
303 /* register notifier */
304 mdev->nb.notifier_call = mlx4_en_netdev_event;
305 if (register_netdevice_notifier(&mdev->nb)) {
306 mdev->nb.notifier_call = NULL;
307 mlx4_err(mdev, "Failed to create notifier\n");
308 }
301 309
302 return mdev; 310 return mdev;
303 311
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index e075ff1f4e80..028937b2a199 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2062,6 +2062,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
2062 /* Detach the netdev so tasks would not attempt to access it */ 2062 /* Detach the netdev so tasks would not attempt to access it */
2063 mutex_lock(&mdev->state_lock); 2063 mutex_lock(&mdev->state_lock);
2064 mdev->pndev[priv->port] = NULL; 2064 mdev->pndev[priv->port] = NULL;
2065 mdev->upper[priv->port] = NULL;
2065 mutex_unlock(&mdev->state_lock); 2066 mutex_unlock(&mdev->state_lock);
2066 2067
2067 mlx4_en_free_resources(priv); 2068 mlx4_en_free_resources(priv);
@@ -2441,6 +2442,180 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
2441#endif 2442#endif
2442}; 2443};
2443 2444
2445struct mlx4_en_bond {
2446 struct work_struct work;
2447 struct mlx4_en_priv *priv;
2448 int is_bonded;
2449 struct mlx4_port_map port_map;
2450};
2451
2452static void mlx4_en_bond_work(struct work_struct *work)
2453{
2454 struct mlx4_en_bond *bond = container_of(work,
2455 struct mlx4_en_bond,
2456 work);
2457 int err = 0;
2458 struct mlx4_dev *dev = bond->priv->mdev->dev;
2459
2460 if (bond->is_bonded) {
2461 if (!mlx4_is_bonded(dev)) {
2462 err = mlx4_bond(dev);
2463 if (err)
2464 en_err(bond->priv, "Fail to bond device\n");
2465 }
2466 if (!err) {
2467 err = mlx4_port_map_set(dev, &bond->port_map);
2468 if (err)
2469 en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n",
2470 bond->port_map.port1,
2471 bond->port_map.port2,
2472 err);
2473 }
2474 } else if (mlx4_is_bonded(dev)) {
2475 err = mlx4_unbond(dev);
2476 if (err)
2477 en_err(bond->priv, "Fail to unbond device\n");
2478 }
2479 dev_put(bond->priv->dev);
2480 kfree(bond);
2481}
2482
2483static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded,
2484 u8 v2p_p1, u8 v2p_p2)
2485{
2486 struct mlx4_en_bond *bond = NULL;
2487
2488 bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
2489 if (!bond)
2490 return -ENOMEM;
2491
2492 INIT_WORK(&bond->work, mlx4_en_bond_work);
2493 bond->priv = priv;
2494 bond->is_bonded = is_bonded;
2495 bond->port_map.port1 = v2p_p1;
2496 bond->port_map.port2 = v2p_p2;
2497 dev_hold(priv->dev);
2498 queue_work(priv->mdev->workqueue, &bond->work);
2499 return 0;
2500}
2501
2502int mlx4_en_netdev_event(struct notifier_block *this,
2503 unsigned long event, void *ptr)
2504{
2505 struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
2506 u8 port = 0;
2507 struct mlx4_en_dev *mdev;
2508 struct mlx4_dev *dev;
2509 int i, num_eth_ports = 0;
2510 bool do_bond = true;
2511 struct mlx4_en_priv *priv;
2512 u8 v2p_port1 = 0;
2513 u8 v2p_port2 = 0;
2514
2515 if (!net_eq(dev_net(ndev), &init_net))
2516 return NOTIFY_DONE;
2517
2518 mdev = container_of(this, struct mlx4_en_dev, nb);
2519 dev = mdev->dev;
2520
2521 /* Go into this mode only when two network devices set on two ports
2522 * of the same mlx4 device are slaves of the same bonding master
2523 */
2524 mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
2525 ++num_eth_ports;
2526 if (!port && (mdev->pndev[i] == ndev))
2527 port = i;
2528 mdev->upper[i] = mdev->pndev[i] ?
2529 netdev_master_upper_dev_get(mdev->pndev[i]) : NULL;
2530 /* condition not met: network device is a slave */
2531 if (!mdev->upper[i])
2532 do_bond = false;
2533 if (num_eth_ports < 2)
2534 continue;
2535 /* condition not met: same master */
2536 if (mdev->upper[i] != mdev->upper[i-1])
2537 do_bond = false;
2538 }
2539 /* condition not met: 2 salves */
2540 do_bond = (num_eth_ports == 2) ? do_bond : false;
2541
2542 /* handle only events that come with enough info */
2543 if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port)
2544 return NOTIFY_DONE;
2545
2546 priv = netdev_priv(ndev);
2547 if (do_bond) {
2548 struct netdev_notifier_bonding_info *notifier_info = ptr;
2549 struct netdev_bonding_info *bonding_info =
2550 &notifier_info->bonding_info;
2551
2552 /* required mode 1, 2 or 4 */
2553 if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) &&
2554 (bonding_info->master.bond_mode != BOND_MODE_XOR) &&
2555 (bonding_info->master.bond_mode != BOND_MODE_8023AD))
2556 do_bond = false;
2557
2558 /* require exactly 2 slaves */
2559 if (bonding_info->master.num_slaves != 2)
2560 do_bond = false;
2561
2562 /* calc v2p */
2563 if (do_bond) {
2564 if (bonding_info->master.bond_mode ==
2565 BOND_MODE_ACTIVEBACKUP) {
2566 /* in active-backup mode virtual ports are
2567 * mapped to the physical port of the active
2568 * slave */
2569 if (bonding_info->slave.state ==
2570 BOND_STATE_BACKUP) {
2571 if (port == 1) {
2572 v2p_port1 = 2;
2573 v2p_port2 = 2;
2574 } else {
2575 v2p_port1 = 1;
2576 v2p_port2 = 1;
2577 }
2578 } else { /* BOND_STATE_ACTIVE */
2579 if (port == 1) {
2580 v2p_port1 = 1;
2581 v2p_port2 = 1;
2582 } else {
2583 v2p_port1 = 2;
2584 v2p_port2 = 2;
2585 }
2586 }
2587 } else { /* Active-Active */
2588 /* in active-active mode a virtual port is
2589 * mapped to the native physical port if and only
2590 * if the physical port is up */
2591 __s8 link = bonding_info->slave.link;
2592
2593 if (port == 1)
2594 v2p_port2 = 2;
2595 else
2596 v2p_port1 = 1;
2597 if ((link == BOND_LINK_UP) ||
2598 (link == BOND_LINK_FAIL)) {
2599 if (port == 1)
2600 v2p_port1 = 1;
2601 else
2602 v2p_port2 = 2;
2603 } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */
2604 if (port == 1)
2605 v2p_port1 = 2;
2606 else
2607 v2p_port2 = 1;
2608 }
2609 }
2610 }
2611 }
2612
2613 mlx4_en_queue_bond_work(priv, do_bond,
2614 v2p_port1, v2p_port2);
2615
2616 return NOTIFY_DONE;
2617}
2618
2444int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, 2619int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
2445 struct mlx4_en_port_profile *prof) 2620 struct mlx4_en_port_profile *prof)
2446{ 2621{
@@ -2623,6 +2798,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
2623 } 2798 }
2624 2799
2625 mdev->pndev[port] = dev; 2800 mdev->pndev[port] = dev;
2801 mdev->upper[port] = NULL;
2626 2802
2627 netif_carrier_off(dev); 2803 netif_carrier_off(dev);
2628 mlx4_en_set_default_moderation(priv); 2804 mlx4_en_set_default_moderation(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 944a112dff37..2a8268e6be15 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -390,6 +390,7 @@ struct mlx4_en_dev {
390 struct pci_dev *pdev; 390 struct pci_dev *pdev;
391 struct mutex state_lock; 391 struct mutex state_lock;
392 struct net_device *pndev[MLX4_MAX_PORTS + 1]; 392 struct net_device *pndev[MLX4_MAX_PORTS + 1];
393 struct net_device *upper[MLX4_MAX_PORTS + 1];
393 u32 port_cnt; 394 u32 port_cnt;
394 bool device_up; 395 bool device_up;
395 struct mlx4_en_profile profile; 396 struct mlx4_en_profile profile;
@@ -410,6 +411,7 @@ struct mlx4_en_dev {
410 unsigned long overflow_period; 411 unsigned long overflow_period;
411 struct ptp_clock *ptp_clock; 412 struct ptp_clock *ptp_clock;
412 struct ptp_clock_info ptp_clock_info; 413 struct ptp_clock_info ptp_clock_info;
414 struct notifier_block nb;
413}; 415};
414 416
415 417
@@ -845,6 +847,9 @@ int mlx4_en_reset_config(struct net_device *dev,
845 struct hwtstamp_config ts_config, 847 struct hwtstamp_config ts_config,
846 netdev_features_t new_features); 848 netdev_features_t new_features);
847 849
850int mlx4_en_netdev_event(struct notifier_block *this,
851 unsigned long event, void *ptr);
852
848/* 853/*
849 * Functions for time stamping 854 * Functions for time stamping
850 */ 855 */