Skip to content

Commit 534fd7a

Browse files
yishaihjgunthorpe
authored andcommitted
IB/mlx5: Manage indirection mkey upon DEVX flow for ODP
Manage indirection mkey upon DEVX flow to support ODP. To support a page fault event on the indirection mkey it needs to be part of the device mkey radix tree. Both the creation and the deletion flows for a DEVX object which is indirection mkey were adapted to handle that. Signed-off-by: Yishai Hadas <[email protected]> Reviewed-by: Artemy Kovalyov <[email protected]> Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent fa31f14 commit 534fd7a

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed

drivers/infiniband/hw/mlx5/devx.c

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@
1717
#define UVERBS_MODULE_NAME mlx5_ib
1818
#include <rdma/uverbs_named_ioctl.h>
1919

20+
enum devx_obj_flags {
21+
DEVX_OBJ_FLAGS_INDIRECT_MKEY = 1 << 0,
22+
};
23+
2024
#define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in)
2125
struct devx_obj {
2226
struct mlx5_core_dev *mdev;
2327
u64 obj_id;
2428
u32 dinlen; /* destroy inbox length */
2529
u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW];
30+
u32 flags;
31+
struct mlx5_ib_devx_mr devx_mr;
2632
};
2733

2834
struct devx_umem {
@@ -1011,6 +1017,36 @@ static void devx_obj_build_destroy_cmd(void *in, void *out, void *din,
10111017
}
10121018
}
10131019

1020+
static int devx_handle_mkey_indirect(struct devx_obj *obj,
1021+
struct mlx5_ib_dev *dev,
1022+
void *in, void *out)
1023+
{
1024+
struct mlx5_mkey_table *table = &dev->mdev->priv.mkey_table;
1025+
struct mlx5_ib_devx_mr *devx_mr = &obj->devx_mr;
1026+
unsigned long flags;
1027+
struct mlx5_core_mkey *mkey;
1028+
void *mkc;
1029+
u8 key;
1030+
int err;
1031+
1032+
mkey = &devx_mr->mmkey;
1033+
mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
1034+
key = MLX5_GET(mkc, mkc, mkey_7_0);
1035+
mkey->key = mlx5_idx_to_mkey(
1036+
MLX5_GET(create_mkey_out, out, mkey_index)) | key;
1037+
mkey->type = MLX5_MKEY_INDIRECT_DEVX;
1038+
mkey->iova = MLX5_GET64(mkc, mkc, start_addr);
1039+
mkey->size = MLX5_GET64(mkc, mkc, len);
1040+
mkey->pd = MLX5_GET(mkc, mkc, pd);
1041+
devx_mr->ndescs = MLX5_GET(mkc, mkc, translations_octword_size);
1042+
1043+
write_lock_irqsave(&table->lock, flags);
1044+
err = radix_tree_insert(&table->tree, mlx5_base_mkey(mkey->key),
1045+
mkey);
1046+
write_unlock_irqrestore(&table->lock, flags);
1047+
return err;
1048+
}
1049+
10141050
static int devx_handle_mkey_create(struct mlx5_ib_dev *dev,
10151051
struct devx_obj *obj,
10161052
void *in, int in_len)
@@ -1030,24 +1066,67 @@ static int devx_handle_mkey_create(struct mlx5_ib_dev *dev,
10301066
access_mode |= MLX5_GET(mkc, mkc, access_mode_4_2) << 2;
10311067

10321068
if (access_mode == MLX5_MKC_ACCESS_MODE_KLMS ||
1033-
access_mode == MLX5_MKC_ACCESS_MODE_KSM)
1069+
access_mode == MLX5_MKC_ACCESS_MODE_KSM) {
1070+
if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING))
1071+
obj->flags |= DEVX_OBJ_FLAGS_INDIRECT_MKEY;
10341072
return 0;
1073+
}
10351074

10361075
MLX5_SET(create_mkey_in, in, mkey_umem_valid, 1);
10371076
return 0;
10381077
}
10391078

