Commit c92dd270 authored by Mohamad Haj Yahia's avatar Mohamad Haj Yahia Committed by Ben Hutchings

net/mlx5: Fix potential deadlock in command mode change

commit 9cba4ebc upstream.

Call command completion handler in case of timeout when working in
interrupts mode.
Avoid flushing the commands workqueue after acquiring the semaphores to
prevent a potential deadlock.

Fixes: e126ba97 ('mlx5: Add driver for Mellanox Connect-IB adapters')
Signed-off-by: default avatarMohamad Haj Yahia <mohamad@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[bwh: Backported to 3.16: the calculation of ds is more complex]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 8b65deb4
...@@ -608,13 +608,13 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent) ...@@ -608,13 +608,13 @@ static int wait_func(struct mlx5_core_dev *dev, struct mlx5_cmd_work_ent *ent)
if (cmd->mode == CMD_MODE_POLLING) { if (cmd->mode == CMD_MODE_POLLING) {
wait_for_completion(&ent->done); wait_for_completion(&ent->done);
err = ent->ret; } else if (!wait_for_completion_timeout(&ent->done, timeout)) {
} else { ent->ret = -ETIMEDOUT;
if (!wait_for_completion_timeout(&ent->done, timeout)) mlx5_cmd_comp_handler(dev, 1UL << ent->idx);
err = -ETIMEDOUT;
else
err = 0;
} }
err = ent->ret;
if (err == -ETIMEDOUT) { if (err == -ETIMEDOUT) {
mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n", mlx5_core_warn(dev, "%s(0x%x) timeout. Will cause a leak of a command resource\n",
mlx5_command_str(msg_to_opcode(ent->in)), mlx5_command_str(msg_to_opcode(ent->in)),
...@@ -663,31 +663,29 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in, ...@@ -663,31 +663,29 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
goto out_free; goto out_free;
} }
if (!callback) { if (callback)
err = wait_func(dev, ent); goto out;
if (err == -ETIMEDOUT)
goto out;
t1 = timespec_to_ktime(ent->ts1);
t2 = timespec_to_ktime(ent->ts2);
delta = ktime_sub(t2, t1);
ds = ktime_to_ns(delta);
op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
if (op < ARRAY_SIZE(cmd->stats)) {
stats = &cmd->stats[op];
spin_lock_irq(&stats->lock);
stats->sum += ds;
++stats->n;
spin_unlock_irq(&stats->lock);
}
mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
"fw exec time for %s is %lld nsec\n",
mlx5_command_str(op), ds);
*status = ent->status;
free_cmd(ent);
}
return err; err = wait_func(dev, ent);
if (err == -ETIMEDOUT)
goto out_free;
t1 = timespec_to_ktime(ent->ts1);
t2 = timespec_to_ktime(ent->ts2);
delta = ktime_sub(t2, t1);
ds = ktime_to_ns(delta);
op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
if (op < ARRAY_SIZE(cmd->stats)) {
stats = &cmd->stats[op];
spin_lock_irq(&stats->lock);
stats->sum += ds;
++stats->n;
spin_unlock_irq(&stats->lock);
}
mlx5_core_dbg_mask(dev, 1 << MLX5_CMD_TIME,
"fw exec time for %s is %lld nsec\n",
mlx5_command_str(op), ds);
*status = ent->status;
out_free: out_free:
free_cmd(ent); free_cmd(ent);
...@@ -1077,41 +1075,30 @@ static int create_debugfs_files(struct mlx5_core_dev *dev) ...@@ -1077,41 +1075,30 @@ static int create_debugfs_files(struct mlx5_core_dev *dev)
return err; return err;
} }
void mlx5_cmd_use_events(struct mlx5_core_dev *dev) static void mlx5_cmd_change_mod(struct mlx5_core_dev *dev, int mode)
{ {
struct mlx5_cmd *cmd = &dev->cmd; struct mlx5_cmd *cmd = &dev->cmd;
int i; int i;
for (i = 0; i < cmd->max_reg_cmds; i++) for (i = 0; i < cmd->max_reg_cmds; i++)
down(&cmd->sem); down(&cmd->sem);
down(&cmd->pages_sem); down(&cmd->pages_sem);
flush_workqueue(cmd->wq); cmd->mode = mode;
cmd->mode = CMD_MODE_EVENTS;
up(&cmd->pages_sem); up(&cmd->pages_sem);
for (i = 0; i < cmd->max_reg_cmds; i++) for (i = 0; i < cmd->max_reg_cmds; i++)
up(&cmd->sem); up(&cmd->sem);
} }
void mlx5_cmd_use_polling(struct mlx5_core_dev *dev) void mlx5_cmd_use_events(struct mlx5_core_dev *dev)
{ {
struct mlx5_cmd *cmd = &dev->cmd; mlx5_cmd_change_mod(dev, CMD_MODE_EVENTS);
int i; }
for (i = 0; i < cmd->max_reg_cmds; i++)
down(&cmd->sem);
down(&cmd->pages_sem);
flush_workqueue(cmd->wq);
cmd->mode = CMD_MODE_POLLING;
up(&cmd->pages_sem); void mlx5_cmd_use_polling(struct mlx5_core_dev *dev)
for (i = 0; i < cmd->max_reg_cmds; i++) {
up(&cmd->sem); mlx5_cmd_change_mod(dev, CMD_MODE_POLLING);
} }
static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg) static void free_msg(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *msg)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment