Reorganize mlx5 UMR creation flow
Subsystems (2)
cover Reorganize mlx5 UMR creation flow
From: Leon Romanovsky <[email protected]>
This flow has become crufty and confusing. Revise it so that the rules on how UMR is used with MRs is much clearer and more correct.
Fixes a few minor bugs in ODP and rereg_mr where disallowed things were not properly blocked.
Thanks
Jason Gunthorpe (5):
RDMA/mlx5: Remove dead check for EAGAIN after alloc_mr_from_cache() RDMA/mlx5: Use set_mkc_access_pd_addr_fields() in reg_create() RDMA/mlx5: Make mkeys always owned by the kernel's PD when not enabled RDMA/mlx5: Disable IB_DEVICE_MEM_MGT_EXTENSIONS if IB_WR_REG_MR can't
work
RDMA/mlx5: Clarify what the UMR is for when creating MRs
drivers/infiniband/hw/mlx5/main.c | 4 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 45 +++++++-- drivers/infiniband/hw/mlx5/mr.c | 133 ++++++++++++++------------- drivers/infiniband/hw/mlx5/odp.c | 9 +- drivers/infiniband/hw/mlx5/wr.c | 27 +++--- 5 files changed, 127 insertions(+), 91 deletions(-)
--
2.26.2
PATCH 1/5 RDMA/mlx5: Remove dead check for EAGAIN after alloc_mr_from_cache()
From: Jason Gunthorpe <[email protected]>
alloc_mr_from_cache() no longer returns EAGAIN, this is just dead code now.
--- drivers/infiniband/hw/mlx5/mr.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +1 -3
@@ -1402,10 +1402,8 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,if (order <=mr_cache_max_order (dev) && use_umr) { mr =alloc_mr_from_cache (pd, umem, virt_addr, length, ncont, page_shift, order, access_flags); -if (PTR_ERR (mr) == -EAGAIN ) { -mlx5_ib_dbg (dev,"cache empty for order %d\n" , order); +if (IS_ERR (mr)) mr =NULL ; - } }else if (!MLX5_CAP_GEN (dev->mdev, umr_extended_translation_offset)) {if (access_flags &IB_ACCESS_ON_DEMAND ) { err = -EINVAL ;
Signature · 1 line
2.26.2
PATCH 2/5 RDMA/mlx5: Use set_mkc_access_pd_addr_fields() in reg_create()
In reply to Leon RomanovskyFrom: Jason Gunthorpe <[email protected]>
reg_create() open codes this helper, use the shared code.
--- drivers/infiniband/hw/mlx5/mr.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +1 -14
@@ -1199,29 +1199,16 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd,MLX5_SET (create_mkey_in, in, pg_access, !!(pg_cap)); mkc =MLX5_ADDR_OF (create_mkey_in, in, memory_key_mkey_entry); +set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, pd);MLX5_SET (mkc, mkc, free, !populate);MLX5_SET (mkc, mkc, access_mode_1_0,MLX5_MKC_ACCESS_MODE_MTT ); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) -MLX5_SET (mkc, mkc, relaxed_ordering_write, - !!(access_flags &IB_ACCESS_RELAXED_ORDERING )); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) -MLX5_SET (mkc, mkc, relaxed_ordering_read, - !!(access_flags &IB_ACCESS_RELAXED_ORDERING )); -MLX5_SET (mkc, mkc, a, !!(access_flags &IB_ACCESS_REMOTE_ATOMIC )); -MLX5_SET (mkc, mkc, rw, !!(access_flags &IB_ACCESS_REMOTE_WRITE )); -MLX5_SET (mkc, mkc, rr, !!(access_flags &IB_ACCESS_REMOTE_READ )); -MLX5_SET (mkc, mkc, lw, !!(access_flags &IB_ACCESS_LOCAL_WRITE )); -MLX5_SET (mkc, mkc, lr,1 );MLX5_SET (mkc, mkc, umr_en,1 ); -MLX5_SET64 (mkc, mkc, start_addr, virt_addr);MLX5_SET64 (mkc, mkc, len, length); -MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn);MLX5_SET (mkc, mkc, bsf_octword_size,0 );MLX5_SET (mkc, mkc, translations_octword_size,get_octo_len (virt_addr, length, page_shift));MLX5_SET (mkc, mkc, log_page_size, page_shift); -MLX5_SET (mkc, mkc, qpn,0xffffff );if (populate) {MLX5_SET (create_mkey_in, in, translations_octword_actual_size,get_octo_len (virt_addr, length, page_shift));
Signature · 1 line
2.26.2
PATCH 3/5 RDMA/mlx5: Make mkeys always owned by the kernel's PD when not enabled
In reply to Leon RomanovskyFrom: Jason Gunthorpe <[email protected]>
Any mkey that is not enabled and assigned to userspace should have the PD set to a kernel owned PD.
When cache entries are created for the first time the PDN is set to 0, which is probably a kernel PD, but be explicit.
When a MR is registered using the hybrid reg_create with UMR xlt & enable the disabled mkey is pointing at the user PD, keep it pointing at the kernel until a UMR enables it and sets the user PD.
--- drivers/infiniband/hw/mlx5/mr.c | 51 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 25 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +26 -25
@@ -52,6 +52,29 @@ enum {static void create_mkey_callback (int status,struct mlx5_async_work *context); +static void set_mkc_access_pd_addr_fields (void *mkc,int acc,u64 start_addr, +struct ib_pd *pd) +{ +struct mlx5_ib_dev *dev =to_mdev (pd->device); + +MLX5_SET (mkc, mkc, a, !!(acc &IB_ACCESS_REMOTE_ATOMIC )); +MLX5_SET (mkc, mkc, rw, !!(acc &IB_ACCESS_REMOTE_WRITE )); +MLX5_SET (mkc, mkc, rr, !!(acc &IB_ACCESS_REMOTE_READ )); +MLX5_SET (mkc, mkc, lw, !!(acc &IB_ACCESS_LOCAL_WRITE )); +MLX5_SET (mkc, mkc, lr,1 ); + +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) +MLX5_SET (mkc, mkc, relaxed_ordering_write, + !!(acc &IB_ACCESS_RELAXED_ORDERING )); +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) +MLX5_SET (mkc, mkc, relaxed_ordering_read, + !!(acc &IB_ACCESS_RELAXED_ORDERING )); + +MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn); +MLX5_SET (mkc, mkc, qpn,0xffffff ); +MLX5_SET64 (mkc, mkc, start_addr, start_addr); +} +static void assign_mkey_variant (struct mlx5_ib_dev *dev,struct mlx5_core_mkey *mkey,u32 *in)
@@ -154,12 +177,12 @@ static struct mlx5_ib_mr *alloc_cache_mr(struct mlx5_cache_ent *ent, void *mkc) mr->cache_ent = ent; mr->dev = ent->dev; +set_mkc_access_pd_addr_fields (mkc,0 ,0 , ent->dev->umrc.pd);MLX5_SET (mkc, mkc, free,1 );MLX5_SET (mkc, mkc, umr_en,1 );MLX5_SET (mkc, mkc, access_mode_1_0, ent->access_mode &0x3 );MLX5_SET (mkc, mkc, access_mode_4_2, (ent->access_mode >>2 ) &0x7 ); -MLX5_SET (mkc, mkc, qpn,0xffffff );MLX5_SET (mkc, mkc, translations_octword_size, ent->xlt);MLX5_SET (mkc, mkc, log_page_size, ent->page);return mr;
@@ -776,29 +799,6 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)return 0 ; } -static void set_mkc_access_pd_addr_fields (void *mkc,int acc,u64 start_addr, -struct ib_pd *pd) -{ -struct mlx5_ib_dev *dev =to_mdev (pd->device); - -MLX5_SET (mkc, mkc, a, !!(acc &IB_ACCESS_REMOTE_ATOMIC )); -MLX5_SET (mkc, mkc, rw, !!(acc &IB_ACCESS_REMOTE_WRITE )); -MLX5_SET (mkc, mkc, rr, !!(acc &IB_ACCESS_REMOTE_READ )); -MLX5_SET (mkc, mkc, lw, !!(acc &IB_ACCESS_LOCAL_WRITE )); -MLX5_SET (mkc, mkc, lr,1 ); - -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) -MLX5_SET (mkc, mkc, relaxed_ordering_write, - !!(acc &IB_ACCESS_RELAXED_ORDERING )); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) -MLX5_SET (mkc, mkc, relaxed_ordering_read, - !!(acc &IB_ACCESS_RELAXED_ORDERING )); - -MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn); -MLX5_SET (mkc, mkc, qpn,0xffffff ); -MLX5_SET64 (mkc, mkc, start_addr, start_addr); -} -struct ib_mr *mlx5_ib_get_dma_mr (struct ib_pd *pd,int acc) {struct mlx5_ib_dev *dev =to_mdev (pd->device);
@@ -1199,7 +1199,8 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd,MLX5_SET (create_mkey_in, in, pg_access, !!(pg_cap)); mkc =MLX5_ADDR_OF (create_mkey_in, in, memory_key_mkey_entry); -set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, pd); +set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, + populate ? pd : dev->umrc.pd);MLX5_SET (mkc, mkc, free, !populate);MLX5_SET (mkc, mkc, access_mode_1_0,MLX5_MKC_ACCESS_MODE_MTT );MLX5_SET (mkc, mkc, umr_en,1 );
Signature · 1 line
2.26.2
PATCH 4/5 RDMA/mlx5: Disable IB_DEVICE_MEM_MGT_EXTENSIONS if IB_WR_REG_MR can't work
In reply to Leon RomanovskyFrom: Jason Gunthorpe <[email protected]>
set_reg_wr() always fails if !umr_modify_entity_size_disabled because mlx5_ib_can_use_umr() always fails. Withotu set_reg_wr() IB_WR_REG_MR doesn't work and that means the device should not advertise IB_DEVICE_MEM_MGT_EXTENSIONS.
--- drivers/infiniband/hw/mlx5/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/main.c +3 -1
@@ -840,7 +840,9 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,/* We support 'Gappy' memory registration too */ props->device_cap_flags |=IB_DEVICE_SG_GAPS_REG ; } - props->device_cap_flags |=IB_DEVICE_MEM_MGT_EXTENSIONS ; +/* IB_WR_REG_MR always requires changing the entity size with UMR */ +if (!MLX5_CAP_GEN (dev->mdev, umr_modify_entity_size_disabled)) + props->device_cap_flags |=IB_DEVICE_MEM_MGT_EXTENSIONS ;if (MLX5_CAP_GEN (mdev, sho)) { props->device_cap_flags |=IB_DEVICE_INTEGRITY_HANDOVER ;/* At this stage no support for signature handover */
--
2.26.2
PATCH 5/5 RDMA/mlx5: Clarify what the UMR is for when creating MRs
In reply to Leon RomanovskyFrom: Jason Gunthorpe <[email protected]>
Once a mkey is created it can be modified using UMR. This is desirable for performance reasons. However, different hardware has restrictions on what modifications are possible using UMR. Make sense of these checks:
- mlx5_ib_can_reconfig_with_umr() returns true if the access flags can be altered. Most cases create MRs using 0 access flags (now made clear by consistent use of set_mkc_access_pd_addr_fields()), but the old logic here was tormented. Make it clear that this is checking if the current access_flags can be modified using UMR to different access_flags. It is always OK to use UMR to change flags that all HW supports.
- mlx5_ib_can_load_pas_with_umr() returns true if UMR can be used to enable and update the PAS/XLT. Enabling requires updating the entity size, so UMR ends up completely disabled on this old hardware. Make it clear why it is disabled. FRWR, ODP and cache always requires mlx5_ib_can_load_pas_with_umr().
- mlx5_ib_pas_fits_in_mr() is used to tell if an existing MR can be resized to hold a new PAS list. This only works for cached MR's because we don't store the PAS list size in other cases.
To be very clear, arrange things so any pre-created MR's in the cache check the newly requested access_flags before allowing the MR to leave the cache. If UMR cannot set the required access_flags the cache fails to create the MR.
This in turn means relaxed ordering and atomic are now correctly blocked early for implicit ODP on older HW.
--- drivers/infiniband/hw/mlx5/mlx5_ib.h | 45 +++++++++++++++---- drivers/infiniband/hw/mlx5/mr.c | 65 ++++++++++++++++++---------- drivers/infiniband/hw/mlx5/odp.c | 9 ++-- drivers/infiniband/hw/mlx5/wr.c | 27 ++++++------ 4 files changed, 97 insertions(+), 49 deletions(-)
drivers/infiniband/hw/mlx5/mlx5_ib.h +37 -8
@@ -1245,7 +1245,7 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev);int mlx5_mr_cache_cleanup (struct mlx5_ib_dev *dev);struct mlx5_ib_mr *mlx5_mr_cache_alloc (struct mlx5_ib_dev *dev, -unsigned int entry); +unsigned int entry,int access_flags);void mlx5_mr_cache_free (struct mlx5_ib_dev *dev,struct mlx5_ib_mr *mr);int mlx5_mr_cache_invalidate (struct mlx5_ib_mr *mr);
@@ -1458,25 +1458,54 @@ int bfregn_to_uar_index(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi, u32 bfregn, bool dyn_bfreg); -static inline bool mlx5_ib_can_use_umr (struct mlx5_ib_dev *dev, -bool do_modify_atomic,int access_flags) +static inline bool mlx5_ib_can_load_pas_with_umr (struct mlx5_ib_dev *dev, +size_t length) { +/* +* umr_check_mkey_mask() rejects MLX5_MKEY_MASK_PAGE_SIZE which is +* always set if MLX5_IB_SEND_UMR_UPDATE_TRANSLATION (aka +* MLX5_IB_UPD_XLT_ADDR and MLX5_IB_UPD_XLT_ENABLE) is set. Thus, a mkey +* can never be enabled without this capability. Simplify this weird +* quirky hardware by just saying it can't use PAS lists with UMR at +* all. +*/ if (MLX5_CAP_GEN (dev->mdev, umr_modify_entity_size_disabled))return false; -if (do_modify_atomic && +/* +* length is the size of the MR in bytes when mlx5_ib_update_xlt() is +* used. +*/ +if (!MLX5_CAP_GEN (dev->mdev, umr_extended_translation_offset) && + length >=MLX5_MAX_UMR_PAGES *PAGE_SIZE ) +return false; +return true; +} + +/* +* true if an existing MR can be reconfigured to new access_flags using UMR. +* Older HW cannot use UMR to update certain elements of the MKC. See +* umr_check_mkey_mask(), get_umr_update_access_mask() and umr_check_mkey_mask() +*/ +static inline bool mlx5_ib_can_reconfig_with_umr (struct mlx5_ib_dev *dev, +unsigned int current_access_flags, +unsigned int target_access_flags) +{ +unsigned int diffs = current_access_flags ^ target_access_flags; + +if ((diffs &IB_ACCESS_REMOTE_ATOMIC ) &&MLX5_CAP_GEN (dev->mdev, atomic) &&MLX5_CAP_GEN (dev->mdev, umr_modify_atomic_disabled))return false; -if (access_flags &IB_ACCESS_RELAXED_ORDERING && +if ((diffs &IB_ACCESS_RELAXED_ORDERING ) &&MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write) && !MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write_umr))return false; -if (access_flags &IB_ACCESS_RELAXED_ORDERING && -MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read) && - !MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read_umr)) +if ((diffs &IB_ACCESS_RELAXED_ORDERING ) && +MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read) && + !MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read_umr))return false;return true;
drivers/infiniband/hw/mlx5/mr.c +42 -23
161 lines not on this page · raw message
drivers/infiniband/hw/mlx5/odp.c +4 -5
@@ -382,7 +382,7 @@ void mlx5_ib_internal_fill_odp_caps(struct mlx5_ib_dev *dev)memset (caps,0 ,sizeof (*caps));if (!MLX5_CAP_GEN (dev->mdev, pg) || - !mlx5_ib_can_use_umr (dev, true,0 )) + !mlx5_ib_can_load_pas_with_umr (dev,0 ))return ; caps->general_caps =IB_ODP_SUPPORT ;
@@ -476,12 +476,12 @@ static struct mlx5_ib_mr *implicit_get_child_mr(struct mlx5_ib_mr *imr,if (IS_ERR (odp))return ERR_CAST (odp); - ret = mr =mlx5_mr_cache_alloc (imr->dev,MLX5_IMR_MTT_CACHE_ENTRY ); + ret = mr =mlx5_mr_cache_alloc (imr->dev,MLX5_IMR_MTT_CACHE_ENTRY , + imr->access_flags);if (IS_ERR (mr)) goto out_umem; mr->ibmr.pd = imr->ibmr.pd; - mr->access_flags = imr->access_flags; mr->umem = &odp->umem; mr->ibmr.lkey = mr->mmkey.key; mr->ibmr.rkey = mr->mmkey.key;
@@ -540,14 +540,13 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,if (IS_ERR (umem_odp))return ERR_CAST (umem_odp); - imr =mlx5_mr_cache_alloc (dev,MLX5_IMR_KSM_CACHE_ENTRY ); + imr =mlx5_mr_cache_alloc (dev,MLX5_IMR_KSM_CACHE_ENTRY , access_flags);if (IS_ERR (imr)) { err =PTR_ERR (imr); goto out_umem; } imr->ibmr.pd = &pd->ibpd; - imr->access_flags = access_flags; imr->mmkey.iova =0 ; imr->umem = &umem_odp->umem; imr->ibmr.lkey = imr->mmkey.key;
drivers/infiniband/hw/mlx5/wr.c +14 -13
@@ -398,7 +398,8 @@ static void set_linv_mkey_seg(struct mlx5_mkey_seg *seg) seg->status =MLX5_MKEY_STATUS_FREE ; } -static void set_reg_mkey_segment (struct mlx5_mkey_seg *seg, +static void set_reg_mkey_segment (struct mlx5_ib_dev *dev, +struct mlx5_mkey_seg *seg,const struct ib_send_wr *wr) {const struct mlx5_umr_wr *umrwr =umr_wr (wr);
@@ -414,10 +415,12 @@ static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg,MLX5_SET (mkc, seg, rr, !!(umrwr->access_flags &IB_ACCESS_REMOTE_READ ));MLX5_SET (mkc, seg, lw, !!(umrwr->access_flags &IB_ACCESS_LOCAL_WRITE ));MLX5_SET (mkc, seg, lr,1 ); -MLX5_SET (mkc, seg, relaxed_ordering_write, - !!(umrwr->access_flags &IB_ACCESS_RELAXED_ORDERING )); -MLX5_SET (mkc, seg, relaxed_ordering_read, - !!(umrwr->access_flags &IB_ACCESS_RELAXED_ORDERING )); +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write_umr)) +MLX5_SET (mkc, seg, relaxed_ordering_write, + !!(umrwr->access_flags &IB_ACCESS_RELAXED_ORDERING )); +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read_umr)) +MLX5_SET (mkc, seg, relaxed_ordering_read, + !!(umrwr->access_flags &IB_ACCESS_RELAXED_ORDERING ));if (umrwr->pd)MLX5_SET (mkc, seg, pd,to_mpd (umrwr->pd)->pdn);
@@ -863,13 +866,11 @@ static int set_reg_wr(struct mlx5_ib_qp *qp,bool atomic = wr->access &IB_ACCESS_REMOTE_ATOMIC ;u8 flags =0 ; -if (!mlx5_ib_can_use_umr (dev, atomic, wr->access)) { -mlx5_ib_warn (to_mdev (qp->ibqp.device), -"Fast update of %s for MR is disabled\n" , - (MLX5_CAP_GEN (dev->mdev, - umr_modify_entity_size_disabled)) ? -"entity size" : -"atomic access" ); +/* Matches access in mlx5_set_umr_free_mkey() */ +if (!mlx5_ib_can_reconfig_with_umr (dev,0 , wr->access)) { +mlx5_ib_warn ( +to_mdev (qp->ibqp.device), +"Fast update for MR access flags is not possible\n" );return -EINVAL ; }
@@ -1263,7 +1264,7 @@ static int handle_qpt_reg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, *seg +=sizeof (struct mlx5_wqe_umr_ctrl_seg ); *size +=sizeof (struct mlx5_wqe_umr_ctrl_seg ) /16 ;handle_post_send_edge (&qp->sq, seg, *size, cur_edge); -set_reg_mkey_segment (*seg, wr); +set_reg_mkey_segment (dev, *seg, wr); *seg +=sizeof (struct mlx5_mkey_seg ); *size +=sizeof (struct mlx5_mkey_seg ) /16 ;handle_post_send_edge (&qp->sq, seg, *size, cur_edge);
Signature · 1 line
2.26.2
Quoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
This flow has become crufty and confusing. Revise it so that the rules on how UMR is used with MRs is much clearer and more correct.
Fixes a few minor bugs in ODP and
rereg_mrwhere disallowed things were not properly blocked.Thanks
Quoted 7 lines
Jason Gunthorpe (5):
RDMA/mlx5: Remove dead check for EAGAIN afteralloc_mr_from_cache()RDMA/mlx5: Useset_mkc_access_pd_addr_fields()inreg_create()RDMA/mlx5: Make mkeys always owned by the kernel's PD when not enabled RDMA/mlx5: DisableIB_DEVICE_MEM_MGT_EXTENSIONSifIB_WR_REG_MRcan't
work
RDMA/mlx5: Clarify what the UMR is for when creating MRs
Applied to for-next
Jason