Introduce mlx5 Memory Scheme ODP
Subsystems (4)
v2 cover Introduce mlx5 Memory Scheme ODP
This series introduces a new ODP scheme in mlx5 where the FW takes the responsibility of parsing and providing page fault data to the driver to handle the fault.
As opposed to the current ODP transport scheme where the driver is responsible for reading and parsing work queues and querying mkeys to acquire needed info to handle the page fault.
The new scheme allows driver to support ODP over Devx QPs where driver is not able to access the QP buffers, owned by the user application, to read the work queue requests.
Furthermore, the new scheme allows support for ODP with new indirect MKEY types as the driver doesn't need to query or parse indirect mkeys in this scheme.
The driver will enable the new scheme on devices that have the relevant capabilities. Otherwise, transport scheme ODP will be the default.
The move to memory scheme ODP is transparent to existing ODP applications and no change is needed.
New application that want to take advantage of the new functionality should query which scheme is active and it's capabilities using Devx.
v1->v2:
- switch mlx5_umem_find_best_pgsz to a function and rename
Michael Guralnik (8):
net/mlx5: Expand mkey page size to support 6 bits net/mlx5: Expose HW bits for Memory scheme ODP RDMA/mlx5: Add new ODP memory scheme eqe format RDMA/mlx5: Enforce umem boundaries for explicit ODP page faults RDMA/mlx5: Split ODP mkey search logic
RDMA/mlx5: Add handling for memory scheme page fault events RDMA/mlx5: Add implicit MR handling to ODP memory scheme net/mlx5: Handle memory scheme ODP capabilities
drivers/infiniband/hw/mlx5/mlx5_ib.h | 30 +- drivers/infiniband/hw/mlx5/mr.c | 10 +- drivers/infiniband/hw/mlx5/odp.c | 400 ++++++++++++++---- .../net/ethernet/mellanox/mlx5/core/main.c | 54 ++- include/linux/mlx5/device.h | 30 +- include/linux/mlx5/mlx5_ifc.h | 64 ++- 6 files changed, 457 insertions(+), 131 deletions(-)
Signature · 1 line
2.17.2
PATCH v2 1/8 net/mlx5: Expand mkey page size to support 6 bits
Protect the usage of the 6th bit with the relevant capability to ensure we are using the new page sizes with FW that supports the bit extension.
--- drivers/infiniband/hw/mlx5/mlx5_ib.h | 27 ++++++++++++++++----------- drivers/infiniband/hw/mlx5/mr.c | 10 ++++------ drivers/infiniband/hw/mlx5/odp.c | 2 +- include/linux/mlx5/mlx5_ifc.h | 7 ++++--- 4 files changed, 25 insertions(+), 21 deletions(-)
drivers/infiniband/hw/mlx5/mlx5_ib.h +16 -11
@@ -63,17 +63,6 @@ __mlx5_log_page_size_to_bitmap(unsigned int log_pgsz_bits,return GENMASK (largest_pg_shift, pgsz_shift); } -/* -* For mkc users, instead of a page_offset the command has a start_iova which -* specifies both the page_offset and the on-the-wire IOVA -*/ -#define mlx5_umem_find_best_pgsz (umem, typ, log_pgsz_fld, pgsz_shift, iova) \ - ib_umem_find_best_pgsz(umem, \ - __mlx5_log_page_size_to_bitmap( \ - __mlx5_bit_sz(typ, log_pgsz_fld), \ - pgsz_shift), \ - iova) -static __always_inline unsigned long __mlx5_page_offset_to_bitmask (unsigned int page_offset_bits,unsigned int offset_shift)
@@ -1725,4 +1714,20 @@ static inline u32 smi_to_native_portnum(struct mlx5_ib_dev *dev, u32 port) return (port - 1) / dev->num_ports + 1; } +/* +* For mkc users, instead of a page_offset the command has a start_iova which +* specifies both the page_offset and the on-the-wire IOVA +*/ +static __always_inline unsigned long +mlx5_umem_mkc_find_best_pgsz (struct mlx5_ib_dev *dev,struct ib_umem *umem, +u64 iova) +{ +int page_size_bits = +MLX5_CAP_GEN_2 (dev->mdev, umr_log_entity_size_5) ?6 :5 ; +unsigned long bitmap = +__mlx5_log_page_size_to_bitmap (page_size_bits,0 ); + +return ib_umem_find_best_pgsz (umem, bitmap, iova); +} +#endif /* MLX5_IB_H */
drivers/infiniband/hw/mlx5/mr.c +4 -6
@@ -1119,8 +1119,7 @@ static struct mlx5_ib_mr *alloc_cacheable_mr(struct ib_pd *pd,if (umem->is_dmabuf) page_size =mlx5_umem_dmabuf_default_pgsz (umem, iova);else - page_size =mlx5_umem_find_best_pgsz (umem, mkc, log_page_size, -0 , iova); + page_size =mlx5_umem_mkc_find_best_pgsz (dev, umem, iova);if (WARN_ON (!page_size))return ERR_PTR (-EINVAL );
@@ -1425,8 +1424,8 @@ static struct ib_mr *create_real_mr(struct ib_pd *pd, struct ib_umem *umem, mr =alloc_cacheable_mr (pd, umem, iova, access_flags,MLX5_MKC_ACCESS_MODE_MTT ); }else { -unsigned int page_size =mlx5_umem_find_best_pgsz ( - umem, mkc, log_page_size,0 , iova); +unsigned int page_size = +mlx5_umem_mkc_find_best_pgsz (dev, umem, iova);mutex_lock (&dev->slow_path_mutex); mr = reg_create(pd, umem, iova, access_flags, page_size,
@@ -1744,8 +1743,7 @@ static bool can_use_umr_rereg_pas(struct mlx5_ib_mr *mr,if (!mlx5r_umr_can_load_pas (dev, new_umem->length))return false; - *page_size = -mlx5_umem_find_best_pgsz (new_umem, mkc, log_page_size,0 , iova); + *page_size =mlx5_umem_mkc_find_best_pgsz (dev, new_umem, iova);if (WARN_ON (!*page_size))return false; return (mr->mmkey.cache_ent->rb_key.ndescs) >=
drivers/infiniband/hw/mlx5/odp.c +1 -1
@@ -693,7 +693,7 @@ static int pagefault_dmabuf_mr(struct mlx5_ib_mr *mr, size_t bcnt,struct ib_umem_dmabuf *umem_dmabuf =to_ib_umem_dmabuf (mr->umem);u32 xlt_flags =0 ;int err; -unsigned int page_size; +unsigned long page_size;if (flags &MLX5_PF_FLAGS_ENABLE ) xlt_flags |=MLX5_IB_UPD_XLT_ENABLE ;
include/linux/mlx5/mlx5_ifc.h +4 -3
@@ -1995,7 +1995,9 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {u8 dp_ordering_force[0x1 ];u8 reserved_at_89[0x9 ];u8 query_vuid[0x1 ]; -u8 reserved_at_93[0xd ]; +u8 reserved_at_93[0x5 ]; +u8 umr_log_entity_size_5[0x1 ]; +u8 reserved_at_99[0x7 ];u8 max_reformat_insert_size[0x8 ];u8 max_reformat_insert_offset[0x8 ];
@@ -4221,8 +4223,7 @@ struct mlx5_ifc_mkc_bits {u8 reserved_at_1c0[0x19 ];u8 relaxed_ordering_read[0x1 ]; -u8 reserved_at_1d9[0x1 ]; -u8 log_page_size[0x5 ]; +u8 log_page_size[0x6 ];u8 reserved_at_1e0[0x20 ]; };
Signature · 1 line
2.17.2
PATCH v2 2/8 net/mlx5: Expose HW bits for Memory scheme ODP
In reply to Michael GuralnikExpose IFC bits to support the new memory scheme on demand paging. Change the macro reading odp capabilities to be able to read from the new IFC layout and align the code in upper layers to be compiled.
--- drivers/infiniband/hw/mlx5/odp.c | 40 +++++++------ .../net/ethernet/mellanox/mlx5/core/main.c | 28 ++++----- include/linux/mlx5/device.h | 4 ++ include/linux/mlx5/mlx5_ifc.h | 57 +++++++++++++++---- 4 files changed, 86 insertions(+), 43 deletions(-)
drivers/infiniband/hw/mlx5/odp.c +22 -18
@@ -332,46 +332,46 @@ static void internal_fill_odp_caps(struct mlx5_ib_dev *dev)else dev->odp_max_size =BIT_ULL (MLX5_MAX_UMR_SHIFT +PAGE_SHIFT ); -if (MLX5_CAP_ODP (dev->mdev, ud_odp_caps.send)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, ud_odp_caps.send)) caps->per_transport_caps.ud_odp_caps |=IB_ODP_SUPPORT_SEND ; -if (MLX5_CAP_ODP (dev->mdev, ud_odp_caps.srq_receive)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, ud_odp_caps.srq_receive)) caps->per_transport_caps.ud_odp_caps |=IB_ODP_SUPPORT_SRQ_RECV ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.send)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.send)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_SEND ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.receive)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.receive)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_RECV ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.write)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.write)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_WRITE ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.read)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.read)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_READ ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.atomic)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.atomic)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_ATOMIC ; -if (MLX5_CAP_ODP (dev->mdev, rc_odp_caps.srq_receive)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, rc_odp_caps.srq_receive)) caps->per_transport_caps.rc_odp_caps |=IB_ODP_SUPPORT_SRQ_RECV ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.send)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.send)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_SEND ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.receive)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.receive)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_RECV ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.write)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.write)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_WRITE ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.read)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.read)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_READ ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.atomic)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.atomic)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_ATOMIC ; -if (MLX5_CAP_ODP (dev->mdev, xrc_odp_caps.srq_receive)) +if (MLX5_CAP_ODP_SCHEME (dev->mdev, xrc_odp_caps.srq_receive)) caps->per_transport_caps.xrc_odp_caps |=IB_ODP_SUPPORT_SRQ_RECV ; if (MLX5_CAP_GEN(dev->mdev, fixed_buffer_size) &&
@@ -388,13 +388,17 @@ static void mlx5_ib_page_fault_resume(struct mlx5_ib_dev *dev,int wq_num = pfault->event_subtype ==MLX5_PFAULT_SUBTYPE_WQE ? pfault->wqe.wq_num : pfault->token;u32 in[MLX5_ST_SZ_DW (page_fault_resume_in)] = {}; +void *info;int err;MLX5_SET (page_fault_resume_in, in, opcode,MLX5_CMD_OP_PAGE_FAULT_RESUME ); -MLX5_SET (page_fault_resume_in, in, page_fault_type, pfault->type); -MLX5_SET (page_fault_resume_in, in, token, pfault->token); -MLX5_SET (page_fault_resume_in, in, wq_number, wq_num); -MLX5_SET (page_fault_resume_in, in, error, !!error); + + info =MLX5_ADDR_OF (page_fault_resume_in, in, + page_fault_info.trans_page_fault_info); +MLX5_SET (trans_page_fault_info, info, page_fault_type, pfault->type); +MLX5_SET (trans_page_fault_info, info, fault_token, pfault->token); +MLX5_SET (trans_page_fault_info, info, wq_number, wq_num); +MLX5_SET (trans_page_fault_info, info, error, !!error); err =mlx5_cmd_exec_in (dev->mdev, page_fault_resume, in);if (err)
drivers/net/ethernet/mellanox/mlx5/core/main.c +14 -14
@@ -479,20 +479,20 @@ static int handle_hca_cap_odp(struct mlx5_core_dev *dev, void *set_ctx) } \ }while (0 ) -ODP_CAP_SET_MAX (dev, ud_odp_caps.srq_receive); -ODP_CAP_SET_MAX (dev, rc_odp_caps.srq_receive); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.srq_receive); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.send); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.receive); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.write); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.read); -ODP_CAP_SET_MAX (dev, xrc_odp_caps.atomic); -ODP_CAP_SET_MAX (dev, dc_odp_caps.srq_receive); -ODP_CAP_SET_MAX (dev, dc_odp_caps.send); -ODP_CAP_SET_MAX (dev, dc_odp_caps.receive); -ODP_CAP_SET_MAX (dev, dc_odp_caps.write); -ODP_CAP_SET_MAX (dev, dc_odp_caps.read); -ODP_CAP_SET_MAX (dev, dc_odp_caps.atomic); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.ud_odp_caps.srq_receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.rc_odp_caps.srq_receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.srq_receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.send); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.write); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.read); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.xrc_odp_caps.atomic); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.srq_receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.send); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.receive); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.write); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.read); +ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.atomic);if (!do_set)return 0 ;
include/linux/mlx5/device.h +4 -0
@@ -1369,6 +1369,10 @@ enum mlx5_qcam_feature_groups {#define MLX5_CAP_ODP (mdev, cap)\ MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, cap) +#define MLX5_CAP_ODP_SCHEME (mdev, cap) \ + MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, \ + transport_page_fault_scheme_cap.cap) +#define MLX5_CAP_ODP_MAX (mdev, cap)\ MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->max, cap)
include/linux/mlx5/mlx5_ifc.h +46 -11
90 lines not on this page · raw message
Signature · 1 line
2.17.2
PATCH v2 3/8 RDMA/mlx5: Add new ODP memory scheme eqe format
In reply to Michael GuralnikAdd new fields to support the new memory scheme page fault and extend the token field to u64 as in the new scheme the token is 48 bit.
--- drivers/infiniband/hw/mlx5/odp.c | 48 +++++++++++++++++++------------- include/linux/mlx5/device.h | 22 ++++++++++++++- 2 files changed, 50 insertions(+), 20 deletions(-)
drivers/infiniband/hw/mlx5/odp.c +29 -19
@@ -45,7 +45,7 @@/* Contains the details of a pagefault. */ struct mlx5_pagefault {u32 bytes_committed; -u32 token; +u64 token;u8 event_subtype;u8 type;union {
@@ -74,6 +74,14 @@ struct mlx5_pagefault {u32 rdma_op_len;u64 rdma_va; } rdma; +struct { +u64 va; +u32 mkey; +u32 fault_byte_count; +u32 prefetch_before_byte_count; +u32 prefetch_after_byte_count; +u8 flags; + } memory; };struct mlx5_ib_pf_eq *eq;
@@ -1273,7 +1281,7 @@ static void mlx5_ib_mr_wqe_pfault_handler(struct mlx5_ib_dev *dev,if (ret)mlx5_ib_err ( dev, -"Failed reading a WQE following page fault, error %d, wqe_index %x, qpn %x\n" , +"Failed reading a WQE following page fault, error %d, wqe_index %x, qpn %llx\n" , ret, wqe_index, pfault->token); resolve_page_fault:
@@ -1332,13 +1340,13 @@ static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev, }else if (ret <0 ||pages_in_range (address, length) > ret) {mlx5_ib_page_fault_resume (dev, pfault,1 );if (ret != -ENOENT ) -mlx5_ib_dbg (dev,"PAGE FAULT error %d. QP 0x%x, type: 0x%x\n" , +mlx5_ib_dbg (dev,"PAGE FAULT error %d. QP 0x%llx, type: 0x%x\n" , ret, pfault->token, pfault->type);return ; }mlx5_ib_page_fault_resume (dev, pfault,0 ); -mlx5_ib_dbg (dev,"PAGE FAULT completed. QP 0x%x, type: 0x%x, prefetch_activated: %d\n" , +mlx5_ib_dbg (dev,"PAGE FAULT completed. QP 0x%llx, type: 0x%x, prefetch_activated: %d\n" , pfault->token, pfault->type, prefetch_activated);
@@ -1354,7 +1362,7 @@ static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev, prefetch_len, &bytes_committed, NULL);if (ret <0 && ret != -EAGAIN ) { -mlx5_ib_dbg (dev,"Prefetch failed. ret: %d, QP 0x%x, address: 0x%.16llx, length = 0x%.16x\n" , +mlx5_ib_dbg (dev,"Prefetch failed. ret: %d, QP 0x%llx, address: 0x%.16llx, length = 0x%.16x\n" , ret, pfault->token, address, prefetch_len); } }
@@ -1405,15 +1413,12 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq) pf_eqe = &eqe->data.page_fault; pfault->event_subtype = eqe->sub_type; - pfault->bytes_committed =be32_to_cpu (pf_eqe->bytes_committed); - -mlx5_ib_dbg (eq->dev, -"PAGE_FAULT: subtype: 0x%02x, bytes_committed: 0x%06x\n" , - eqe->sub_type, pfault->bytes_committed);switch (eqe->sub_type) {case MLX5_PFAULT_SUBTYPE_RDMA :/* RDMA based event */ + pfault->bytes_committed = +be32_to_cpu (pf_eqe->rdma.bytes_committed); pfault->type =be32_to_cpu (pf_eqe->rdma.pftype_token) >>24 ; pfault->token =
@@ -1427,10 +1432,12 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq)be32_to_cpu (pf_eqe->rdma.rdma_op_len); pfault->rdma.rdma_va =be64_to_cpu (pf_eqe->rdma.rdma_va); -mlx5_ib_dbg (eq->dev, -"PAGE_FAULT: type:0x%x, token: 0x%06x, r_key: 0x%08x\n" , - pfault->type, pfault->token, - pfault->rdma.r_key); +mlx5_ib_dbg ( + eq->dev, +"PAGE_FAULT: subtype: 0x%02x, bytes_committed: 0x%06x, type:0x%x, token: 0x%06llx, r_key: 0x%08x\n" , + eqe->sub_type, pfault->bytes_committed, + pfault->type, pfault->token, + pfault->rdma.r_key); mlx5_ib_dbg(eq->dev, "PAGE_FAULT: rdma_op_len: 0x%08x, rdma_va: 0x%016llx\n", pfault->rdma.rdma_op_len,
@@ -1439,6 +1446,8 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq)case MLX5_PFAULT_SUBTYPE_WQE :/* WQE based event */ + pfault->bytes_committed = +be32_to_cpu (pf_eqe->wqe.bytes_committed); pfault->type = (be32_to_cpu (pf_eqe->wqe.pftype_wq) >>24 ) &0x7 ; pfault->token =
@@ -1450,11 +1459,12 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq)be16_to_cpu (pf_eqe->wqe.wqe_index); pfault->wqe.packet_size =be16_to_cpu (pf_eqe->wqe.packet_length); -mlx5_ib_dbg (eq->dev, -"PAGE_FAULT: type:0x%x, token: 0x%06x, wq_num: 0x%06x, wqe_index: 0x%04x\n" , - pfault->type, pfault->token, - pfault->wqe.wq_num, - pfault->wqe.wqe_index); +mlx5_ib_dbg ( + eq->dev, +"PAGE_FAULT: subtype: 0x%02x, bytes_committed: 0x%06x, type:0x%x, token: 0x%06llx, wq_num: 0x%06x, wqe_index: 0x%04x\n" , + eqe->sub_type, pfault->bytes_committed, + pfault->type, pfault->token, pfault->wqe.wq_num, + pfault->wqe.wqe_index);break ;default :
include/linux/mlx5/device.h +21 -1
@@ -211,6 +211,7 @@ enum {enum {MLX5_PFAULT_SUBTYPE_WQE =0 ,MLX5_PFAULT_SUBTYPE_RDMA =1 , +MLX5_PFAULT_SUBTYPE_MEMORY =2 , };enum wqe_page_fault_type {
@@ -646,10 +647,11 @@ struct mlx5_eqe_page_req {__be32 rsvd1[5 ]; }; +#define MEMORY_SCHEME_PAGE_FAULT_GRANULARITY 4096 struct mlx5_eqe_page_fault { - __be32 bytes_committed; union { struct { + __be32 bytes_committed; u16 reserved1; __be16 wqe_index; u16 reserved2;
@@ -659,6 +661,7 @@ struct mlx5_eqe_page_fault {__be32 pftype_wq; }__packed wqe;struct { +__be32 bytes_committed;__be32 r_key;u16 reserved1;__be16 packet_length;
@@ -666,6 +669,23 @@ struct mlx5_eqe_page_fault {__be64 rdma_va;__be32 pftype_token; }__packed rdma; +struct { +u8 flags; +u8 reserved1; +__be16 post_demand_fault_pages; +__be16 pre_demand_fault_pages; +__be16 token47_32; +__be32 token31_0; +/* +* FW changed from specifying the fault size in byte +* count to 4k pages granularity. The size specified +* in pages uses bits 31:12, to keep backward +* compatibility. +*/ +__be32 demand_fault_pages; +__be32 mkey; +__be64 va; + } __packed memory; } __packed; } __packed;
Signature · 1 line
2.17.2
PATCH v2 4/8 RDMA/mlx5: Enforce umem boundaries for explicit ODP page faults
In reply to Michael GuralnikThe new memory scheme page faults are requesting the driver to fetch additinal pages to the faulted memory access.
This is done in order to prefetch pages before and after the area that got the page fault, assuming this will reduce the total amount of page faults.
The driver should ensure it handles only the pages that are within the umem range.
--- drivers/infiniband/hw/mlx5/odp.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
drivers/infiniband/hw/mlx5/odp.c +16 -9
@@ -748,24 +748,31 @@ static int pagefault_dmabuf_mr(struct mlx5_ib_mr *mr, size_t bcnt,* >0: Number of pages mapped */ static int pagefault_mr (struct mlx5_ib_mr *mr,u64 io_virt,size_t bcnt, -u32 *bytes_mapped,u32 flags) +u32 *bytes_mapped,u32 flags,bool permissive_fault) {struct ib_umem_odp *odp =to_ib_umem_odp (mr->umem); -if (unlikely (io_virt < mr->ibmr.iova)) +if (unlikely (io_virt < mr->ibmr.iova) && !permissive_fault)return -EFAULT ;if (mr->umem->is_dmabuf)return pagefault_dmabuf_mr (mr, bcnt, bytes_mapped, flags);if (!odp->is_implicit_odp) { +u64 offset = io_virt < mr->ibmr.iova ?0 : io_virt - mr->ibmr.iova;u64 user_va; -if (check_add_overflow (io_virt - mr->ibmr.iova, - (u64 )odp->umem.address, &user_va)) +if (check_add_overflow (offset, (u64 )odp->umem.address, + &user_va))return -EFAULT ; -if (unlikely (user_va >=ib_umem_end (odp) || -ib_umem_end (odp) - user_va < bcnt)) + +if (permissive_fault) { +if (user_va <ib_umem_start (odp)) + user_va =ib_umem_start (odp); +if ((user_va + bcnt) >ib_umem_end (odp)) + bcnt =ib_umem_end (odp) - user_va; + }else if (unlikely (user_va >=ib_umem_end (odp) || +ib_umem_end (odp) - user_va < bcnt))return -EFAULT ;return pagefault_real_mr (mr, odp, user_va, bcnt, bytes_mapped, flags);
@@ -872,7 +879,7 @@ static int pagefault_single_data_segment(struct mlx5_ib_dev *dev,case MLX5_MKEY_MR : mr = container_of(mmkey, struct mlx5_ib_mr, mmkey); - ret =pagefault_mr (mr, io_virt, bcnt, bytes_mapped,0 ); + ret =pagefault_mr (mr, io_virt, bcnt, bytes_mapped,0 , false);if (ret <0 ) goto end;
@@ -1727,7 +1734,7 @@ static void mlx5_ib_prefetch_mr_work(struct work_struct *w)for (i =0 ; i < work->num_sge; ++i) { ret =pagefault_mr (work->frags[i].mr, work->frags[i].io_virt, work->frags[i].length, &bytes_mapped, - work->pf_flags); + work->pf_flags, false);if (ret <=0 )continue ;mlx5_update_odp_stats (work->frags[i].mr, prefetch, ret);
@@ -1778,7 +1785,7 @@ static int mlx5_ib_prefetch_sg_list(struct ib_pd *pd,if (IS_ERR (mr))return PTR_ERR (mr); ret =pagefault_mr (mr, sg_list[i].addr, sg_list[i].length, - &bytes_mapped, pf_flags); + &bytes_mapped, pf_flags, false);if (ret <0 ) {mlx5r_deref_odp_mkey (&mr->mmkey);return ret;
Signature · 1 line
2.17.2
PATCH v2 5/8 RDMA/mlx5: Split ODP mkey search logic
In reply to Michael GuralnikSplit the search for the ODP mkey when handling an rdma type page fault to a helper function, later to be used in other page fault types.
--- drivers/infiniband/hw/mlx5/odp.c | 65 +++++++++++++++++++------------- 1 file changed, 39 insertions(+), 26 deletions(-)
drivers/infiniband/hw/mlx5/odp.c +39 -26
@@ -819,6 +819,27 @@ static bool mkey_is_eq(struct mlx5_ib_mkey *mmkey, u32 key)return mmkey->key == key; } +static struct mlx5_ib_mkey *find_odp_mkey (struct mlx5_ib_dev *dev,u32 key) +{ +struct mlx5_ib_mkey *mmkey; + +xa_lock (&dev->odp_mkeys); + mmkey =xa_load (&dev->odp_mkeys,mlx5_base_mkey (key)); +if (!mmkey) { + mmkey =ERR_PTR (-ENOENT ); + goto out; + } +if (!mkey_is_eq (mmkey, key)) { + mmkey =ERR_PTR (-EFAULT ); + goto out; + } +refcount_inc (&mmkey->usecount); +out: +xa_unlock (&dev->odp_mkeys); + +return mmkey; +} +/* * Handle a single data segment in a page-fault WQE or RDMA region. *
@@ -846,32 +867,24 @@ static int pagefault_single_data_segment(struct mlx5_ib_dev *dev, io_virt += *bytes_committed; bcnt -= *bytes_committed; - next_mr: -xa_lock (&dev->odp_mkeys); - mmkey =xa_load (&dev->odp_mkeys,mlx5_base_mkey (key)); -if (!mmkey) { -xa_unlock (&dev->odp_mkeys); -mlx5_ib_dbg ( - dev, -"skipping non ODP MR (lkey=0x%06x) in page fault handler.\n" , - key); -if (bytes_mapped) - *bytes_mapped += bcnt; -/* -* The user could specify a SGL with multiple lkeys and only -* some of them are ODP. Treat the non-ODP ones as fully -* faulted. -*/ - ret =0 ; - goto end; - } -refcount_inc (&mmkey->usecount); -xa_unlock (&dev->odp_mkeys); - -if (!mkey_is_eq (mmkey, key)) { -mlx5_ib_dbg (dev,"failed to find mkey %x\n" , key); - ret = -EFAULT ; + mmkey =find_odp_mkey (dev, key); +if (IS_ERR (mmkey)) { + ret =PTR_ERR (mmkey); +if (ret == -ENOENT ) { +mlx5_ib_dbg ( + dev, +"skipping non ODP MR (lkey=0x%06x) in page fault handler.\n" , + key); +if (bytes_mapped) + *bytes_mapped += bcnt; +/* +* The user could specify a SGL with multiple lkeys and +* only some of them are ODP. Treat the non-ODP ones as +* fully faulted. +*/ + ret =0 ; + } goto end; }
@@ -966,7 +979,7 @@ static int pagefault_single_data_segment(struct mlx5_ib_dev *dev, } end: -if (mmkey) +if (!IS_ERR (mmkey))mlx5r_deref_odp_mkey (mmkey);while (head) { frame = head;
Signature · 1 line
2.17.2
PATCH v2 6/8 RDMA/mlx5: Add handling for memory scheme page fault events
In reply to Michael GuralnikThe memory scheme page fault event is a new approch in handling page fault on mkeys using the on-demand-paging feature.
The major shift in handling the page fault in this scheme is that the HW is taking responsibilty for parsing the faulted mkey instead of the previous approach where the driver would read and parse the wqes and query the mkeys to get to the direct mkey that we need to handle.
Therefore, the event we get from FW in this scheme will contain the direct mkey and address we need to handle and require much less work from driver.
Additionally, to optimize performance, the FW can generate the event on a memory area that is larger than the faulted memory operation is requiring, to 'prefetch' memory that is around it and will likely be used soon.
Unlike previous types of page fault, the memory page scheme fault does not always require a resume command after handling the page fault as the FW can post multiple events on same mkey and will set the 'last' flag only on the page fault that requires the resume command.
--- drivers/infiniband/hw/mlx5/odp.c | 120 +++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 6 deletions(-)
drivers/infiniband/hw/mlx5/odp.c +114 -6
@@ -401,12 +401,24 @@ static void mlx5_ib_page_fault_resume(struct mlx5_ib_dev *dev,MLX5_SET (page_fault_resume_in, in, opcode,MLX5_CMD_OP_PAGE_FAULT_RESUME ); - info =MLX5_ADDR_OF (page_fault_resume_in, in, - page_fault_info.trans_page_fault_info); -MLX5_SET (trans_page_fault_info, info, page_fault_type, pfault->type); -MLX5_SET (trans_page_fault_info, info, fault_token, pfault->token); -MLX5_SET (trans_page_fault_info, info, wq_number, wq_num); -MLX5_SET (trans_page_fault_info, info, error, !!error); +if (pfault->event_subtype ==MLX5_PFAULT_SUBTYPE_MEMORY ) { + info =MLX5_ADDR_OF (page_fault_resume_in, in, + page_fault_info.mem_page_fault_info); +MLX5_SET (mem_page_fault_info, info, fault_token_31_0, + pfault->token &0xffffffff ); +MLX5_SET (mem_page_fault_info, info, fault_token_47_32, + (pfault->token >>32 ) &0xffff ); +MLX5_SET (mem_page_fault_info, info, error, !!error); + }else { + info =MLX5_ADDR_OF (page_fault_resume_in, in, + page_fault_info.trans_page_fault_info); +MLX5_SET (trans_page_fault_info, info, page_fault_type, + pfault->type); +MLX5_SET (trans_page_fault_info, info, fault_token, + pfault->token); +MLX5_SET (trans_page_fault_info, info, wq_number, wq_num); +MLX5_SET (trans_page_fault_info, info, error, !!error); + } err =mlx5_cmd_exec_in (dev->mdev, page_fault_resume, in);if (err)
@@ -1388,6 +1400,63 @@ static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev, } } +#define MLX5_MEMORY_PAGE_FAULT_FLAGS_LAST BIT(7) +static void mlx5_ib_mr_memory_pfault_handler (struct mlx5_ib_dev *dev, +struct mlx5_pagefault *pfault) +{ +u64 prefetch_va = + pfault->memory.va - pfault->memory.prefetch_before_byte_count; +size_t prefetch_size = pfault->memory.prefetch_before_byte_count + + pfault->memory.fault_byte_count + + pfault->memory.prefetch_after_byte_count; +struct mlx5_ib_mkey *mmkey; +struct mlx5_ib_mr *mr; +int ret =0 ; + + mmkey =find_odp_mkey (dev, pfault->memory.mkey); +if (IS_ERR (mmkey)) + goto err; + + mr = container_of(mmkey, struct mlx5_ib_mr, mmkey); + +/* If prefetch fails, handle only demanded page fault */ + ret =pagefault_mr (mr, prefetch_va, prefetch_size,NULL ,0 , true); +if (ret <0 ) { + ret =pagefault_mr (mr, pfault->memory.va, + pfault->memory.fault_byte_count,NULL ,0 , + true); +if (ret <0 ) + goto err; + } + +mlx5_update_odp_stats (mr, faults, ret); +mlx5r_deref_odp_mkey (mmkey); + +if (pfault->memory.flags &MLX5_MEMORY_PAGE_FAULT_FLAGS_LAST ) +mlx5_ib_page_fault_resume (dev, pfault,0 ); + +mlx5_ib_dbg ( + dev, +"PAGE FAULT completed %s. token 0x%llx, mkey: 0x%x, va: 0x%llx, byte_count: 0x%x\n" , + pfault->memory.flags &MLX5_MEMORY_PAGE_FAULT_FLAGS_LAST ? +"" : +"without resume cmd" , + pfault->token, pfault->memory.mkey, pfault->memory.va, + pfault->memory.fault_byte_count); + +return ; + +err: +if (!IS_ERR (mmkey)) +mlx5r_deref_odp_mkey (mmkey); +mlx5_ib_page_fault_resume (dev, pfault,1 ); +mlx5_ib_dbg ( + dev, +"PAGE FAULT error. token 0x%llx, mkey: 0x%x, va: 0x%llx, byte_count: 0x%x, err: %d\n" , + pfault->token, pfault->memory.mkey, pfault->memory.va, + pfault->memory.fault_byte_count, ret); +} +static void mlx5_ib_pfault (struct mlx5_ib_dev *dev,struct mlx5_pagefault *pfault) {u8 event_subtype = pfault->event_subtype;
@@ -1399,6 +1468,9 @@ static void mlx5_ib_pfault(struct mlx5_ib_dev *dev, struct mlx5_pagefault *pfaulcase MLX5_PFAULT_SUBTYPE_RDMA :mlx5_ib_mr_rdma_pfault_handler (dev, pfault);break ; +case MLX5_PFAULT_SUBTYPE_MEMORY : +mlx5_ib_mr_memory_pfault_handler (dev, pfault); +break ;default :mlx5_ib_err (dev,"Invalid page fault event subtype: 0x%x\n" , event_subtype);
@@ -1417,6 +1489,7 @@ static void mlx5_ib_eqe_pf_action(struct work_struct *work)mempool_free (pfault, eq->pool); } +#define MEMORY_SCHEME_PAGE_FAULT_GRANULARITY 4096static void mlx5_ib_eq_pf_process (struct mlx5_ib_pf_eq *eq) {struct mlx5_eqe_page_fault *pf_eqe;
@@ -1487,6 +1560,41 @@ static void mlx5_ib_eq_pf_process(struct mlx5_ib_pf_eq *eq) pfault->wqe.wqe_index);break ; +case MLX5_PFAULT_SUBTYPE_MEMORY : +/* Memory based event */ + pfault->bytes_committed =0 ; + pfault->token = +be32_to_cpu (pf_eqe->memory.token31_0) | + ((u64 )be16_to_cpu (pf_eqe->memory.token47_32) + <<32 ); + pfault->memory.va =be64_to_cpu (pf_eqe->memory.va); + pfault->memory.mkey =be32_to_cpu (pf_eqe->memory.mkey); + pfault->memory.fault_byte_count = (be32_to_cpu ( + pf_eqe->memory.demand_fault_pages) >>12 ) * +MEMORY_SCHEME_PAGE_FAULT_GRANULARITY ; + pfault->memory.prefetch_before_byte_count = +be16_to_cpu ( + pf_eqe->memory.pre_demand_fault_pages) * +MEMORY_SCHEME_PAGE_FAULT_GRANULARITY ; + pfault->memory.prefetch_after_byte_count = +be16_to_cpu ( + pf_eqe->memory.post_demand_fault_pages) * +MEMORY_SCHEME_PAGE_FAULT_GRANULARITY ; + pfault->memory.flags = pf_eqe->memory.flags; +mlx5_ib_dbg ( + eq->dev, +"PAGE_FAULT: subtype: 0x%02x, token: 0x%06llx, mkey: 0x%06x, fault_byte_count: 0x%06x, va: 0x%016llx, flags: 0x%02x\n" , + eqe->sub_type, pfault->token, + pfault->memory.mkey, + pfault->memory.fault_byte_count, + pfault->memory.va, pfault->memory.flags); +mlx5_ib_dbg ( + eq->dev, +"PAGE_FAULT: prefetch size: before: 0x%06x, after 0x%06x\n" , + pfault->memory.prefetch_before_byte_count, + pfault->memory.prefetch_after_byte_count); +break ; +default : mlx5_ib_warn(eq->dev, "Unsupported page fault event sub-type: 0x%02hhx\n",
Signature · 1 line
2.17.2
PATCH v2 7/8 RDMA/mlx5: Add implicit MR handling to ODP memory scheme
In reply to Michael GuralnikImplicit MRs in ODP memory scheme require allocating a private null mkey and assigning the mkey and va differently in the KSM mkey. The page faults are received on the null mkey so we also add storing the null mkey in the odp_mkey xarray.
--- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 + drivers/infiniband/hw/mlx5/odp.c | 116 +++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 8 deletions(-)
drivers/infiniband/hw/mlx5/mlx5_ib.h +3 -0
@@ -630,6 +630,8 @@ enum mlx5_mkey_type {MLX5_MKEY_MR =1 ,MLX5_MKEY_MW ,MLX5_MKEY_INDIRECT_DEVX , +MLX5_MKEY_NULL , + MLX5_MKEY_IMPLICIT_CHILD, }; struct mlx5r_cache_rb_key {
@@ -715,6 +717,7 @@ struct mlx5_ib_mr {struct mlx5_ib_mr *dd_crossed_mr;struct list_head dd_node; u8 revoked :1; +struct mlx5_ib_mkey null_mmkey; }; }; };
drivers/infiniband/hw/mlx5/odp.c +108 -8
180 lines not on this page · raw message
Signature · 1 line
2.17.2
PATCH v2 8/8 net/mlx5: Handle memory scheme ODP capabilities
In reply to Michael GuralnikWhen running over new FW that supports the new memory scheme ODP, set the cap in the FW to signal the FW we are working in the new scheme.
In the memory scheme ODP the per_transport_service capabilities are RO for the driver so we skip their setting.
--- .../net/ethernet/mellanox/mlx5/core/main.c | 22 +++++++++++++++---- include/linux/mlx5/device.h | 10 ++++++--- 2 files changed, 25 insertions(+), 7 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/main.c +18 -4
@@ -454,8 +454,8 @@ static int handle_hca_cap_atomic(struct mlx5_core_dev *dev, void *set_ctx)static int handle_hca_cap_odp (struct mlx5_core_dev *dev,void *set_ctx) { +bool do_set = false, mem_page_fault = false;void *set_hca_cap; -bool do_set = false;int err; if (!IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING) ||
@@ -470,6 +470,17 @@ static int handle_hca_cap_odp(struct mlx5_core_dev *dev, void *set_ctx)memcpy (set_hca_cap, dev->caps.hca[MLX5_CAP_ODP ]->cur,MLX5_ST_SZ_BYTES (odp_cap)); +/* For best performance, enable memory scheme ODP only when +* it has page prefetch enabled. +*/ +if (MLX5_CAP_ODP_MAX (dev, mem_page_fault) && +MLX5_CAP_ODP_MAX (dev, memory_page_fault_scheme_cap.page_prefetch)) { + mem_page_fault = true; + do_set = true; +MLX5_SET (odp_cap, set_hca_cap, mem_page_fault, mem_page_fault); + goto set; + }; +#define ODP_CAP_SET_MAX (dev, field) \ do { \ u32 _res = MLX5_CAP_ODP_MAX(dev, field); \
@@ -494,10 +505,13 @@ static int handle_hca_cap_odp(struct mlx5_core_dev *dev, void *set_ctx)ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.read);ODP_CAP_SET_MAX (dev, transport_page_fault_scheme_cap.dc_odp_caps.atomic); -if (!do_set) -return 0 ; +set: +if (do_set) + err =set_caps (dev, set_ctx,MLX5_SET_HCA_CAP_OP_MOD_ODP ); -return set_caps (dev, set_ctx,MLX5_SET_HCA_CAP_OP_MOD_ODP ); +mlx5_core_dbg (dev,"Using ODP %s scheme\n" , + mem_page_fault ?"memory" :"transport" ); +return err; }static int max_uc_list_get_devlink_param (struct mlx5_core_dev *dev)
include/linux/mlx5/device.h +7 -3
@@ -1389,9 +1389,13 @@ enum mlx5_qcam_feature_groups {#define MLX5_CAP_ODP (mdev, cap)\ MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, cap) -#define MLX5_CAP_ODP_SCHEME (mdev, cap) \ - MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, \ - transport_page_fault_scheme_cap.cap) +#define MLX5_CAP_ODP_SCHEME (mdev, cap) \ + (MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, \ + mem_page_fault) ? \ + MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, \ + memory_page_fault_scheme_cap.cap) : \ + MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->cur, \ + transport_page_fault_scheme_cap.cap))#define MLX5_CAP_ODP_MAX (mdev, cap)\ MLX5_GET(odp_cap, mdev->caps.hca[MLX5_CAP_ODP]->max, cap)
Signature · 1 line
2.17.2
Leon Romanovsky
AppliedQuoted 8 lines · Michael Guralnik
This series introduces a new ODP scheme in mlx5 where the FW takes the responsibility of parsing and providing page fault data to the driver to handle the fault.
As opposed to the current ODP transport scheme where the driver is responsible for reading and parsing work queues and querying mkeys to acquire needed info to handle the page fault.[...]
Applied, thanks!
[1/8] net/mlx5: Expand mkey page size to support 6 bits
https://git.kernel.org/rdma/rdma/c/cef7dde8836ab0 [2/8] net/mlx5: Expose HW bits for Memory scheme ODP https://git.kernel.org/rdma/rdma/c/6cd9171d04cff7 [3/8] RDMA/mlx5: Add new ODP memory scheme eqe format https://git.kernel.org/rdma/rdma/c/64c68385a39bb6 [4/8] RDMA/mlx5: Enforce umem boundaries for explicit ODP page faults https://git.kernel.org/rdma/rdma/c/8c6d097d830f77 [5/8] RDMA/mlx5: Split ODP mkey search logic https://git.kernel.org/rdma/rdma/c/7f91510af938b4 [6/8] RDMA/mlx5: Add handling for memory scheme page fault events https://git.kernel.org/rdma/rdma/c/e4fda2320f8e6b [7/8] RDMA/mlx5: Add implicit MR handling to ODP memory scheme https://git.kernel.org/rdma/rdma/c/6f2487bfafce5e [8/8] net/mlx5: Handle memory scheme ODP capabilities https://git.kernel.org/rdma/rdma/c/5416992c011080
Best regards,
Signature · 1 line
Leon Romanovsky <[email protected]>