1079+
static void devx_free_indirect_mkey(struct rcu_head *rcu)
1080+
{
1081+
kfree(container_of(rcu, struct devx_obj, devx_mr.rcu));
1082+
}
1083+
1084+
/* This function to delete from the radix tree needs to be called before
1085+
* destroying the underlying mkey. Otherwise a race might occur in case that
1086+
* other thread will get the same mkey before this one will be deleted,
1087+
* in that case it will fail via inserting to the tree its own data.
1088+
*
1089+
* Note:
1090+
* An error in the destroy is not expected unless there is some other indirect
1091+
* mkey which points to this one. In a kernel cleanup flow it will be just
1092+
* destroyed in the iterative destruction call. In a user flow, in case
1093+
* the application didn't close in the expected order it's its own problem,
1094+
* the mkey won't be part of the tree, in both cases the kernel is safe.
1095+
*/
1096+
static void devx_cleanup_mkey(struct devx_obj *obj)
1097+
{
1098+
struct mlx5_mkey_table *table = &obj->mdev->priv.mkey_table;
1099+
struct mlx5_core_mkey *del_mkey;
1100+
unsigned long flags;
1101+
1102+
write_lock_irqsave(&table->lock, flags);
1103+
del_mkey = radix_tree_delete(&table->tree,
1104+
mlx5_base_mkey(obj->devx_mr.mmkey.key));
1105+
write_unlock_irqrestore(&table->lock, flags);
1106+
}
1107+
10401108
static int devx_obj_cleanup(struct ib_uobject *uobject,
10411109
enum rdma_remove_reason why)
10421110
{
10431111
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
10441112
struct devx_obj *obj = uobject->object;
10451113
int ret;
10461114

1115+
if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY)
1116+
devx_cleanup_mkey(obj);
1117+
10471118
ret = mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out, sizeof(out));
10481119
if (ib_is_destroy_retryable(ret, why, uobject))
10491120
return ret;
10501121

1122+
if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY) {
1123+
struct mlx5_ib_dev *dev = to_mdev(uobject->context->device);
1124+
1125+
call_srcu(&dev->mr_srcu, &obj->devx_mr.rcu,
1126+
devx_free_indirect_mkey);
1127+
return ret;
1128+
}
1129+
10511130
kfree(obj);
10521131
return ret;
10531132
}
@@ -1108,6 +1187,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
11081187
&obj_id);
11091188
WARN_ON(obj->dinlen > MLX5_MAX_DESTROY_INBOX_SIZE_DW * sizeof(u32));
11101189

1190+
if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY) {
1191+
err = devx_handle_mkey_indirect(obj, dev, cmd_in, cmd_out);
1192+
if (err)
1193+
goto obj_destroy;
1194+
}
1195+
11111196
err = uverbs_copy_to(attrs, MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, cmd_out, cmd_out_len);
11121197
if (err)
11131198
goto obj_destroy;
@@ -1116,6 +1201,8 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(
11161201
return 0;
11171202

11181203
obj_destroy:
1204+
if (obj->flags & DEVX_OBJ_FLAGS_INDIRECT_MKEY)
1205+
devx_cleanup_mkey(obj);
11191206
mlx5_cmd_exec(obj->mdev, obj->dinbox, obj->dinlen, out, sizeof(out));
11201207
obj_free:
11211208
kfree(obj);

drivers/infiniband/hw/mlx5/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5724,6 +5724,7 @@ void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
57245724
{
57255725
mlx5_ib_cleanup_multiport_master(dev);
57265726
if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
5727+
srcu_barrier(&dev->mr_srcu);
57275728
cleanup_srcu_struct(&dev->mr_srcu);
57285729
drain_workqueue(dev->advise_mr_wq);
57295730
destroy_workqueue(dev->advise_mr_wq);

drivers/infiniband/hw/mlx5/mlx5_ib.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,12 @@ struct mlx5_ib_mw {
602602
int ndescs;
603603
};
604604

605+
struct mlx5_ib_devx_mr {
606+
struct mlx5_core_mkey mmkey;
607+
int ndescs;
608+
struct rcu_head rcu;
609+
};
610+
605611
struct mlx5_ib_umr_context {
606612
struct ib_cqe cqe;
607613
enum ib_wc_status status;

include/linux/mlx5/driver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ struct mlx5_core_sig_ctx {
364364
enum {
365365
MLX5_MKEY_MR = 1,
366366
MLX5_MKEY_MW,
367+
MLX5_MKEY_INDIRECT_DEVX,
367368
};
368369

369370
struct mlx5_core_mkey {

0 commit comments

Comments
 (0)