summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/hw/bnxt_re/bnxt_re.h6
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c87
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.h6
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c4
-rw-r--r--drivers/infiniband/hw/bnxt_re/uapi.c85
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;