Skip to content

Commit

Permalink
IB/mlx5: Create UMR QP just before first reg_mr occurs
Browse files Browse the repository at this point in the history
UMR QP is not used in some cases, so move QP and its CQ creations from
driver load flow to the time first reg_mr occurs, that is when MR
interfaces are first called.

The initialization of dev->umrc.pd and dev->umrc.lock is still done in
driver load because pd is needed for mlx5_mkey_cache_init and the lock
is reused to protect against the concurrent creation.

When testing 4G bytes memory registration latency with rtool [1] and 8
threads in parallel, there is minor performance degradation (<5% for
the max latency) is seen for the first reg_mr with this change.

Link: https://github.com/paravmellanox/rtool [1]

Signed-off-by: Jianbo Liu <[email protected]>
Link: https://lore.kernel.org/r/55d3c4f8a542fd974d8a4c5816eccfb318a59b38.1717409369.git.leon@kernel.org
Signed-off-by: Leon Romanovsky <[email protected]>
  • Loading branch information
Jianbo Liu authored and rleon committed Jun 16, 2024
1 parent ae6f6dd commit 6384201
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 14 deletions.
3 changes: 2 additions & 1 deletion drivers/infiniband/hw/mlx5/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4086,6 +4086,7 @@ static void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev)
{
mlx5_mkey_cache_cleanup(dev);
mlx5r_umr_resource_cleanup(dev);
mlx5r_umr_cleanup(dev);
}

