162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 HGST, a Western Digital Company. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/memremap.h> 662306a36Sopenharmony_ci#include <linux/moduleparam.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci#include <linux/pci-p2pdma.h> 962306a36Sopenharmony_ci#include <rdma/mr_pool.h> 1062306a36Sopenharmony_ci#include <rdma/rw.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cienum { 1362306a36Sopenharmony_ci RDMA_RW_SINGLE_WR, 1462306a36Sopenharmony_ci RDMA_RW_MULTI_WR, 1562306a36Sopenharmony_ci RDMA_RW_MR, 1662306a36Sopenharmony_ci RDMA_RW_SIG_MR, 1762306a36Sopenharmony_ci}; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic bool rdma_rw_force_mr; 2062306a36Sopenharmony_cimodule_param_named(force_mr, rdma_rw_force_mr, bool, 0); 2162306a36Sopenharmony_ciMODULE_PARM_DESC(force_mr, "Force usage of MRs for RDMA READ/WRITE operations"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * Report whether memory registration should be used. Memory registration must 2562306a36Sopenharmony_ci * be used for iWarp devices because of iWARP-specific limitations. Memory 2662306a36Sopenharmony_ci * registration is also enabled if registering memory might yield better 2762306a36Sopenharmony_ci * performance than using multiple SGE entries, see rdma_rw_io_needs_mr() 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic inline bool rdma_rw_can_use_mr(struct ib_device *dev, u32 port_num) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci if (rdma_protocol_iwarp(dev, port_num)) 3262306a36Sopenharmony_ci return true; 3362306a36Sopenharmony_ci if (dev->attrs.max_sgl_rd) 3462306a36Sopenharmony_ci return true; 3562306a36Sopenharmony_ci if (unlikely(rdma_rw_force_mr)) 3662306a36Sopenharmony_ci return true; 3762306a36Sopenharmony_ci return false; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Check if the device will use memory registration for this RW operation. 4262306a36Sopenharmony_ci * For RDMA READs we must use MRs on iWarp and can optionally use them as an 4362306a36Sopenharmony_ci * optimization otherwise. Additionally we have a debug option to force usage 4462306a36Sopenharmony_ci * of MRs to help testing this code path. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic inline bool rdma_rw_io_needs_mr(struct ib_device *dev, u32 port_num, 4762306a36Sopenharmony_ci enum dma_data_direction dir, int dma_nents) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci if (dir == DMA_FROM_DEVICE) { 5062306a36Sopenharmony_ci if (rdma_protocol_iwarp(dev, port_num)) 5162306a36Sopenharmony_ci return true; 5262306a36Sopenharmony_ci if (dev->attrs.max_sgl_rd && dma_nents > dev->attrs.max_sgl_rd) 5362306a36Sopenharmony_ci return true; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci if (unlikely(rdma_rw_force_mr)) 5662306a36Sopenharmony_ci return true; 5762306a36Sopenharmony_ci return false; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline u32 rdma_rw_fr_page_list_len(struct ib_device *dev, 6162306a36Sopenharmony_ci bool pi_support) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci u32 max_pages; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (pi_support) 6662306a36Sopenharmony_ci max_pages = dev->attrs.max_pi_fast_reg_page_list_len; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci max_pages = dev->attrs.max_fast_reg_page_list_len; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* arbitrary limit to avoid allocating gigantic resources */ 7162306a36Sopenharmony_ci return min_t(u32, max_pages, 256); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic inline int rdma_rw_inv_key(struct rdma_rw_reg_ctx *reg) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int count = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (reg->mr->need_inval) { 7962306a36Sopenharmony_ci reg->inv_wr.opcode = IB_WR_LOCAL_INV; 8062306a36Sopenharmony_ci reg->inv_wr.ex.invalidate_rkey = reg->mr->lkey; 8162306a36Sopenharmony_ci reg->inv_wr.next = ®->reg_wr.wr; 8262306a36Sopenharmony_ci count++; 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci reg->inv_wr.next = NULL; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return count; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* Caller must have zero-initialized *reg. */ 9162306a36Sopenharmony_cistatic int rdma_rw_init_one_mr(struct ib_qp *qp, u32 port_num, 9262306a36Sopenharmony_ci struct rdma_rw_reg_ctx *reg, struct scatterlist *sg, 9362306a36Sopenharmony_ci u32 sg_cnt, u32 offset) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device, 9662306a36Sopenharmony_ci qp->integrity_en); 9762306a36Sopenharmony_ci u32 nents = min(sg_cnt, pages_per_mr); 9862306a36Sopenharmony_ci int count = 0, ret; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci reg->mr = ib_mr_pool_get(qp, &qp->rdma_mrs); 10162306a36Sopenharmony_ci if (!reg->mr) 10262306a36Sopenharmony_ci return -EAGAIN; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci count += rdma_rw_inv_key(reg); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = ib_map_mr_sg(reg->mr, sg, nents, &offset, PAGE_SIZE); 10762306a36Sopenharmony_ci if (ret < 0 || ret < nents) { 10862306a36Sopenharmony_ci ib_mr_pool_put(qp, &qp->rdma_mrs, reg->mr); 10962306a36Sopenharmony_ci return -EINVAL; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci reg->reg_wr.wr.opcode = IB_WR_REG_MR; 11362306a36Sopenharmony_ci reg->reg_wr.mr = reg->mr; 11462306a36Sopenharmony_ci reg->reg_wr.access = IB_ACCESS_LOCAL_WRITE; 11562306a36Sopenharmony_ci if (rdma_protocol_iwarp(qp->device, port_num)) 11662306a36Sopenharmony_ci reg->reg_wr.access |= IB_ACCESS_REMOTE_WRITE; 11762306a36Sopenharmony_ci count++; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci reg->sge.addr = reg->mr->iova; 12062306a36Sopenharmony_ci reg->sge.length = reg->mr->length; 12162306a36Sopenharmony_ci return count; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int rdma_rw_init_mr_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 12562306a36Sopenharmony_ci u32 port_num, struct scatterlist *sg, u32 sg_cnt, u32 offset, 12662306a36Sopenharmony_ci u64 remote_addr, u32 rkey, enum dma_data_direction dir) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct rdma_rw_reg_ctx *prev = NULL; 12962306a36Sopenharmony_ci u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device, 13062306a36Sopenharmony_ci qp->integrity_en); 13162306a36Sopenharmony_ci int i, j, ret = 0, count = 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ctx->nr_ops = DIV_ROUND_UP(sg_cnt, pages_per_mr); 13462306a36Sopenharmony_ci ctx->reg = kcalloc(ctx->nr_ops, sizeof(*ctx->reg), GFP_KERNEL); 13562306a36Sopenharmony_ci if (!ctx->reg) { 13662306a36Sopenharmony_ci ret = -ENOMEM; 13762306a36Sopenharmony_ci goto out; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for (i = 0; i < ctx->nr_ops; i++) { 14162306a36Sopenharmony_ci struct rdma_rw_reg_ctx *reg = &ctx->reg[i]; 14262306a36Sopenharmony_ci u32 nents = min(sg_cnt, pages_per_mr); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ret = rdma_rw_init_one_mr(qp, port_num, reg, sg, sg_cnt, 14562306a36Sopenharmony_ci offset); 14662306a36Sopenharmony_ci if (ret < 0) 14762306a36Sopenharmony_ci goto out_free; 14862306a36Sopenharmony_ci count += ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (prev) { 15162306a36Sopenharmony_ci if (reg->mr->need_inval) 15262306a36Sopenharmony_ci prev->wr.wr.next = ®->inv_wr; 15362306a36Sopenharmony_ci else 15462306a36Sopenharmony_ci prev->wr.wr.next = ®->reg_wr.wr; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci reg->reg_wr.wr.next = ®->wr.wr; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci reg->wr.wr.sg_list = ®->sge; 16062306a36Sopenharmony_ci reg->wr.wr.num_sge = 1; 16162306a36Sopenharmony_ci reg->wr.remote_addr = remote_addr; 16262306a36Sopenharmony_ci reg->wr.rkey = rkey; 16362306a36Sopenharmony_ci if (dir == DMA_TO_DEVICE) { 16462306a36Sopenharmony_ci reg->wr.wr.opcode = IB_WR_RDMA_WRITE; 16562306a36Sopenharmony_ci } else if (!rdma_cap_read_inv(qp->device, port_num)) { 16662306a36Sopenharmony_ci reg->wr.wr.opcode = IB_WR_RDMA_READ; 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci reg->wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV; 16962306a36Sopenharmony_ci reg->wr.wr.ex.invalidate_rkey = reg->mr->lkey; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci count++; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci remote_addr += reg->sge.length; 17462306a36Sopenharmony_ci sg_cnt -= nents; 17562306a36Sopenharmony_ci for (j = 0; j < nents; j++) 17662306a36Sopenharmony_ci sg = sg_next(sg); 17762306a36Sopenharmony_ci prev = reg; 17862306a36Sopenharmony_ci offset = 0; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (prev) 18262306a36Sopenharmony_ci prev->wr.wr.next = NULL; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ctx->type = RDMA_RW_MR; 18562306a36Sopenharmony_ci return count; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciout_free: 18862306a36Sopenharmony_ci while (--i >= 0) 18962306a36Sopenharmony_ci ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->reg[i].mr); 19062306a36Sopenharmony_ci kfree(ctx->reg); 19162306a36Sopenharmony_ciout: 19262306a36Sopenharmony_ci return ret; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int rdma_rw_init_map_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 19662306a36Sopenharmony_ci struct scatterlist *sg, u32 sg_cnt, u32 offset, 19762306a36Sopenharmony_ci u64 remote_addr, u32 rkey, enum dma_data_direction dir) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci u32 max_sge = dir == DMA_TO_DEVICE ? qp->max_write_sge : 20062306a36Sopenharmony_ci qp->max_read_sge; 20162306a36Sopenharmony_ci struct ib_sge *sge; 20262306a36Sopenharmony_ci u32 total_len = 0, i, j; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci ctx->nr_ops = DIV_ROUND_UP(sg_cnt, max_sge); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ctx->map.sges = sge = kcalloc(sg_cnt, sizeof(*sge), GFP_KERNEL); 20762306a36Sopenharmony_ci if (!ctx->map.sges) 20862306a36Sopenharmony_ci goto out; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ctx->map.wrs = kcalloc(ctx->nr_ops, sizeof(*ctx->map.wrs), GFP_KERNEL); 21162306a36Sopenharmony_ci if (!ctx->map.wrs) 21262306a36Sopenharmony_ci goto out_free_sges; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci for (i = 0; i < ctx->nr_ops; i++) { 21562306a36Sopenharmony_ci struct ib_rdma_wr *rdma_wr = &ctx->map.wrs[i]; 21662306a36Sopenharmony_ci u32 nr_sge = min(sg_cnt, max_sge); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (dir == DMA_TO_DEVICE) 21962306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_WRITE; 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_READ; 22262306a36Sopenharmony_ci rdma_wr->remote_addr = remote_addr + total_len; 22362306a36Sopenharmony_ci rdma_wr->rkey = rkey; 22462306a36Sopenharmony_ci rdma_wr->wr.num_sge = nr_sge; 22562306a36Sopenharmony_ci rdma_wr->wr.sg_list = sge; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci for (j = 0; j < nr_sge; j++, sg = sg_next(sg)) { 22862306a36Sopenharmony_ci sge->addr = sg_dma_address(sg) + offset; 22962306a36Sopenharmony_ci sge->length = sg_dma_len(sg) - offset; 23062306a36Sopenharmony_ci sge->lkey = qp->pd->local_dma_lkey; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci total_len += sge->length; 23362306a36Sopenharmony_ci sge++; 23462306a36Sopenharmony_ci sg_cnt--; 23562306a36Sopenharmony_ci offset = 0; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci rdma_wr->wr.next = i + 1 < ctx->nr_ops ? 23962306a36Sopenharmony_ci &ctx->map.wrs[i + 1].wr : NULL; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ctx->type = RDMA_RW_MULTI_WR; 24362306a36Sopenharmony_ci return ctx->nr_ops; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciout_free_sges: 24662306a36Sopenharmony_ci kfree(ctx->map.sges); 24762306a36Sopenharmony_ciout: 24862306a36Sopenharmony_ci return -ENOMEM; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int rdma_rw_init_single_wr(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 25262306a36Sopenharmony_ci struct scatterlist *sg, u32 offset, u64 remote_addr, u32 rkey, 25362306a36Sopenharmony_ci enum dma_data_direction dir) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct ib_rdma_wr *rdma_wr = &ctx->single.wr; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ctx->nr_ops = 1; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ctx->single.sge.lkey = qp->pd->local_dma_lkey; 26062306a36Sopenharmony_ci ctx->single.sge.addr = sg_dma_address(sg) + offset; 26162306a36Sopenharmony_ci ctx->single.sge.length = sg_dma_len(sg) - offset; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci memset(rdma_wr, 0, sizeof(*rdma_wr)); 26462306a36Sopenharmony_ci if (dir == DMA_TO_DEVICE) 26562306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_WRITE; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_READ; 26862306a36Sopenharmony_ci rdma_wr->wr.sg_list = &ctx->single.sge; 26962306a36Sopenharmony_ci rdma_wr->wr.num_sge = 1; 27062306a36Sopenharmony_ci rdma_wr->remote_addr = remote_addr; 27162306a36Sopenharmony_ci rdma_wr->rkey = rkey; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ctx->type = RDMA_RW_SINGLE_WR; 27462306a36Sopenharmony_ci return 1; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/** 27862306a36Sopenharmony_ci * rdma_rw_ctx_init - initialize a RDMA READ/WRITE context 27962306a36Sopenharmony_ci * @ctx: context to initialize 28062306a36Sopenharmony_ci * @qp: queue pair to operate on 28162306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 28262306a36Sopenharmony_ci * @sg: scatterlist to READ/WRITE from/to 28362306a36Sopenharmony_ci * @sg_cnt: number of entries in @sg 28462306a36Sopenharmony_ci * @sg_offset: current byte offset into @sg 28562306a36Sopenharmony_ci * @remote_addr:remote address to read/write (relative to @rkey) 28662306a36Sopenharmony_ci * @rkey: remote key to operate on 28762306a36Sopenharmony_ci * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ 28862306a36Sopenharmony_ci * 28962306a36Sopenharmony_ci * Returns the number of WQEs that will be needed on the workqueue if 29062306a36Sopenharmony_ci * successful, or a negative error code. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ciint rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, 29362306a36Sopenharmony_ci struct scatterlist *sg, u32 sg_cnt, u32 sg_offset, 29462306a36Sopenharmony_ci u64 remote_addr, u32 rkey, enum dma_data_direction dir) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct ib_device *dev = qp->pd->device; 29762306a36Sopenharmony_ci struct sg_table sgt = { 29862306a36Sopenharmony_ci .sgl = sg, 29962306a36Sopenharmony_ci .orig_nents = sg_cnt, 30062306a36Sopenharmony_ci }; 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = ib_dma_map_sgtable_attrs(dev, &sgt, dir, 0); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci sg_cnt = sgt.nents; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* 30962306a36Sopenharmony_ci * Skip to the S/G entry that sg_offset falls into: 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci for (;;) { 31262306a36Sopenharmony_ci u32 len = sg_dma_len(sg); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (sg_offset < len) 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci sg = sg_next(sg); 31862306a36Sopenharmony_ci sg_offset -= len; 31962306a36Sopenharmony_ci sg_cnt--; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci ret = -EIO; 32362306a36Sopenharmony_ci if (WARN_ON_ONCE(sg_cnt == 0)) 32462306a36Sopenharmony_ci goto out_unmap_sg; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (rdma_rw_io_needs_mr(qp->device, port_num, dir, sg_cnt)) { 32762306a36Sopenharmony_ci ret = rdma_rw_init_mr_wrs(ctx, qp, port_num, sg, sg_cnt, 32862306a36Sopenharmony_ci sg_offset, remote_addr, rkey, dir); 32962306a36Sopenharmony_ci } else if (sg_cnt > 1) { 33062306a36Sopenharmony_ci ret = rdma_rw_init_map_wrs(ctx, qp, sg, sg_cnt, sg_offset, 33162306a36Sopenharmony_ci remote_addr, rkey, dir); 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci ret = rdma_rw_init_single_wr(ctx, qp, sg, sg_offset, 33462306a36Sopenharmony_ci remote_addr, rkey, dir); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (ret < 0) 33862306a36Sopenharmony_ci goto out_unmap_sg; 33962306a36Sopenharmony_ci return ret; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ciout_unmap_sg: 34262306a36Sopenharmony_ci ib_dma_unmap_sgtable_attrs(dev, &sgt, dir, 0); 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_init); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/** 34862306a36Sopenharmony_ci * rdma_rw_ctx_signature_init - initialize a RW context with signature offload 34962306a36Sopenharmony_ci * @ctx: context to initialize 35062306a36Sopenharmony_ci * @qp: queue pair to operate on 35162306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 35262306a36Sopenharmony_ci * @sg: scatterlist to READ/WRITE from/to 35362306a36Sopenharmony_ci * @sg_cnt: number of entries in @sg 35462306a36Sopenharmony_ci * @prot_sg: scatterlist to READ/WRITE protection information from/to 35562306a36Sopenharmony_ci * @prot_sg_cnt: number of entries in @prot_sg 35662306a36Sopenharmony_ci * @sig_attrs: signature offloading algorithms 35762306a36Sopenharmony_ci * @remote_addr:remote address to read/write (relative to @rkey) 35862306a36Sopenharmony_ci * @rkey: remote key to operate on 35962306a36Sopenharmony_ci * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * Returns the number of WQEs that will be needed on the workqueue if 36262306a36Sopenharmony_ci * successful, or a negative error code. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ciint rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 36562306a36Sopenharmony_ci u32 port_num, struct scatterlist *sg, u32 sg_cnt, 36662306a36Sopenharmony_ci struct scatterlist *prot_sg, u32 prot_sg_cnt, 36762306a36Sopenharmony_ci struct ib_sig_attrs *sig_attrs, 36862306a36Sopenharmony_ci u64 remote_addr, u32 rkey, enum dma_data_direction dir) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct ib_device *dev = qp->pd->device; 37162306a36Sopenharmony_ci u32 pages_per_mr = rdma_rw_fr_page_list_len(qp->pd->device, 37262306a36Sopenharmony_ci qp->integrity_en); 37362306a36Sopenharmony_ci struct sg_table sgt = { 37462306a36Sopenharmony_ci .sgl = sg, 37562306a36Sopenharmony_ci .orig_nents = sg_cnt, 37662306a36Sopenharmony_ci }; 37762306a36Sopenharmony_ci struct sg_table prot_sgt = { 37862306a36Sopenharmony_ci .sgl = prot_sg, 37962306a36Sopenharmony_ci .orig_nents = prot_sg_cnt, 38062306a36Sopenharmony_ci }; 38162306a36Sopenharmony_ci struct ib_rdma_wr *rdma_wr; 38262306a36Sopenharmony_ci int count = 0, ret; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (sg_cnt > pages_per_mr || prot_sg_cnt > pages_per_mr) { 38562306a36Sopenharmony_ci pr_err("SG count too large: sg_cnt=%u, prot_sg_cnt=%u, pages_per_mr=%u\n", 38662306a36Sopenharmony_ci sg_cnt, prot_sg_cnt, pages_per_mr); 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = ib_dma_map_sgtable_attrs(dev, &sgt, dir, 0); 39162306a36Sopenharmony_ci if (ret) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (prot_sg_cnt) { 39562306a36Sopenharmony_ci ret = ib_dma_map_sgtable_attrs(dev, &prot_sgt, dir, 0); 39662306a36Sopenharmony_ci if (ret) 39762306a36Sopenharmony_ci goto out_unmap_sg; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ctx->type = RDMA_RW_SIG_MR; 40162306a36Sopenharmony_ci ctx->nr_ops = 1; 40262306a36Sopenharmony_ci ctx->reg = kzalloc(sizeof(*ctx->reg), GFP_KERNEL); 40362306a36Sopenharmony_ci if (!ctx->reg) { 40462306a36Sopenharmony_ci ret = -ENOMEM; 40562306a36Sopenharmony_ci goto out_unmap_prot_sg; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ctx->reg->mr = ib_mr_pool_get(qp, &qp->sig_mrs); 40962306a36Sopenharmony_ci if (!ctx->reg->mr) { 41062306a36Sopenharmony_ci ret = -EAGAIN; 41162306a36Sopenharmony_ci goto out_free_ctx; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci count += rdma_rw_inv_key(ctx->reg); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci memcpy(ctx->reg->mr->sig_attrs, sig_attrs, sizeof(struct ib_sig_attrs)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = ib_map_mr_sg_pi(ctx->reg->mr, sg, sgt.nents, NULL, prot_sg, 41962306a36Sopenharmony_ci prot_sgt.nents, NULL, SZ_4K); 42062306a36Sopenharmony_ci if (unlikely(ret)) { 42162306a36Sopenharmony_ci pr_err("failed to map PI sg (%u)\n", 42262306a36Sopenharmony_ci sgt.nents + prot_sgt.nents); 42362306a36Sopenharmony_ci goto out_destroy_sig_mr; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ctx->reg->reg_wr.wr.opcode = IB_WR_REG_MR_INTEGRITY; 42762306a36Sopenharmony_ci ctx->reg->reg_wr.wr.wr_cqe = NULL; 42862306a36Sopenharmony_ci ctx->reg->reg_wr.wr.num_sge = 0; 42962306a36Sopenharmony_ci ctx->reg->reg_wr.wr.send_flags = 0; 43062306a36Sopenharmony_ci ctx->reg->reg_wr.access = IB_ACCESS_LOCAL_WRITE; 43162306a36Sopenharmony_ci if (rdma_protocol_iwarp(qp->device, port_num)) 43262306a36Sopenharmony_ci ctx->reg->reg_wr.access |= IB_ACCESS_REMOTE_WRITE; 43362306a36Sopenharmony_ci ctx->reg->reg_wr.mr = ctx->reg->mr; 43462306a36Sopenharmony_ci ctx->reg->reg_wr.key = ctx->reg->mr->lkey; 43562306a36Sopenharmony_ci count++; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ctx->reg->sge.addr = ctx->reg->mr->iova; 43862306a36Sopenharmony_ci ctx->reg->sge.length = ctx->reg->mr->length; 43962306a36Sopenharmony_ci if (sig_attrs->wire.sig_type == IB_SIG_TYPE_NONE) 44062306a36Sopenharmony_ci ctx->reg->sge.length -= ctx->reg->mr->sig_attrs->meta_length; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci rdma_wr = &ctx->reg->wr; 44362306a36Sopenharmony_ci rdma_wr->wr.sg_list = &ctx->reg->sge; 44462306a36Sopenharmony_ci rdma_wr->wr.num_sge = 1; 44562306a36Sopenharmony_ci rdma_wr->remote_addr = remote_addr; 44662306a36Sopenharmony_ci rdma_wr->rkey = rkey; 44762306a36Sopenharmony_ci if (dir == DMA_TO_DEVICE) 44862306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_WRITE; 44962306a36Sopenharmony_ci else 45062306a36Sopenharmony_ci rdma_wr->wr.opcode = IB_WR_RDMA_READ; 45162306a36Sopenharmony_ci ctx->reg->reg_wr.wr.next = &rdma_wr->wr; 45262306a36Sopenharmony_ci count++; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return count; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciout_destroy_sig_mr: 45762306a36Sopenharmony_ci ib_mr_pool_put(qp, &qp->sig_mrs, ctx->reg->mr); 45862306a36Sopenharmony_ciout_free_ctx: 45962306a36Sopenharmony_ci kfree(ctx->reg); 46062306a36Sopenharmony_ciout_unmap_prot_sg: 46162306a36Sopenharmony_ci if (prot_sgt.nents) 46262306a36Sopenharmony_ci ib_dma_unmap_sgtable_attrs(dev, &prot_sgt, dir, 0); 46362306a36Sopenharmony_ciout_unmap_sg: 46462306a36Sopenharmony_ci ib_dma_unmap_sgtable_attrs(dev, &sgt, dir, 0); 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_signature_init); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * Now that we are going to post the WRs we can update the lkey and need_inval 47162306a36Sopenharmony_ci * state on the MRs. If we were doing this at init time, we would get double 47262306a36Sopenharmony_ci * or missing invalidations if a context was initialized but not actually 47362306a36Sopenharmony_ci * posted. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_cistatic void rdma_rw_update_lkey(struct rdma_rw_reg_ctx *reg, bool need_inval) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci reg->mr->need_inval = need_inval; 47862306a36Sopenharmony_ci ib_update_fast_reg_key(reg->mr, ib_inc_rkey(reg->mr->lkey)); 47962306a36Sopenharmony_ci reg->reg_wr.key = reg->mr->lkey; 48062306a36Sopenharmony_ci reg->sge.lkey = reg->mr->lkey; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci/** 48462306a36Sopenharmony_ci * rdma_rw_ctx_wrs - return chain of WRs for a RDMA READ or WRITE operation 48562306a36Sopenharmony_ci * @ctx: context to operate on 48662306a36Sopenharmony_ci * @qp: queue pair to operate on 48762306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 48862306a36Sopenharmony_ci * @cqe: completion queue entry for the last WR 48962306a36Sopenharmony_ci * @chain_wr: WR to append to the posted chain 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * Return the WR chain for the set of RDMA READ/WRITE operations described by 49262306a36Sopenharmony_ci * @ctx, as well as any memory registration operations needed. If @chain_wr 49362306a36Sopenharmony_ci * is non-NULL the WR it points to will be appended to the chain of WRs posted. 49462306a36Sopenharmony_ci * If @chain_wr is not set @cqe must be set so that the caller gets a 49562306a36Sopenharmony_ci * completion notification. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_cistruct ib_send_wr *rdma_rw_ctx_wrs(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 49862306a36Sopenharmony_ci u32 port_num, struct ib_cqe *cqe, struct ib_send_wr *chain_wr) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct ib_send_wr *first_wr, *last_wr; 50162306a36Sopenharmony_ci int i; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (ctx->type) { 50462306a36Sopenharmony_ci case RDMA_RW_SIG_MR: 50562306a36Sopenharmony_ci case RDMA_RW_MR: 50662306a36Sopenharmony_ci for (i = 0; i < ctx->nr_ops; i++) { 50762306a36Sopenharmony_ci rdma_rw_update_lkey(&ctx->reg[i], 50862306a36Sopenharmony_ci ctx->reg[i].wr.wr.opcode != 50962306a36Sopenharmony_ci IB_WR_RDMA_READ_WITH_INV); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (ctx->reg[0].inv_wr.next) 51362306a36Sopenharmony_ci first_wr = &ctx->reg[0].inv_wr; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci first_wr = &ctx->reg[0].reg_wr.wr; 51662306a36Sopenharmony_ci last_wr = &ctx->reg[ctx->nr_ops - 1].wr.wr; 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci case RDMA_RW_MULTI_WR: 51962306a36Sopenharmony_ci first_wr = &ctx->map.wrs[0].wr; 52062306a36Sopenharmony_ci last_wr = &ctx->map.wrs[ctx->nr_ops - 1].wr; 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci case RDMA_RW_SINGLE_WR: 52362306a36Sopenharmony_ci first_wr = &ctx->single.wr.wr; 52462306a36Sopenharmony_ci last_wr = &ctx->single.wr.wr; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci default: 52762306a36Sopenharmony_ci BUG(); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (chain_wr) { 53162306a36Sopenharmony_ci last_wr->next = chain_wr; 53262306a36Sopenharmony_ci } else { 53362306a36Sopenharmony_ci last_wr->wr_cqe = cqe; 53462306a36Sopenharmony_ci last_wr->send_flags |= IB_SEND_SIGNALED; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return first_wr; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_wrs); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/** 54262306a36Sopenharmony_ci * rdma_rw_ctx_post - post a RDMA READ or RDMA WRITE operation 54362306a36Sopenharmony_ci * @ctx: context to operate on 54462306a36Sopenharmony_ci * @qp: queue pair to operate on 54562306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 54662306a36Sopenharmony_ci * @cqe: completion queue entry for the last WR 54762306a36Sopenharmony_ci * @chain_wr: WR to append to the posted chain 54862306a36Sopenharmony_ci * 54962306a36Sopenharmony_ci * Post the set of RDMA READ/WRITE operations described by @ctx, as well as 55062306a36Sopenharmony_ci * any memory registration operations needed. If @chain_wr is non-NULL the 55162306a36Sopenharmony_ci * WR it points to will be appended to the chain of WRs posted. If @chain_wr 55262306a36Sopenharmony_ci * is not set @cqe must be set so that the caller gets a completion 55362306a36Sopenharmony_ci * notification. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ciint rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, 55662306a36Sopenharmony_ci struct ib_cqe *cqe, struct ib_send_wr *chain_wr) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct ib_send_wr *first_wr; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci first_wr = rdma_rw_ctx_wrs(ctx, qp, port_num, cqe, chain_wr); 56162306a36Sopenharmony_ci return ib_post_send(qp, first_wr, NULL); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_post); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/** 56662306a36Sopenharmony_ci * rdma_rw_ctx_destroy - release all resources allocated by rdma_rw_ctx_init 56762306a36Sopenharmony_ci * @ctx: context to release 56862306a36Sopenharmony_ci * @qp: queue pair to operate on 56962306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 57062306a36Sopenharmony_ci * @sg: scatterlist that was used for the READ/WRITE 57162306a36Sopenharmony_ci * @sg_cnt: number of entries in @sg 57262306a36Sopenharmony_ci * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_civoid rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 57562306a36Sopenharmony_ci u32 port_num, struct scatterlist *sg, u32 sg_cnt, 57662306a36Sopenharmony_ci enum dma_data_direction dir) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci int i; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci switch (ctx->type) { 58162306a36Sopenharmony_ci case RDMA_RW_MR: 58262306a36Sopenharmony_ci for (i = 0; i < ctx->nr_ops; i++) 58362306a36Sopenharmony_ci ib_mr_pool_put(qp, &qp->rdma_mrs, ctx->reg[i].mr); 58462306a36Sopenharmony_ci kfree(ctx->reg); 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case RDMA_RW_MULTI_WR: 58762306a36Sopenharmony_ci kfree(ctx->map.wrs); 58862306a36Sopenharmony_ci kfree(ctx->map.sges); 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case RDMA_RW_SINGLE_WR: 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci default: 59362306a36Sopenharmony_ci BUG(); 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_destroy); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/** 60262306a36Sopenharmony_ci * rdma_rw_ctx_destroy_signature - release all resources allocated by 60362306a36Sopenharmony_ci * rdma_rw_ctx_signature_init 60462306a36Sopenharmony_ci * @ctx: context to release 60562306a36Sopenharmony_ci * @qp: queue pair to operate on 60662306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 60762306a36Sopenharmony_ci * @sg: scatterlist that was used for the READ/WRITE 60862306a36Sopenharmony_ci * @sg_cnt: number of entries in @sg 60962306a36Sopenharmony_ci * @prot_sg: scatterlist that was used for the READ/WRITE of the PI 61062306a36Sopenharmony_ci * @prot_sg_cnt: number of entries in @prot_sg 61162306a36Sopenharmony_ci * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_civoid rdma_rw_ctx_destroy_signature(struct rdma_rw_ctx *ctx, struct ib_qp *qp, 61462306a36Sopenharmony_ci u32 port_num, struct scatterlist *sg, u32 sg_cnt, 61562306a36Sopenharmony_ci struct scatterlist *prot_sg, u32 prot_sg_cnt, 61662306a36Sopenharmony_ci enum dma_data_direction dir) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci if (WARN_ON_ONCE(ctx->type != RDMA_RW_SIG_MR)) 61962306a36Sopenharmony_ci return; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ib_mr_pool_put(qp, &qp->sig_mrs, ctx->reg->mr); 62262306a36Sopenharmony_ci kfree(ctx->reg); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (prot_sg_cnt) 62562306a36Sopenharmony_ci ib_dma_unmap_sg(qp->pd->device, prot_sg, prot_sg_cnt, dir); 62662306a36Sopenharmony_ci ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_ctx_destroy_signature); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci/** 63162306a36Sopenharmony_ci * rdma_rw_mr_factor - return number of MRs required for a payload 63262306a36Sopenharmony_ci * @device: device handling the connection 63362306a36Sopenharmony_ci * @port_num: port num to which the connection is bound 63462306a36Sopenharmony_ci * @maxpages: maximum payload pages per rdma_rw_ctx 63562306a36Sopenharmony_ci * 63662306a36Sopenharmony_ci * Returns the number of MRs the device requires to move @maxpayload 63762306a36Sopenharmony_ci * bytes. The returned value is used during transport creation to 63862306a36Sopenharmony_ci * compute max_rdma_ctxts and the size of the transport's Send and 63962306a36Sopenharmony_ci * Send Completion Queues. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ciunsigned int rdma_rw_mr_factor(struct ib_device *device, u32 port_num, 64262306a36Sopenharmony_ci unsigned int maxpages) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci unsigned int mr_pages; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (rdma_rw_can_use_mr(device, port_num)) 64762306a36Sopenharmony_ci mr_pages = rdma_rw_fr_page_list_len(device, false); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci mr_pages = device->attrs.max_sge_rd; 65062306a36Sopenharmony_ci return DIV_ROUND_UP(maxpages, mr_pages); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_rw_mr_factor); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_civoid rdma_rw_init_qp(struct ib_device *dev, struct ib_qp_init_attr *attr) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci u32 factor; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci WARN_ON_ONCE(attr->port_num == 0); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* 66162306a36Sopenharmony_ci * Each context needs at least one RDMA READ or WRITE WR. 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * For some hardware we might need more, eventually we should ask the 66462306a36Sopenharmony_ci * HCA driver for a multiplier here. 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ci factor = 1; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* 66962306a36Sopenharmony_ci * If the devices needs MRs to perform RDMA READ or WRITE operations, 67062306a36Sopenharmony_ci * we'll need two additional MRs for the registrations and the 67162306a36Sopenharmony_ci * invalidation. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN || 67462306a36Sopenharmony_ci rdma_rw_can_use_mr(dev, attr->port_num)) 67562306a36Sopenharmony_ci factor += 2; /* inv + reg */ 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci attr->cap.max_send_wr += factor * attr->cap.max_rdma_ctxs; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * But maybe we were just too high in the sky and the device doesn't 68162306a36Sopenharmony_ci * even support all we need, and we'll have to live with what we get.. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci attr->cap.max_send_wr = 68462306a36Sopenharmony_ci min_t(u32, attr->cap.max_send_wr, dev->attrs.max_qp_wr); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ciint rdma_rw_init_mrs(struct ib_qp *qp, struct ib_qp_init_attr *attr) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct ib_device *dev = qp->pd->device; 69062306a36Sopenharmony_ci u32 nr_mrs = 0, nr_sig_mrs = 0, max_num_sg = 0; 69162306a36Sopenharmony_ci int ret = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN) { 69462306a36Sopenharmony_ci nr_sig_mrs = attr->cap.max_rdma_ctxs; 69562306a36Sopenharmony_ci nr_mrs = attr->cap.max_rdma_ctxs; 69662306a36Sopenharmony_ci max_num_sg = rdma_rw_fr_page_list_len(dev, true); 69762306a36Sopenharmony_ci } else if (rdma_rw_can_use_mr(dev, attr->port_num)) { 69862306a36Sopenharmony_ci nr_mrs = attr->cap.max_rdma_ctxs; 69962306a36Sopenharmony_ci max_num_sg = rdma_rw_fr_page_list_len(dev, false); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (nr_mrs) { 70362306a36Sopenharmony_ci ret = ib_mr_pool_init(qp, &qp->rdma_mrs, nr_mrs, 70462306a36Sopenharmony_ci IB_MR_TYPE_MEM_REG, 70562306a36Sopenharmony_ci max_num_sg, 0); 70662306a36Sopenharmony_ci if (ret) { 70762306a36Sopenharmony_ci pr_err("%s: failed to allocated %u MRs\n", 70862306a36Sopenharmony_ci __func__, nr_mrs); 70962306a36Sopenharmony_ci return ret; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (nr_sig_mrs) { 71462306a36Sopenharmony_ci ret = ib_mr_pool_init(qp, &qp->sig_mrs, nr_sig_mrs, 71562306a36Sopenharmony_ci IB_MR_TYPE_INTEGRITY, max_num_sg, max_num_sg); 71662306a36Sopenharmony_ci if (ret) { 71762306a36Sopenharmony_ci pr_err("%s: failed to allocated %u SIG MRs\n", 71862306a36Sopenharmony_ci __func__, nr_sig_mrs); 71962306a36Sopenharmony_ci goto out_free_rdma_mrs; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ciout_free_rdma_mrs: 72662306a36Sopenharmony_ci ib_mr_pool_destroy(qp, &qp->rdma_mrs); 72762306a36Sopenharmony_ci return ret; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_civoid rdma_rw_cleanup_mrs(struct ib_qp *qp) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci ib_mr_pool_destroy(qp, &qp->sig_mrs); 73362306a36Sopenharmony_ci ib_mr_pool_destroy(qp, &qp->rdma_mrs); 73462306a36Sopenharmony_ci} 735