From: David Hu <[email protected]>

Support the standard 1-step queue buffer creation for SRQ by
`UVERBS_ATTR_CREATE_SRQ_BUF_UMEM` via `ib_umem_get_attr()`.

Set up hardware pble directly from the pinned SRQ umem via
`irdma_setup_q_pbl_from_umem()`.

Proper umem and pble cleanup, and error unwind are added into existing
`irdma_srq_free_rsrc()` upon SRQ destruction.

We maintain backward compatibility for the legacy 2-step registration if
the UMEM attribute is not provided.

Signed-off-by: David Hu <[email protected]>
---
 drivers/infiniband/hw/irdma/verbs.c | 68 ++++++++++++++++++++++++-----
 1 file changed, 58 insertions(+), 10 deletions(-)

diff --git a/drivers/infiniband/hw/irdma/verbs.c 
b/drivers/infiniband/hw/irdma/verbs.c
index 41e56ab8aa6d..7e8a5e481730 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -1996,9 +1996,16 @@ static void irdma_srq_free_rsrc(struct irdma_pci_f *rf, 
struct irdma_srq *iwsrq)
                iwsrq->kmem.va = NULL;
        } else {
                /* Not called in any failure path, so iwpbl is valid. */
-               struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
+               if (iwsrq->iwpbl) {
+                       struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
 
-               refcount_dec(&iwmr->user_ring_refs);
+                       if (iwmr && 
refcount_dec_and_test(&iwmr->user_ring_refs)) {
+                               ib_umem_release(iwmr->region);
+                               if (iwsrq->iwpbl->pbl_allocated)
+                                       irdma_free_pble(rf->pble_rsrc, 
&iwsrq->iwpbl->pble_alloc);
+                               kfree(iwmr);
+                       }
+               }
        }
 
        irdma_free_rsrc(rf, rf->allocated_srqs, srq->srq_uk.srq_id);
@@ -2425,6 +2432,7 @@ static int irdma_setup_umode_srq(struct irdma_device 
*iwdev,
                                 struct ib_udata *udata,
                                 struct uverbs_attr_bundle *attrs)
 {
+       struct irdma_srq_uk_init_info *ukinfo = &info->srq_uk_init_info;
        struct irdma_create_srq_req req = {};
        struct irdma_ucontext *ucontext;
        struct irdma_srq_mr *srqmr;
@@ -2440,14 +2448,49 @@ static int irdma_setup_umode_srq(struct irdma_device 
*iwdev,
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&ucontext->srq_reg_mem_list_lock, flags);
-       iwpbl = irdma_get_pbl((unsigned long)req.user_srq_buf,
-                             &ucontext->srq_reg_mem_list);
-       spin_unlock_irqrestore(&ucontext->srq_reg_mem_list_lock, flags);
-       if (!iwpbl)
-               return -EPROTO;
+       if (attrs && uverbs_attr_is_valid(attrs, 
UVERBS_ATTR_CREATE_SRQ_BUF_UMEM)) {
+               struct irdma_mem_reg_req srq_req = {};
+               struct ib_umem *umem;
+               u32 total;
+               u8 shift;
 
-       iwsrq->iwpbl = iwpbl;
+               irdma_get_wqe_shift(ukinfo->uk_attrs, ukinfo->max_srq_frag_cnt, 
0, &shift);
+               srq_req.rq_pages =
+                       DIV_ROUND_UP((ukinfo->srq_size << shift) * 
IRDMA_QP_WQE_MIN_SIZE,
+                                    IRDMA_HW_PAGE_SIZE);
+               total = srq_req.rq_pages + IRDMA_SHADOW_PGCNT;
+
+               umem = ib_umem_get_attr(&iwdev->ibdev, attrs,
+                                       UVERBS_ATTR_CREATE_SRQ_BUF_UMEM,
+                                       total << IRDMA_HW_PAGE_SHIFT,
+                                       IB_ACCESS_LOCAL_WRITE);
+               if (IS_ERR(umem))
+                       return PTR_ERR(umem);
+
+               iwsrq->iwpbl = irdma_setup_q_pbl_from_umem(iwdev, umem,
+                                                          iwsrq->ibsrq.pd,
+                                                          
IRDMA_MEMREG_TYPE_SRQ,
+                                                          &srq_req);
+               if (IS_ERR(iwsrq->iwpbl)) {
+                       ret = PTR_ERR(iwsrq->iwpbl);
+                       iwsrq->iwpbl = NULL;
+                       ib_umem_release(umem);
+                       return ret;
+               }
+               iwpbl = iwsrq->iwpbl;
+       } else {
+               if (!req.user_srq_buf)
+                       return -EINVAL;
+
+               spin_lock_irqsave(&ucontext->srq_reg_mem_list_lock, flags);
+               iwpbl = irdma_get_pbl((unsigned long)req.user_srq_buf,
+                                     &ucontext->srq_reg_mem_list);
+               spin_unlock_irqrestore(&ucontext->srq_reg_mem_list_lock, flags);
+               if (!iwpbl)
+                       return -EPROTO;
+
+               iwsrq->iwpbl = iwpbl;
+       }
        srqmr = &iwpbl->srq_mr;
 
        if (iwpbl->pbl_allocated) {
@@ -2615,7 +2658,12 @@ static int irdma_create_srq(struct ib_srq *ibsrq,
        if (iwsrq->user_mode && iwsrq->iwpbl) {
                struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
 
-               refcount_dec(&iwmr->user_ring_refs);
+               if (iwmr && refcount_dec_and_test(&iwmr->user_ring_refs)) {
+                       ib_umem_release(iwmr->region);
+                       if (iwsrq->iwpbl->pbl_allocated)
+                               irdma_free_pble(rf->pble_rsrc, 
&iwsrq->iwpbl->pble_alloc);
+                       kfree(iwmr);
+               }
        }
        irdma_free_rsrc(rf, rf->allocated_srqs, iwsrq->srq_num);
        return err_code;
-- 
2.56.0.317.g454f8302e1-goog

Reply via email to