diff options
author | Yan Burman <yanb@mellanox.com> | 2013-03-06 22:46:55 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-07 15:52:04 -0500 |
commit | bfa8ab47415a87c6c93a9e54e16f2f8cc6de79af (patch) | |
tree | d529eba9c805f34b8c27f5b40e543d2f61c3cc7d /drivers/net/ethernet/mellanox | |
parent | e7dbeba85600aa2c8daf99f8f53d9ad27e88b810 (diff) |
net/mlx4_en: Fix race when setting the device MAC address
Remove unnecessary use of workqueue for the device MAC address setting
flow, and fix a race when setting MAC address which was introduced by
commit c07cb4b0a "net/mlx4_en: Manage hash of MAC addresses per port"
The race happened when mlx4_en_replace_mac was being executed in parallel
with a successive call to ndo_set_mac_address, e.g witn an A/B/A MAC
setting configuration test, the third set fails.
With this change we also properly report an error if set MAC fails.
Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 42 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 |
2 files changed, 21 insertions, 22 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index bb4d8d99f36d..217e618fd712 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c | |||
@@ -650,28 +650,10 @@ u64 mlx4_en_mac_to_u64(u8 *addr) | |||
650 | return mac; | 650 | return mac; |
651 | } | 651 | } |
652 | 652 | ||
653 | static int mlx4_en_set_mac(struct net_device *dev, void *addr) | 653 | static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv) |
654 | { | 654 | { |
655 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
656 | struct mlx4_en_dev *mdev = priv->mdev; | ||
657 | struct sockaddr *saddr = addr; | ||
658 | |||
659 | if (!is_valid_ether_addr(saddr->sa_data)) | ||
660 | return -EADDRNOTAVAIL; | ||
661 | |||
662 | memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); | ||
663 | queue_work(mdev->workqueue, &priv->mac_task); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static void mlx4_en_do_set_mac(struct work_struct *work) | ||
668 | { | ||
669 | struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, | ||
670 | mac_task); | ||
671 | struct mlx4_en_dev *mdev = priv->mdev; | ||
672 | int err = 0; | 655 | int err = 0; |
673 | 656 | ||
674 | mutex_lock(&mdev->state_lock); | ||
675 | if (priv->port_up) { | 657 | if (priv->port_up) { |
676 | /* Remove old MAC and insert the new one */ | 658 | /* Remove old MAC and insert the new one */ |
677 | err = mlx4_en_replace_mac(priv, priv->base_qpn, | 659 | err = mlx4_en_replace_mac(priv, priv->base_qpn, |
@@ -683,7 +665,26 @@ static void mlx4_en_do_set_mac(struct work_struct *work) | |||
683 | } else | 665 | } else |
684 | en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); | 666 | en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); |
685 | 667 | ||
668 | return err; | ||
669 | } | ||
670 | |||
671 | static int mlx4_en_set_mac(struct net_device *dev, void *addr) | ||
672 | { | ||
673 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
674 | struct mlx4_en_dev *mdev = priv->mdev; | ||
675 | struct sockaddr *saddr = addr; | ||
676 | int err; | ||
677 | |||
678 | if (!is_valid_ether_addr(saddr->sa_data)) | ||
679 | return -EADDRNOTAVAIL; | ||
680 | |||
681 | memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); | ||
682 | |||
683 | mutex_lock(&mdev->state_lock); | ||
684 | err = mlx4_en_do_set_mac(priv); | ||
686 | mutex_unlock(&mdev->state_lock); | 685 | mutex_unlock(&mdev->state_lock); |
686 | |||
687 | return err; | ||
687 | } | 688 | } |
688 | 689 | ||
689 | static void mlx4_en_clear_list(struct net_device *dev) | 690 | static void mlx4_en_clear_list(struct net_device *dev) |
@@ -1348,7 +1349,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work) | |||
1348 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); | 1349 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); |
1349 | } | 1350 | } |
1350 | if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { | 1351 | if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { |
1351 | queue_work(mdev->workqueue, &priv->mac_task); | 1352 | mlx4_en_do_set_mac(priv); |
1352 | mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; | 1353 | mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; |
1353 | } | 1354 | } |
1354 | mutex_unlock(&mdev->state_lock); | 1355 | mutex_unlock(&mdev->state_lock); |
@@ -2078,7 +2079,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
2078 | priv->msg_enable = MLX4_EN_MSG_LEVEL; | 2079 | priv->msg_enable = MLX4_EN_MSG_LEVEL; |
2079 | spin_lock_init(&priv->stats_lock); | 2080 | spin_lock_init(&priv->stats_lock); |
2080 | INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); | 2081 | INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); |
2081 | INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac); | ||
2082 | INIT_WORK(&priv->watchdog_task, mlx4_en_restart); | 2082 | INIT_WORK(&priv->watchdog_task, mlx4_en_restart); |
2083 | INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); | 2083 | INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); |
2084 | INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); | 2084 | INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index c313d7e943a9..f710b7ce0dcb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | |||
@@ -509,7 +509,6 @@ struct mlx4_en_priv { | |||
509 | struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; | 509 | struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; |
510 | struct mlx4_qp drop_qp; | 510 | struct mlx4_qp drop_qp; |
511 | struct work_struct rx_mode_task; | 511 | struct work_struct rx_mode_task; |
512 | struct work_struct mac_task; | ||
513 | struct work_struct watchdog_task; | 512 | struct work_struct watchdog_task; |
514 | struct work_struct linkstate_task; | 513 | struct work_struct linkstate_task; |
515 | struct delayed_work stats_task; | 514 | struct delayed_work stats_task; |