From d7544ddd20317ee9af98d8549871e8ff4155c413 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Wed, 9 Jul 2014 11:29:21 +0300 Subject: [PATCH] net/mlx4: Switching between sending commands via polling and events may results in hung tasks When switching between those methonds of sending commands, it's possbile that a task will keep waiting for the polling sempahore, but may never be able to acquire it. This is due to mlx4_cmd_use_events which "down"s the sempahore back to 0. Reproducing it involves in sending commands while changing between mlx4_cmd_use_polling and mlx4_cmd_use_events. Signed-off-by: Matan Barak (Ported from Mellanox OFED 2.4) Signed-off-by: Mukesh Kacker --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 27 ++++++++++++++++------- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 27ee706ae9478..372443c285395 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -805,14 +805,20 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) return mlx4_internal_err_ret_value(dev, op, op_modifier); - if (mlx4_priv(dev)->cmd.use_events) - return mlx4_cmd_wait(dev, in_param, out_param, - out_is_imm, in_modifier, - op_modifier, op, timeout); - else - return mlx4_cmd_poll(dev, in_param, out_param, - out_is_imm, in_modifier, - op_modifier, op, timeout); + else { + int ret; + read_lock(&mlx4_priv(dev)->cmd.switch_lock); + if (mlx4_priv(dev)->cmd.use_events) + ret = mlx4_cmd_wait(dev, in_param, out_param, + out_is_imm, in_modifier, + op_modifier, op, timeout); + else + ret = mlx4_cmd_poll(dev, in_param, out_param, + out_is_imm, in_modifier, + op_modifier, op, timeout); + read_unlock(&mlx4_priv(dev)->cmd.switch_lock); + return ret; + } } return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, in_modifier, op_modifier, op, timeout); @@ -2469,6 +2475,7 @@ int mlx4_cmd_init(struct mlx4_dev *dev) int flags = 0; if (!priv->cmd.initialized) { + rwlock_init(&priv->cmd.switch_lock); mutex_init(&priv->cmd.slave_cmd_mutex); sema_init(&priv->cmd.poll_sem, 1); priv->cmd.use_events = 0; @@ -2598,6 +2605,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) if (!priv->cmd.context) return -ENOMEM; + write_lock(&priv->cmd.switch_lock); for (i = 0; i < priv->cmd.max_cmds; ++i) { priv->cmd.context[i].token = i; priv->cmd.context[i].next = i + 1; @@ -2622,6 +2630,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) down(&priv->cmd.poll_sem); priv->cmd.use_events = 1; + write_unlock(&priv->cmd.switch_lock); return err; } @@ -2634,6 +2643,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i; + write_lock(&priv->cmd.switch_lock); priv->cmd.use_events = 0; for (i = 0; i < priv->cmd.max_cmds; ++i) @@ -2642,6 +2652,7 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev) kfree(priv->cmd.context); up(&priv->cmd.poll_sem); + write_unlock(&priv->cmd.switch_lock); } struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 84d1cfe8113f0..b38e385147ccb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -612,6 +612,7 @@ struct mlx4_cmd { struct mutex slave_cmd_mutex; struct semaphore poll_sem; struct semaphore event_sem; + rwlock_t switch_lock; int max_cmds; spinlock_t context_lock; int free_head; -- 2.50.1