Commit 9cba4ebc authored by Mohamad Haj Yahia's avatar Mohamad Haj Yahia Committed by David S. Miller
Browse files

net/mlx5: Fix potential deadlock in command mode change



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>
parent d57847dc
Loading
Loading
Loading
Loading
+33 −46
Original line number Original line Diff line number Diff line
@@ -710,13 +710,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)),
@@ -774,10 +774,12 @@ 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)
		goto out;

	err = wait_func(dev, ent);
	err = wait_func(dev, ent);
	if (err == -ETIMEDOUT)
	if (err == -ETIMEDOUT)
			goto out;
		goto out_free;


	ds = ent->ts2 - ent->ts1;
	ds = ent->ts2 - ent->ts1;
	op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
	op = be16_to_cpu(((struct mlx5_inbox_hdr *)in->first.data)->opcode);
@@ -792,10 +794,6 @@ static int mlx5_cmd_invoke(struct mlx5_core_dev *dev, struct mlx5_cmd_msg *in,
			   "fw exec time for %s is %lld nsec\n",
			   "fw exec time for %s is %lld nsec\n",
			   mlx5_command_str(op), ds);
			   mlx5_command_str(op), ds);
	*status = ent->status;
	*status = ent->status;
		free_cmd(ent);
	}

	return err;


out_free:
out_free:
	free_cmd(ent);
	free_cmd(ent);
@@ -1185,41 +1183,30 @@ err_dbg:
	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)