diff options
Diffstat (limited to 'drivers/infiniband/hw/hns/hns_roce_srq.c')
-rw-r--r-- | drivers/infiniband/hw/hns/hns_roce_srq.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index 8dae98f827..4e2d1c8e16 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -5,6 +5,7 @@ #include <linux/pci.h> #include <rdma/ib_umem.h> +#include <rdma/uverbs_ioctl.h> #include "hns_roce_device.h" #include "hns_roce_cmd.h" #include "hns_roce_hem.h" @@ -387,6 +388,79 @@ static void free_srq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) free_srq_idx(hr_dev, srq); } +static int get_srq_ucmd(struct hns_roce_srq *srq, struct ib_udata *udata, + struct hns_roce_ib_create_srq *ucmd) +{ + struct ib_device *ibdev = srq->ibsrq.device; + int ret; + + ret = ib_copy_from_udata(ucmd, udata, min(udata->inlen, sizeof(*ucmd))); + if (ret) { + ibdev_err(ibdev, "failed to copy SRQ udata, ret = %d.\n", ret); + return ret; + } + + return 0; +} + +static void free_srq_db(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq, + struct ib_udata *udata) +{ + struct hns_roce_ucontext *uctx; + + if (!(srq->cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB)) + return; + + srq->cap_flags &= ~HNS_ROCE_SRQ_CAP_RECORD_DB; + if (udata) { + uctx = rdma_udata_to_drv_context(udata, + struct hns_roce_ucontext, + ibucontext); + hns_roce_db_unmap_user(uctx, &srq->rdb); + } else { + hns_roce_free_db(hr_dev, &srq->rdb); + } +} + +static int alloc_srq_db(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq, + struct ib_udata *udata, + struct hns_roce_ib_create_srq_resp *resp) +{ + struct hns_roce_ib_create_srq ucmd = {}; + struct hns_roce_ucontext *uctx; + int ret; + + if (udata) { + ret = get_srq_ucmd(srq, udata, &ucmd); + if (ret) + return ret; + + if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB) && + (ucmd.req_cap_flags & HNS_ROCE_SRQ_CAP_RECORD_DB)) { + uctx = rdma_udata_to_drv_context(udata, + struct hns_roce_ucontext, ibucontext); + ret = hns_roce_db_map_user(uctx, ucmd.db_addr, + &srq->rdb); + if (ret) + return ret; + + srq->cap_flags |= HNS_ROCE_RSP_SRQ_CAP_RECORD_DB; + } + } else { + if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ_RECORD_DB) { + ret = hns_roce_alloc_db(hr_dev, &srq->rdb, 1); + if (ret) + return ret; + + *srq->rdb.db_record = 0; + srq->cap_flags |= HNS_ROCE_RSP_SRQ_CAP_RECORD_DB; + } + srq->db_reg = hr_dev->reg_base + SRQ_DB_REG; + } + + return 0; +} + int hns_roce_create_srq(struct ib_srq *ib_srq, struct ib_srq_init_attr *init_attr, struct ib_udata *udata) @@ -407,15 +481,20 @@ int hns_roce_create_srq(struct ib_srq *ib_srq, if (ret) return ret; - ret = alloc_srqn(hr_dev, srq); + ret = alloc_srq_db(hr_dev, srq, udata, &resp); if (ret) goto err_srq_buf; + ret = alloc_srqn(hr_dev, srq); + if (ret) + goto err_srq_db; + ret = alloc_srqc(hr_dev, srq); if (ret) goto err_srqn; if (udata) { + resp.cap_flags = srq->cap_flags; resp.srqn = srq->srqn; if (ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp)))) { @@ -424,7 +503,6 @@ int hns_roce_create_srq(struct ib_srq *ib_srq, } } - srq->db_reg = hr_dev->reg_base + SRQ_DB_REG; srq->event = hns_roce_ib_srq_event; refcount_set(&srq->refcount, 1); init_completion(&srq->free); @@ -435,6 +513,8 @@ err_srqc: free_srqc(hr_dev, srq); err_srqn: free_srqn(hr_dev, srq); +err_srq_db: + free_srq_db(hr_dev, srq, udata); err_srq_buf: free_srq_buf(hr_dev, srq); @@ -448,6 +528,7 @@ int hns_roce_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) free_srqc(hr_dev, srq); free_srqn(hr_dev, srq); + free_srq_db(hr_dev, srq, udata); free_srq_buf(hr_dev, srq); return 0; } |