Commit d89d58f4 authored by Dragos Tatulea's avatar Dragos Tatulea Committed by Michael S. Tsirkin
Browse files

vdpa/mlx5: Introduce async fw command wrapper



Introduce a new function mlx5_vdpa_exec_async_cmds() which
wraps the mlx5_core async firmware command API in a way
that will be used to parallelize certain operation in this
driver.

The wrapper deals with the case when mlx5_cmd_exec_cb() returns
EBUSY due to the command being throttled.

Signed-off-by: default avatarDragos Tatulea <dtatulea@nvidia.com>
Reviewed-by: default avatarTariq Toukan <tariqt@nvidia.com>
Message-Id: <20240816090159.1967650-4-dtatulea@nvidia.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Acked-by: default avatarEugenio Pérez <eperezma@redhat.com>
Tested-by: default avatarLei Yang <leiyang@redhat.com>
parent de2cd39f
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -105,6 +105,18 @@ struct mlx5_vdpa_dev {
	bool suspended;
};

struct mlx5_vdpa_async_cmd {
	int err;
	struct mlx5_async_work cb_work;
	struct completion cmd_done;

	void *in;
	size_t inlen;

	void *out;
	size_t outlen;
};

int mlx5_vdpa_create_tis(struct mlx5_vdpa_dev *mvdev, void *in, u32 *tisn);
void mlx5_vdpa_destroy_tis(struct mlx5_vdpa_dev *mvdev, u32 tisn);
int mlx5_vdpa_create_rqt(struct mlx5_vdpa_dev *mvdev, void *in, int inlen, u32 *rqtn);
@@ -134,6 +146,9 @@ int mlx5_vdpa_update_cvq_iotlb(struct mlx5_vdpa_dev *mvdev,
				unsigned int asid);
int mlx5_vdpa_create_dma_mr(struct mlx5_vdpa_dev *mvdev);
int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid);
int mlx5_vdpa_exec_async_cmds(struct mlx5_vdpa_dev *mvdev,
			      struct mlx5_vdpa_async_cmd *cmds,
			      int num_cmds);

#define mlx5_vdpa_err(__dev, format, ...)                                                          \
	dev_err((__dev)->mdev->device, "%s:%d:(pid %d) error: " format, __func__, __LINE__,        \
+73 −0
Original line number Diff line number Diff line
@@ -321,3 +321,76 @@ void mlx5_vdpa_free_resources(struct mlx5_vdpa_dev *mvdev)
	mutex_destroy(&mvdev->mr_mtx);
	res->valid = false;
}

static void virtqueue_cmd_callback(int status, struct mlx5_async_work *context)
{
	struct mlx5_vdpa_async_cmd *cmd =
		container_of(context, struct mlx5_vdpa_async_cmd, cb_work);

	cmd->err = mlx5_cmd_check(context->ctx->dev, status, cmd->in, cmd->out);
	complete(&cmd->cmd_done);
}

static int issue_async_cmd(struct mlx5_vdpa_dev *mvdev,
			   struct mlx5_vdpa_async_cmd *cmds,
			   int issued,
			   int *completed)

{
	struct mlx5_vdpa_async_cmd *cmd = &cmds[issued];
	int err;

retry:
	err = mlx5_cmd_exec_cb(&mvdev->async_ctx,
			       cmd->in, cmd->inlen,
			       cmd->out, cmd->outlen,
			       virtqueue_cmd_callback,
			       &cmd->cb_work);
	if (err == -EBUSY) {
		if (*completed < issued) {
			/* Throttled by own commands: wait for oldest completion. */
			wait_for_completion(&cmds[*completed].cmd_done);
			(*completed)++;

			goto retry;
		} else {
			/* Throttled by external commands: switch to sync api. */
			err = mlx5_cmd_exec(mvdev->mdev,
					    cmd->in, cmd->inlen,
					    cmd->out, cmd->outlen);
			if (!err)
				(*completed)++;
		}
	}

	return err;
}

int mlx5_vdpa_exec_async_cmds(struct mlx5_vdpa_dev *mvdev,
			      struct mlx5_vdpa_async_cmd *cmds,
			      int num_cmds)
{
	int completed = 0;
	int issued = 0;
	int err = 0;

	for (int i = 0; i < num_cmds; i++)
		init_completion(&cmds[i].cmd_done);

	while (issued < num_cmds) {

		err = issue_async_cmd(mvdev, cmds, issued, &completed);
		if (err) {
			mlx5_vdpa_err(mvdev, "error issuing command %d of %d: %d\n",
				      issued, num_cmds, err);
			break;
		}

		issued++;
	}

	while (completed < issued)
		wait_for_completion(&cmds[completed++].cmd_done);

	return err;
}