| From foo@baz Sat Dec 19 11:38:44 AM CET 2020 |
| From: Moshe Shemesh <moshe@mellanox.com> |
| Date: Wed, 9 Dec 2020 15:03:38 +0200 |
| Subject: net/mlx4_en: Avoid scheduling restart task if it is already running |
| |
| From: Moshe Shemesh <moshe@mellanox.com> |
| |
| [ Upstream commit fed91613c9dd455dd154b22fa8e11b8526466082 ] |
| |
| Add restarting state flag to avoid scheduling another restart task while |
| such task is already running. Change task name from watchdog_task to |
| restart_task to better fit the task role. |
| |
| Fixes: 1e338db56e5a ("mlx4_en: Fix a race at restart task") |
| Signed-off-by: Moshe Shemesh <moshe@mellanox.com> |
| Signed-off-by: Tariq Toukan <tariqt@nvidia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 20 +++++++++++++------- |
| drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 7 ++++++- |
| 2 files changed, 19 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c |
| +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c |
| @@ -1378,8 +1378,10 @@ static void mlx4_en_tx_timeout(struct ne |
| tx_ring->cons, tx_ring->prod); |
| |
| priv->port_stats.tx_timeout++; |
| - en_dbg(DRV, priv, "Scheduling watchdog\n"); |
| - queue_work(mdev->workqueue, &priv->watchdog_task); |
| + if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) { |
| + en_dbg(DRV, priv, "Scheduling port restart\n"); |
| + queue_work(mdev->workqueue, &priv->restart_task); |
| + } |
| } |
| |
| |
| @@ -1829,6 +1831,7 @@ int mlx4_en_start_port(struct net_device |
| local_bh_enable(); |
| } |
| |
| + clear_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state); |
| netif_tx_start_all_queues(dev); |
| netif_device_attach(dev); |
| |
| @@ -1999,7 +2002,7 @@ void mlx4_en_stop_port(struct net_device |
| static void mlx4_en_restart(struct work_struct *work) |
| { |
| struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, |
| - watchdog_task); |
| + restart_task); |
| struct mlx4_en_dev *mdev = priv->mdev; |
| struct net_device *dev = priv->dev; |
| |
| @@ -2377,7 +2380,7 @@ static int mlx4_en_change_mtu(struct net |
| if (netif_running(dev)) { |
| mutex_lock(&mdev->state_lock); |
| if (!mdev->device_up) { |
| - /* NIC is probably restarting - let watchdog task reset |
| + /* NIC is probably restarting - let restart task reset |
| * the port */ |
| en_dbg(DRV, priv, "Change MTU called with card down!?\n"); |
| } else { |
| @@ -2386,7 +2389,9 @@ static int mlx4_en_change_mtu(struct net |
| if (err) { |
| en_err(priv, "Failed restarting port:%d\n", |
| priv->port); |
| - queue_work(mdev->workqueue, &priv->watchdog_task); |
| + if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, |
| + &priv->state)) |
| + queue_work(mdev->workqueue, &priv->restart_task); |
| } |
| } |
| mutex_unlock(&mdev->state_lock); |
| @@ -2792,7 +2797,8 @@ static int mlx4_xdp_set(struct net_devic |
| if (err) { |
| en_err(priv, "Failed starting port %d for XDP change\n", |
| priv->port); |
| - queue_work(mdev->workqueue, &priv->watchdog_task); |
| + if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) |
| + queue_work(mdev->workqueue, &priv->restart_task); |
| } |
| } |
| |
| @@ -3165,7 +3171,7 @@ int mlx4_en_init_netdev(struct mlx4_en_d |
| priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev); |
| spin_lock_init(&priv->stats_lock); |
| INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); |
| - INIT_WORK(&priv->watchdog_task, mlx4_en_restart); |
| + INIT_WORK(&priv->restart_task, mlx4_en_restart); |
| INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); |
| INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); |
| INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); |
| --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h |
| +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h |
| @@ -530,6 +530,10 @@ struct mlx4_en_stats_bitmap { |
| struct mutex mutex; /* for mutual access to stats bitmap */ |
| }; |
| |
| +enum { |
| + MLX4_EN_STATE_FLAG_RESTARTING, |
| +}; |
| + |
| struct mlx4_en_priv { |
| struct mlx4_en_dev *mdev; |
| struct mlx4_en_port_profile *prof; |
| @@ -595,7 +599,7 @@ struct mlx4_en_priv { |
| struct mlx4_en_cq *rx_cq[MAX_RX_RINGS]; |
| struct mlx4_qp drop_qp; |
| struct work_struct rx_mode_task; |
| - struct work_struct watchdog_task; |
| + struct work_struct restart_task; |
| struct work_struct linkstate_task; |
| struct delayed_work stats_task; |
| struct delayed_work service_task; |
| @@ -641,6 +645,7 @@ struct mlx4_en_priv { |
| u32 pflags; |
| u8 rss_key[MLX4_EN_RSS_KEY_SIZE]; |
| u8 rss_hash_fn; |
| + unsigned long state; |
| }; |
| |
| enum mlx4_en_wol { |