diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_main.c | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 176 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 5 |
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 | ||
| 2445 | struct 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 | |||
| 2452 | static 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 | |||
| 2483 | static 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 | |||
| 2502 | int 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 | ¬ifier_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 | |||
| 2444 | int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | 2619 | int 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 | ||
| 850 | int 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 | */ |