static void mlx5_ib_stage_ib_reg_cleanup(struct mlx5_ib_dev *dev)
Expand All @@ -4097,7 +4098,7 @@ static int mlx5_ib_stage_post_ib_reg_umr_init(struct mlx5_ib_dev *dev)
{
int ret;

ret = mlx5r_umr_resource_init(dev);
ret = mlx5r_umr_init(dev);
if (ret)
return ret;

Expand Down
2 changes: 2 additions & 0 deletions drivers/infiniband/hw/mlx5/mlx5_ib.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,8 @@ struct umr_common {
*/
struct mutex lock;
unsigned int state;
/* Protects from repeat UMR QP creation */
struct mutex init_lock;
};

#define NUM_MKEYS_PER_PAGE \
Expand Down
9 changes: 9 additions & 0 deletions drivers/infiniband/hw/mlx5/mr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1470,13 +1470,18 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
{
struct mlx5_ib_dev *dev = to_mdev(pd->device);
struct ib_umem *umem;
int err;

if (!IS_ENABLED(CONFIG_INFINIBAND_USER_MEM))
return ERR_PTR(-EOPNOTSUPP);

mlx5_ib_dbg(dev, "start 0x%llx, iova 0x%llx, length 0x%llx, access_flags 0x%x\n",
start, iova, length, access_flags);

err = mlx5r_umr_resource_init(dev);
if (err)
return ERR_PTR(err);

if (access_flags & IB_ACCESS_ON_DEMAND)
return create_user_odp_mr(pd, start, length, iova, access_flags,
udata);
Expand Down Expand Up @@ -1523,6 +1528,10 @@ struct ib_mr *mlx5_ib_reg_user_mr_dmabuf(struct ib_pd *pd, u64 offset,
"offset 0x%llx, virt_addr 0x%llx, length 0x%llx, fd %d, access_flags 0x%x\n",
offset, virt_addr, length, fd, access_flags);

err = mlx5r_umr_resource_init(dev);
if (err)
return ERR_PTR(err);

/* dmabuf requires xlt update via umr to work. */
if (!mlx5r_umr_can_load_pas(dev, length))
return ERR_PTR(-EINVAL);
Expand Down
55 changes: 42 additions & 13 deletions drivers/infiniband/hw/mlx5/umr.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,28 @@ static int mlx5r_umr_qp_rst2rts(struct mlx5_ib_dev *dev, struct ib_qp *qp)
int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
{
struct ib_qp_init_attr init_attr = {};
struct ib_pd *pd;
struct ib_cq *cq;
struct ib_qp *qp;
int ret;
int ret = 0;

pd = ib_alloc_pd(&dev->ib_dev, 0);
if (IS_ERR(pd)) {
mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
return PTR_ERR(pd);
}

/*
* UMR qp is set once, never changed until device unload.
* Avoid taking the mutex if initialization is already done.
*/
if (dev->umrc.qp)
return 0;

mutex_lock(&dev->umrc.init_lock);
/* First user allocates the UMR resources. Skip if already allocated. */
if (dev->umrc.qp)
goto unlock;

cq = ib_alloc_cq(&dev->ib_dev, NULL, 128, 0, IB_POLL_SOFTIRQ);
if (IS_ERR(cq)) {
mlx5_ib_dbg(dev, "Couldn't create CQ for sync UMR QP\n");
ret = PTR_ERR(cq);
goto destroy_pd;
goto unlock;
}

init_attr.send_cq = cq;
Expand All @@ -160,7 +166,7 @@ int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
init_attr.cap.max_send_sge = 1;
init_attr.qp_type = MLX5_IB_QPT_REG_UMR;
init_attr.port_num = 1;
qp = ib_create_qp(pd, &init_attr);
qp = ib_create_qp(dev->umrc.pd, &init_attr);
if (IS_ERR(qp)) {
mlx5_ib_dbg(dev, "Couldn't create sync UMR QP\n");
ret = PTR_ERR(qp);
Expand All @@ -171,31 +177,54 @@ int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev)
if (ret)
goto destroy_qp;

dev->umrc.qp = qp;
dev->umrc.cq = cq;
dev->umrc.pd = pd;

sema_init(&dev->umrc.sem, MAX_UMR_WR);
mutex_init(&dev->umrc.lock);
dev->umrc.state = MLX5_UMR_STATE_ACTIVE;
dev->umrc.qp = qp;

mutex_unlock(&dev->umrc.init_lock);
return 0;

destroy_qp:
ib_destroy_qp(qp);
destroy_cq:
ib_free_cq(cq);
destroy_pd:
ib_dealloc_pd(pd);
unlock:
mutex_unlock(&dev->umrc.init_lock);
return ret;
}

void mlx5r_umr_resource_cleanup(struct mlx5_ib_dev *dev)
{
if (dev->umrc.state == MLX5_UMR_STATE_UNINIT)
return;
mutex_destroy(&dev->umrc.lock);
/* After device init, UMR cp/qp are not unset during the lifetime. */
ib_destroy_qp(dev->umrc.qp);
ib_free_cq(dev->umrc.cq);
}

int mlx5r_umr_init(struct mlx5_ib_dev *dev)
{
struct ib_pd *pd;

pd = ib_alloc_pd(&dev->ib_dev, 0);
if (IS_ERR(pd)) {
mlx5_ib_dbg(dev, "Couldn't create PD for sync UMR QP\n");
return PTR_ERR(pd);
}
dev->umrc.pd = pd;

mutex_init(&dev->umrc.init_lock);

return 0;
}

void mlx5r_umr_cleanup(struct mlx5_ib_dev *dev)
{
mutex_destroy(&dev->umrc.init_lock);
ib_dealloc_pd(dev->umrc.pd);
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/infiniband/hw/mlx5/umr.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
int mlx5r_umr_resource_init(struct mlx5_ib_dev *dev);
void mlx5r_umr_resource_cleanup(struct mlx5_ib_dev *dev);

int mlx5r_umr_init(struct mlx5_ib_dev *dev);
void mlx5r_umr_cleanup(struct mlx5_ib_dev *dev);

static inline bool mlx5r_umr_can_load_pas(struct mlx5_ib_dev *dev,
size_t length)
{
Expand Down

0 comments on commit 6384201

Please sign in to comment.