diff options
| -rw-r--r-- | drivers/infiniband/hw/bnxt_re/bnxt_re.h | 6 | ||||
| -rw-r--r-- | drivers/infiniband/hw/bnxt_re/ib_verbs.c | 87 | ||||
| -rw-r--r-- | drivers/infiniband/hw/bnxt_re/ib_verbs.h | 6 | ||||
| -rw-r--r-- | drivers/infiniband/hw/bnxt_re/main.c | 4 | ||||
| -rw-r--r-- | drivers/infiniband/hw/bnxt_re/uapi.c | 85 |
5 files changed, 107 insertions, 81 deletions
diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index 3a7ce4729fcf..a43e678151d3 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -41,7 +41,6 @@ #define __BNXT_RE_H__ #include <rdma/uverbs_ioctl.h> #include "hw_counters.h" -#include <linux/hashtable.h> #define ROCE_DRV_MODULE_NAME "bnxt_re" #define BNXT_RE_DESC "Broadcom NetXtreme-C/E RoCE Driver" @@ -158,9 +157,6 @@ struct bnxt_re_nq_record { struct mutex load_lock; }; -#define MAX_CQ_HASH_BITS (16) -#define MAX_SRQ_HASH_BITS (16) - static inline bool bnxt_re_chip_gen_p7(u16 chip_num) { return (chip_num == CHIP_NUM_58818 || @@ -215,8 +211,6 @@ struct bnxt_re_dev { struct bnxt_re_pacing pacing; struct work_struct dbq_fifo_check_work; struct delayed_work dbq_pacing_work; - DECLARE_HASHTABLE(cq_hash, MAX_CQ_HASH_BITS); - DECLARE_HASHTABLE(srq_hash, MAX_SRQ_HASH_BITS); struct dentry *dbg_root; struct dentry *qp_debugfs; unsigned long event_bitmap; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index a2a354a0fbef..9184b2b95834 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2151,11 +2151,26 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata) if (ret) return ret; - if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) - hash_del(&srq->hash_entry); + if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) { + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + + /* + * Untrack the SRQ before releasing its hardware ID below, so a + * concurrent create that gets the same ID reused by firmware + * cannot have its fresh XArray entry erased by this destroy. + */ + if (uctx) + xa_erase(&uctx->srq_xa, srq->qplib_srq.id); + } bnxt_qplib_destroy_srq(&rdev->qplib_res, qplib_srq); - if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) - free_page((unsigned long)srq->uctx_srq_page); + if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) { + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + + if (uctx) + free_page((unsigned long)srq->uctx_srq_page); + } ib_umem_release(srq->umem); atomic_dec(&rdev->stats.res.srq_count); return 0; @@ -2262,20 +2277,21 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, resp.srqid = srq->qplib_srq.id; if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) { - hash_add(rdev->srq_hash, &srq->hash_entry, srq->qplib_srq.id); srq->uctx_srq_page = (void *)get_zeroed_page(GFP_KERNEL); if (!srq->uctx_srq_page) { rc = -ENOMEM; - goto fail; + goto fail_destroy_srq; + } + if (xa_is_err(xa_store(&uctx->srq_xa, srq->qplib_srq.id, + ib_srq->uobject, GFP_KERNEL))) { + rc = -ENOMEM; + goto fail_free_srq_page; } resp.comp_mask |= BNXT_RE_SRQ_TOGGLE_PAGE_SUPPORT; } rc = ib_respond_udata(udata, resp); - if (rc) { - bnxt_qplib_destroy_srq(&rdev->qplib_res, - &srq->qplib_srq); - goto fail; - } + if (rc) + goto fail_respond; } active_srqs = atomic_inc_return(&rdev->stats.res.srq_count); if (active_srqs > rdev->stats.res.srq_watermark) @@ -2284,6 +2300,17 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, return 0; +fail_respond: + if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) { + xa_erase(&uctx->srq_xa, srq->qplib_srq.id); + free_page((unsigned long)srq->uctx_srq_page); + } + bnxt_qplib_destroy_srq(&rdev->qplib_res, &srq->qplib_srq); + goto fail; +fail_free_srq_page: + free_page((unsigned long)srq->uctx_srq_page); +fail_destroy_srq: + bnxt_qplib_destroy_srq(&rdev->qplib_res, &srq->qplib_srq); fail: ib_umem_release(srq->umem); exit: @@ -3465,11 +3492,26 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) if (ret) return ret; - if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) - hash_del(&cq->hash_entry); + if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) { + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + + /* + * Untrack the CQ before releasing its hardware ID below, so a + * concurrent create that gets the same ID reused by firmware + * cannot have its fresh XArray entry erased by this destroy. + */ + if (uctx) + xa_erase(&uctx->cq_xa, cq->qplib_cq.id); + } bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq); - if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) - free_page((unsigned long)cq->uctx_cq_page); + if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) { + struct bnxt_re_ucontext *uctx = + rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); + + if (uctx) + free_page((unsigned long)cq->uctx_cq_page); + } bnxt_re_put_nq(rdev, nq); @@ -3544,14 +3586,16 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *att spin_lock_init(&cq->cq_lock); if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) { - hash_add(rdev->cq_hash, &cq->hash_entry, cq->qplib_cq.id); - /* Allocate a page */ cq->uctx_cq_page = (void *)get_zeroed_page(GFP_KERNEL); if (!cq->uctx_cq_page) { rc = -ENOMEM; goto destroy_cq; } - + if (xa_is_err(xa_store(&uctx->cq_xa, cq->qplib_cq.id, + ibcq->uobject, GFP_KERNEL))) { + rc = -ENOMEM; + goto free_cq_page; + } resp.comp_mask |= BNXT_RE_CQ_TOGGLE_PAGE_SUPPORT; } resp.cqid = cq->qplib_cq.id; @@ -3564,6 +3608,9 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *att return 0; free_mem: + if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) + xa_erase(&uctx->cq_xa, cq->qplib_cq.id); +free_cq_page: free_page((unsigned long)cq->uctx_cq_page); destroy_cq: bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq); @@ -4789,6 +4836,8 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) goto cfail; } uctx->shpage_mmap = &entry->rdma_entry; + xa_init(&uctx->cq_xa); + xa_init(&uctx->srq_xa); if (rdev->pacing.dbr_pacing) resp.comp_mask |= BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED; @@ -4841,6 +4890,8 @@ void bnxt_re_dealloc_ucontext(struct ib_ucontext *ib_uctx) uctx->shpage_mmap = NULL; if (uctx->shpg) free_page((unsigned long)uctx->shpg); + xa_destroy(&uctx->cq_xa); + xa_destroy(&uctx->srq_xa); if (uctx->dpi.dbr) { /* Free DPI only if this is the first PD allocated by the diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index 22bf81668cfb..4c78c183784b 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -70,6 +70,8 @@ struct bnxt_re_ah { struct bnxt_qplib_ah qplib_ah; }; +struct bnxt_re_user_mmap_entry; + struct bnxt_re_srq { struct ib_srq ib_srq; struct bnxt_re_dev *rdev; @@ -78,7 +80,6 @@ struct bnxt_re_srq { struct ib_umem *umem; spinlock_t lock; /* protect srq */ void *uctx_srq_page; - struct hlist_node hash_entry; }; struct bnxt_re_qp { @@ -113,7 +114,6 @@ struct bnxt_re_cq { struct ib_umem *resize_umem; int resize_cqe; void *uctx_cq_page; - struct hlist_node hash_entry; }; struct bnxt_re_mr { @@ -147,6 +147,8 @@ struct bnxt_re_ucontext { void *shpg; spinlock_t sh_lock; /* protect shpg */ struct rdma_user_mmap_entry *shpage_mmap; + struct xarray cq_xa; /* cqid → ib_uobject, per-context toggle page lookup */ + struct xarray srq_xa; /* srqid → ib_uobject, per-context toggle page lookup */ u64 cmask; }; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index d25fdc458120..ce72db1b4bc3 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -2337,10 +2337,6 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) if (!(rdev->qplib_res.en_dev->flags & BNXT_EN_FLAG_ROCE_VF_RES_MGMT)) bnxt_re_vf_res_config(rdev); } - hash_init(rdev->cq_hash); - if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) - hash_init(rdev->srq_hash); - bnxt_re_debugfs_add_pdev(rdev); bnxt_re_init_dcb_wq(rdev); diff --git a/drivers/infiniband/hw/bnxt_re/uapi.c b/drivers/infiniband/hw/bnxt_re/uapi.c index 263238a6e4cd..c5e4e6e47b5f 100644 --- a/drivers/infiniband/hw/bnxt_re/uapi.c +++ b/drivers/infiniband/hw/bnxt_re/uapi.c @@ -22,31 +22,6 @@ #include "bnxt_re.h" #include "ib_verbs.h" -static struct bnxt_re_cq *bnxt_re_search_for_cq(struct bnxt_re_dev *rdev, u32 cq_id) -{ - struct bnxt_re_cq *cq = NULL, *tmp_cq; - - hash_for_each_possible(rdev->cq_hash, tmp_cq, hash_entry, cq_id) { - if (tmp_cq->qplib_cq.id == cq_id) { - cq = tmp_cq; - break; - } - } - return cq; -} - -static struct bnxt_re_srq *bnxt_re_search_for_srq(struct bnxt_re_dev *rdev, u32 srq_id) -{ - struct bnxt_re_srq *srq = NULL, *tmp_srq; - - hash_for_each_possible(rdev->srq_hash, tmp_srq, hash_entry, srq_id) { - if (tmp_srq->qplib_srq.id == srq_id) { - srq = tmp_srq; - break; - } - } - return srq; -} static int UVERBS_HANDLER(BNXT_RE_METHOD_NOTIFY_DRV)(struct uverbs_attr_bundle *attrs) { @@ -244,12 +219,10 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund enum bnxt_re_mmap_flag mmap_flag = BNXT_RE_MMAP_TOGGLE_PAGE; enum bnxt_re_get_toggle_mem_type res_type; struct bnxt_re_user_mmap_entry *entry; + struct ib_uobject *res_uobj; struct bnxt_re_ucontext *uctx; struct ib_ucontext *ib_uctx; - struct bnxt_re_dev *rdev; - struct bnxt_re_srq *srq; u32 length = PAGE_SIZE; - struct bnxt_re_cq *cq; u64 mem_offset; u32 offset = 0; u64 addr = 0; @@ -265,35 +238,45 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund return err; uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); - rdev = uctx->rdev; err = uverbs_copy_from(&res_id, attrs, BNXT_RE_TOGGLE_MEM_RES_ID); if (err) return err; - switch (res_type) { - case BNXT_RE_CQ_TOGGLE_MEM: - cq = bnxt_re_search_for_cq(rdev, res_id); - if (!cq) - return -EINVAL; - - addr = (u64)cq->uctx_cq_page; - if (!addr) - return -EOPNOTSUPP; - break; - case BNXT_RE_SRQ_TOGGLE_MEM: - srq = bnxt_re_search_for_srq(rdev, res_id); - if (!srq) - return -EINVAL; - - addr = (u64)srq->uctx_srq_page; - if (!addr) - return -EOPNOTSUPP; - break; - - default: + /* + * bnxt_re_create_cq/srq() publishes the uobject into cq_xa/srq_xa + * before returning to the uverbs core, but the core only sets + * uobject->object once the create callback has returned success. + * A lookup that races with an in-progress create can therefore + * find a uobject whose ->object is still NULL; skip it instead of + * feeding NULL to container_of(). + */ + if (res_type == BNXT_RE_CQ_TOGGLE_MEM) { + struct bnxt_re_cq *cq; + + xa_lock(&uctx->cq_xa); + res_uobj = xa_load(&uctx->cq_xa, res_id); + if (res_uobj && res_uobj->object) { + cq = container_of(res_uobj->object, struct bnxt_re_cq, ib_cq); + addr = (u64)cq->uctx_cq_page; + } + xa_unlock(&uctx->cq_xa); + } else if (res_type == BNXT_RE_SRQ_TOGGLE_MEM) { + struct bnxt_re_srq *srq; + + xa_lock(&uctx->srq_xa); + res_uobj = xa_load(&uctx->srq_xa, res_id); + if (res_uobj && res_uobj->object) { + srq = container_of(res_uobj->object, struct bnxt_re_srq, ib_srq); + addr = (u64)srq->uctx_srq_page; + } + xa_unlock(&uctx->srq_xa); + } else { return -EOPNOTSUPP; } + if (!addr) + return -EOPNOTSUPP; + entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mem_offset); if (!entry) return -ENOMEM; @@ -322,7 +305,7 @@ static int get_toggle_mem_obj_cleanup(struct ib_uobject *uobject, enum rdma_remove_reason why, struct uverbs_attr_bundle *attrs) { - struct bnxt_re_user_mmap_entry *entry = uobject->object; + struct bnxt_re_user_mmap_entry *entry = uobject->object; rdma_user_mmap_entry_remove(&entry->rdma_entry); return 0; |
