RDMA/bnxt_re: Generic driver fixes
Subsystems (2)
Selvin Xavier
maintainerv2 cover RDMA/bnxt_re: Generic driver fixes
Includes fixes for few issues pointed by sashiko. Also, some generic fixes found during internal code reviews.
Please review and Apply.
Thanks,
Selvin Xavier
v1 -> v2:
- Added patches for SRQ/CQ resource teardown in HW before freeing the toggle page to avoid any access from NQ processing after the page is freed
- Fixed synchronization issues pointer for Sasiko for the patch that handles multiple WC page allocation
- Adding a cq and srq reference to avoid UAF
- Add a zero check ureq->sq_slots
- Adds a rollback code when ioremap fails
- Handles request to getting toggle mem on devices that doesn't support the feature
Selvin Xavier (15):
RDMA/bnxt_re: Initialize dpi variable to zero RDMA/bnxt_re: Free SRQ toggle page after firmware teardown RDMA/bnxt_re: Free CQ toggle page after firmware teardown RDMA/bnxt_re: Avoid any race while handling the hash list of CQ RDMA/bnxt_re: Avoid any race while handling the hash list of SRQ RDMA/bnxt_re: Add ownership check while getting the CQ toggle page RDMA/bnxt_re: Add ownership check while getting the SRQ toggle page RDMA/bnxt_re: Avoid displaying the kernel pointer RDMA/bnxt_re: Add a max slot check for SQ
RDMA/bnxt_re: Proper rollback if the ioremap fails RDMA/bnxt_re: Avoid repeated requests to allocate WC pages RDMA/bnxt_re: Fix the cleanup upon error during SRQ create RDMA/bnxt_re: Fix the cleanup upon error during CQ create RDMA/bnxt_re: Fail DBR related page allocation UAPIs if the feature is
disabled
RDMA/bnxt_re: Reject GET_TOGGLE_MEM when toggle page was not allocated
drivers/infiniband/hw/bnxt_re/bnxt_re.h | 2 + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 97 +++++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 9 +++ drivers/infiniband/hw/bnxt_re/main.c | 4 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 11 +++ drivers/infiniband/hw/bnxt_re/qplib_sp.h | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 61 ++++++++++++-- 7 files changed, 169 insertions(+), 16 deletions(-)
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 1/15 RDMA/bnxt_re: Initialize dpi variable to zero
dpi is initialized only for BNXT_RE_ALLOC_WC_PAGE, but copied for all the cases. So initialize the dpi to 0.
--- drivers/infiniband/hw/bnxt_re/uapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/bnxt_re/uapi.c +1 -1
@@ -76,8 +76,8 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *struct ib_ucontext *ib_uctx;struct bnxt_re_dev *rdev;u64 mmap_offset; +u32 dpi =0 ;u32 length; -u32 dpi;u64 addr;int err;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 2/15 RDMA/bnxt_re: Free SRQ toggle page after firmware teardown
In reply to Selvin XavierFree the toggle page only after firmware teardown completes so that an NQ interrupt arriving during bnxt_qplib_destroy_srq() won't write the toggle values to an already-freed page. Move free_page() after bnxt_qplib_destroy_srq().
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +3 -3
@@ -2149,11 +2149,11 @@ 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 ) { -free_page ((unsigned long )srq->uctx_srq_page); +if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT )hash_del (&srq->hash_entry); - }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);ib_umem_release (srq->umem);atomic_dec (&rdev->stats.res.srq_count);return ib_respond_empty_udata (udata);
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 3/15 RDMA/bnxt_re: Free CQ toggle page after firmware teardown
In reply to Selvin XavierFree the toggle page only after firmware teardown completes so that an NQ interrupt arriving during bnxt_qplib_destroy_cq() won't write the toggle value to an already-freed page. Move free_page() after bnxt_qplib_destroy_cq.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +3 -3
@@ -3452,11 +3452,11 @@ 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 ) { -free_page ((unsigned long )cq->uctx_cq_page); +if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT )hash_del (&cq->hash_entry); - }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);bnxt_re_put_nq (rdev, nq);
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 4/15 RDMA/bnxt_re: Avoid any race while handling the hash list of CQ
In reply to Selvin XavierAdd/Delete to/from hash list needs to be synchronized with the traversing of the hash list. Add a mutex for this synchronization. Also add a reference for the CQ to avoid any usage of the CQ structures after the CQ is freed.
--- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 1 + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 28 ++++++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 3 +++ drivers/infiniband/hw/bnxt_re/main.c | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 4 ++++ 5 files changed, 35 insertions(+), 2 deletions(-)
drivers/infiniband/hw/bnxt_re/bnxt_re.h +1 -0
@@ -217,6 +217,7 @@ struct bnxt_re_dev {struct delayed_work dbq_pacing_work;DECLARE_HASHTABLE (cq_hash,MAX_CQ_HASH_BITS );DECLARE_HASHTABLE (srq_hash,MAX_SRQ_HASH_BITS ); +struct mutex cq_hash_lock;/* guards cq_hash */ struct dentry *dbg_root;struct dentry *qp_debugfs;unsigned long event_bitmap;
drivers/infiniband/hw/bnxt_re/ib_verbs.c +26 -2
@@ -3435,6 +3435,18 @@ static void bnxt_re_put_nq(struct bnxt_re_dev *rdev, struct bnxt_qplib_nq *nq) }/* Completion Queues */ +static void bnxt_re_cq_release (struct kref *ref) +{ + struct bnxt_re_cq *cq = container_of(ref, struct bnxt_re_cq, cq_ref); + +complete (&cq->cq_destroy_comp); +} + +void bnxt_re_put_cq (struct bnxt_re_cq *cq) +{ +kref_put (&cq->cq_ref, bnxt_re_cq_release); +} +int bnxt_re_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) {struct bnxt_qplib_chip_ctx *cctx;
@@ -3452,10 +3464,18 @@ 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 ) +if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT && cq->uctx) { +mutex_lock (&rdev->cq_hash_lock);hash_del (&cq->hash_entry); +mutex_unlock (&rdev->cq_hash_lock); +/* Drop the creator's reference and wait for any concurrent +* bnxt_re_search_for_cq() caller to finish with the pointer. +*/ +kref_put (&cq->cq_ref, bnxt_re_cq_release); +wait_for_completion (&cq->cq_destroy_comp); + }bnxt_qplib_destroy_cq (&rdev->qplib_res, &cq->qplib_cq); -if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT ) +if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT && cq->uctx)free_page ((unsigned long )cq->uctx_cq_page);bnxt_re_put_nq (rdev, nq);
@@ -3531,7 +3551,11 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attspin_lock_init (&cq->cq_lock);if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT ) { +kref_init (&cq->cq_ref); +init_completion (&cq->cq_destroy_comp); +mutex_lock (&rdev->cq_hash_lock);hash_add (rdev->cq_hash, &cq->hash_entry, cq->qplib_cq.id); +mutex_unlock (&rdev->cq_hash_lock);/* Allocate a page */ cq->uctx_cq_page = (void *)get_zeroed_page (GFP_KERNEL );if (!cq->uctx_cq_page) {
drivers/infiniband/hw/bnxt_re/ib_verbs.h +3 -0
@@ -114,6 +114,8 @@ struct bnxt_re_cq {int resize_cqe;void *uctx_cq_page;struct hlist_node hash_entry; +struct kref cq_ref; +struct completion cq_destroy_comp; };struct bnxt_re_mr {
@@ -265,6 +267,7 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attint bnxt_re_resize_cq (struct ib_cq *ibcq,unsigned int cqe,struct ib_udata *udata);int bnxt_re_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +void bnxt_re_put_cq (struct bnxt_re_cq *cq);int bnxt_re_poll_cq (struct ib_cq *cq,int num_entries,struct ib_wc *wc);int bnxt_re_req_notify_cq (struct ib_cq *cq,enum ib_cq_notify_flags flags);struct ib_mr *bnxt_re_get_dma_mr (struct ib_pd *pd,int mr_access_flags);
drivers/infiniband/hw/bnxt_re/main.c +1 -0
@@ -2340,6 +2340,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type)bnxt_re_vf_res_config (rdev); }hash_init (rdev->cq_hash); +mutex_init (&rdev->cq_hash_lock);if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT )hash_init (rdev->srq_hash);
drivers/infiniband/hw/bnxt_re/uapi.c +4 -0
@@ -26,12 +26,15 @@ static struct bnxt_re_cq *bnxt_re_search_for_cq(struct bnxt_re_dev *rdev, u32 cq {struct bnxt_re_cq *cq =NULL , *tmp_cq; +mutex_lock (&rdev->cq_hash_lock);hash_for_each_possible (rdev->cq_hash, tmp_cq, hash_entry, cq_id) {if (tmp_cq->qplib_cq.id == cq_id) { +kref_get (&tmp_cq->cq_ref); cq = tmp_cq;break ; } } +mutex_unlock (&rdev->cq_hash_lock);return cq; }
@@ -252,6 +255,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundreturn -EINVAL ; addr = (u64 )cq->uctx_cq_page; +bnxt_re_put_cq (cq);break ;case BNXT_RE_SRQ_TOGGLE_MEM : srq =bnxt_re_search_for_srq (rdev, res_id);
Signature · 1 line
2.39.3
Jason Gunthorpe
maintainerRe: [PATCH rdma-rc v2 04/15] RDMA/bnxt_re: Avoid any race while handling the hash list of CQ
Quoted 4 lines · Selvin Xavier
Add/Delete to/from hash list needs to be synchronized with the traversing of the hash list. Add a mutex for this synchronization. Also add a reference for the CQ to avoid any usage of the CQ structures after the CQ is freed.
Arg, this is messed up like this because the driver didn't implement the uapi properly:
drivers/infiniband/hw/bnxt_re/uapi.c static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund · line 259
Quoted 6 lines
drivers/infiniband/hw/bnxt_re/uapi.c +1
-0@@ -252,6 +255,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundreturn -EINVAL ; addr = (u64 )cq->uctx_cq_page; +bnxt_re_put_cq (cq);break ;
Passing in uobj's through anything but the normal UVERBS_ATTR_IDR is completely wrong.
And now the security model is messed up because the broken bnxt_re_search_for_cq() doesn't respect the uctx boundaries and the userspace can pass in any cq belonging to any process for this operation. That's illegal.
I said the same thing on the dbr patches and they were fixed to use
+ uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_DBR_HANDLE);
Which is the correct way to reach into other objects and prevents all of these bugs.
Fixing this by adding more mess to the driver isn't right, you need to rely on the uobject system to do this. Once you find the driver object you'll need to call some new uobject function to validate and lock it properly using object locking. Do not add new refcounts and completions.
Jason
Selvin Xavier
maintainerPATCH v2 5/15 RDMA/bnxt_re: Avoid any race while handling the hash list of SRQ
In reply to Selvin XavierAdd/Delete to/from hash list needs to be synchronized with the traversing of the hash list. Add a mutex for this synchronization to avoid any usage of the SRQ structures after the SRQ is freed.
--- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 1 + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 29 ++++++++++++++++++++++-- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 3 +++ drivers/infiniband/hw/bnxt_re/main.c | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 4 ++++ 5 files changed, 36 insertions(+), 2 deletions(-)
drivers/infiniband/hw/bnxt_re/bnxt_re.h +1 -0
@@ -218,6 +218,7 @@ struct bnxt_re_dev {DECLARE_HASHTABLE (cq_hash,MAX_CQ_HASH_BITS );DECLARE_HASHTABLE (srq_hash,MAX_SRQ_HASH_BITS );struct mutex cq_hash_lock;/* guards cq_hash */ +struct mutex srq_hash_lock;/* guards srq_hash */ struct dentry *dbg_root;struct dentry *qp_debugfs;unsigned long event_bitmap;
drivers/infiniband/hw/bnxt_re/ib_verbs.c +27 -2
@@ -2137,6 +2137,19 @@ static enum ib_mtu __to_ib_mtu(u32 mtu) }/* Shared Receive Queues */ +/* Shared Receive Queue lifetime helpers */ +static void bnxt_re_srq_release (struct kref *ref) +{ + struct bnxt_re_srq *srq = container_of(ref, struct bnxt_re_srq, srq_ref); + +complete (&srq->srq_destroy_comp); +} + +void bnxt_re_put_srq (struct bnxt_re_srq *srq) +{ +kref_put (&srq->srq_ref, bnxt_re_srq_release); +} +int bnxt_re_destroy_srq (struct ib_srq *ib_srq,struct ib_udata *udata) { struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
@@ -2149,10 +2162,18 @@ 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 ) +if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT && srq->uctx) { +mutex_lock (&rdev->srq_hash_lock);hash_del (&srq->hash_entry); +mutex_unlock (&rdev->srq_hash_lock); +/* Drop the creator's reference and wait for any concurrent +* bnxt_re_search_for_srq() caller to finish with the pointer. +*/ +kref_put (&srq->srq_ref, bnxt_re_srq_release); +wait_for_completion (&srq->srq_destroy_comp); + }bnxt_qplib_destroy_srq (&rdev->qplib_res, qplib_srq); -if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT ) +if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT && srq->uctx)free_page ((unsigned long )srq->uctx_srq_page);ib_umem_release (srq->umem);atomic_dec (&rdev->stats.res.srq_count);
@@ -2260,7 +2281,11 @@ 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 ) { +kref_init (&srq->srq_ref); +init_completion (&srq->srq_destroy_comp); +mutex_lock (&rdev->srq_hash_lock);hash_add (rdev->srq_hash, &srq->hash_entry, srq->qplib_srq.id); +mutex_unlock (&rdev->srq_hash_lock); srq->uctx_srq_page = (void *)get_zeroed_page (GFP_KERNEL );if (!srq->uctx_srq_page) { rc = -ENOMEM ;
drivers/infiniband/hw/bnxt_re/ib_verbs.h +3 -0
@@ -79,6 +79,8 @@ struct bnxt_re_srq {spinlock_t lock;/* protect srq */ void *uctx_srq_page;struct hlist_node hash_entry; +struct kref srq_ref; +struct completion srq_destroy_comp; };struct bnxt_re_qp {
@@ -247,6 +249,7 @@ int bnxt_re_modify_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr, struct ib_udata *udata);int bnxt_re_query_srq (struct ib_srq *srq,struct ib_srq_attr *srq_attr);int bnxt_re_destroy_srq (struct ib_srq *srq,struct ib_udata *udata); +void bnxt_re_put_srq (struct bnxt_re_srq *srq);int bnxt_re_post_srq_recv (struct ib_srq *srq,const struct ib_recv_wr *recv_wr,const struct ib_recv_wr **bad_recv_wr); int bnxt_re_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *qp_init_attr,
drivers/infiniband/hw/bnxt_re/main.c +1 -0
@@ -2343,6 +2343,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type)mutex_init (&rdev->cq_hash_lock);if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT )hash_init (rdev->srq_hash); +mutex_init (&rdev->srq_hash_lock);bnxt_re_debugfs_add_pdev (rdev);
drivers/infiniband/hw/bnxt_re/uapi.c +4 -0
@@ -42,12 +42,15 @@ static struct bnxt_re_srq *bnxt_re_search_for_srq(struct bnxt_re_dev *rdev, u32 {struct bnxt_re_srq *srq =NULL , *tmp_srq; +mutex_lock (&rdev->srq_hash_lock);hash_for_each_possible (rdev->srq_hash, tmp_srq, hash_entry, srq_id) {if (tmp_srq->qplib_srq.id == srq_id) { +kref_get (&tmp_srq->srq_ref); srq = tmp_srq;break ; } } +mutex_unlock (&rdev->srq_hash_lock);return srq; }
@@ -263,6 +266,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundreturn -EINVAL ; addr = (u64 )srq->uctx_srq_page; +bnxt_re_put_srq (srq);break ;default :
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 6/15 RDMA/bnxt_re: Add ownership check while getting the CQ toggle page
In reply to Selvin XavierThe cq resource id provided by user-space is used for searching the driver CQ structure. Validate if the context currently issuing the request is same as the context created the resource.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 + drivers/infiniband/hw/bnxt_re/ib_verbs.h | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 5 +++++ 3 files changed, 7 insertions(+)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +1 -0
@@ -3534,6 +3534,7 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attreturn -EINVAL ; cq->rdev = rdev; + cq->uctx = &uctx->ib_uctx; cctx = rdev->chip_ctx; cq->qplib_cq.cq_handle = (u64 )(unsigned long )(&cq->qplib_cq);
drivers/infiniband/hw/bnxt_re/ib_verbs.h +1 -0
@@ -104,6 +104,7 @@ struct bnxt_re_qp {struct bnxt_re_cq {struct ib_cq ib_cq;struct bnxt_re_dev *rdev; +struct ib_ucontext *uctx;spinlock_t cq_lock;/* protect cq */ u16 cq_count;u16 cq_period;
drivers/infiniband/hw/bnxt_re/uapi.c +5 -0
@@ -257,6 +257,11 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundif (!cq)return -EINVAL ; +if (cq->uctx != ib_uctx) { +bnxt_re_put_cq (cq); +return -EINVAL ; + } + addr = (u64 )cq->uctx_cq_page;bnxt_re_put_cq (cq);break ;
Signature · 1 line
2.39.3
Jason Gunthorpe
maintainerRe: [PATCH rdma-rc v2 06/15] RDMA/bnxt_re: Add ownership check while getting the CQ toggle page
Quoted 4 lines · Selvin Xavier
The cq resource id provided by user-space is used for searching the driver CQ structure. Validate if the context currently issuing the request is same as the context created the resource.
Hah, just like I said - again fix it by using uobjects correctly, not adding more junk into the driver.
Jason
Selvin Xavier
maintainerPATCH v2 7/15 RDMA/bnxt_re: Add ownership check while getting the SRQ toggle page
In reply to Selvin XavierThe SRQ resource id provided by user-space is used for searching the driver SRQ structure. Validate if the context currently issuing the request is same as the context created the resource.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 + drivers/infiniband/hw/bnxt_re/ib_verbs.h | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 5 +++++ 3 files changed, 7 insertions(+)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +1 -0
@@ -2246,6 +2246,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); srq->rdev = rdev; + srq->uctx = uctx ? &uctx->ib_uctx :NULL ; srq->qplib_srq.pd = &pd->qplib_pd; srq->qplib_srq.dpi = &rdev->dpi_privileged;/* Allocate 1 more than what's provided so posting max doesn't
drivers/infiniband/hw/bnxt_re/ib_verbs.h +1 -0
@@ -73,6 +73,7 @@ struct bnxt_re_ah {struct bnxt_re_srq {struct ib_srq ib_srq;struct bnxt_re_dev *rdev; +struct ib_ucontext *uctx;u32 srq_limit;struct bnxt_qplib_srq qplib_srq;struct ib_umem *umem;
drivers/infiniband/hw/bnxt_re/uapi.c +5 -0
@@ -270,6 +270,11 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundif (!srq)return -EINVAL ; +if (srq->uctx != ib_uctx) { +bnxt_re_put_srq (srq); +return -EINVAL ; + } + addr = (u64 )srq->uctx_srq_page;bnxt_re_put_srq (srq);break ;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 8/15 RDMA/bnxt_re: Avoid displaying the kernel pointer
In reply to Selvin XavierWhile dumping the info on MR using the rdma tool, we dump the mr_hwq which is a kernel pointer. There is no need to expose this value for end user. So avoid it.
--- drivers/infiniband/hw/bnxt_re/main.c | 2 -- 1 file changed, 2 deletions(-)
drivers/infiniband/hw/bnxt_re/main.c +0 -2
@@ -1093,8 +1093,6 @@ static int bnxt_re_fill_res_mr_entry(struct sk_buff *msg, struct ib_mr *ib_mr) goto err;if (rdma_nl_put_driver_u32 (msg,"element_size" , mr_hwq->element_size)) goto err; -if (rdma_nl_put_driver_u64_hex (msg,"hwq" , (unsigned long )mr_hwq)) - goto err;if (rdma_nl_put_driver_u64_hex (msg,"va" , mr->qplib_mr.va)) goto err;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 9/15 RDMA/bnxt_re: Add a max slot check for SQ
In reply to Selvin XavierThe variable WQE mode must be validated against the maximum slots supported by HW. The max supported value is 64K. Adding a max and min check and fail if user supplied value is more than the max supported and zero.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 3 +++ drivers/infiniband/hw/bnxt_re/qplib_sp.h | 1 + 2 files changed, 4 insertions(+)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +3 -0
@@ -1748,6 +1748,9 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,return qptype; qplqp->type = (u8 )qptype; qplqp->wqe_mode =bnxt_re_is_var_size_supported (rdev, uctx); +if (uctx && qplqp->wqe_mode ==BNXT_QPLIB_WQE_MODE_VARIABLE && + (!ureq->sq_slots || ureq->sq_slots >BNXT_RE_MAX_SQ_SLOTS )) +return -EINVAL ;if (fixed_que_attr) {if (qplqp->wqe_mode !=BNXT_QPLIB_WQE_MODE_VARIABLE )return -EOPNOTSUPP ;
drivers/infiniband/hw/bnxt_re/qplib_sp.h +1 -0
@@ -369,6 +369,7 @@ int bnxt_qplib_destroy_flow(struct bnxt_qplib_res *res);#define BNXT_VAR_MAX_SLOT_ALIGN 256#define BNXT_VAR_MAX_SGE 13#define BNXT_RE_MAX_RQ_WQES 65536 +#define BNXT_RE_MAX_SQ_SLOTS 65536#define BNXT_STATIC_MAX_SGE 6
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 10/15 RDMA/bnxt_re: Proper rollback if the ioremap fails
In reply to Selvin Xavierbnxt_qplib_alloc_dpi returns success even if ioremap fails. Add the proper rollback when the ioremap fails and return -ENOMEM status.
--- drivers/infiniband/hw/bnxt_re/qplib_res.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/infiniband/hw/bnxt_re/qplib_res.c +11 -0
@@ -764,9 +764,13 @@ int bnxt_qplib_alloc_dpi(struct bnxt_qplib_res *res,break ;case BNXT_QPLIB_DPI_TYPE_WC : dpi->dbr =ioremap_wc (umaddr,PAGE_SIZE ); +if (!dpi->dbr) + goto fail_ioremap;break ;default : dpi->dbr =ioremap (umaddr,PAGE_SIZE ); +if (!dpi->dbr) + goto fail_ioremap;break ; }
@@ -774,6 +778,13 @@ int bnxt_qplib_alloc_dpi(struct bnxt_qplib_res *res,mutex_unlock (&res->dpi_tbl_lock);return 0 ; +fail_ioremap: +/* Roll back the bit we just claimed. */ +set_bit (bit_num, dpit->tbl); + dpit->app_tbl[bit_num] =NULL ; +mutex_unlock (&res->dpi_tbl_lock); +return -ENOMEM ; + } int bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res,
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 11/15 RDMA/bnxt_re: Avoid repeated requests to allocate WC pages
In reply to Selvin XavierApplications can request multiple WC pages for the same ucontext. As of now, only 1 WC page per ucontext is supported. Add a lock to avoid concurrent access and a check to fail repeated requests. Also, if the mmap entry insert fails for the WC, free the Doorbell page index mapped for the WC page.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 + drivers/infiniband/hw/bnxt_re/ib_verbs.h | 1 + drivers/infiniband/hw/bnxt_re/uapi.c | 33 +++++++++++++++++++----- 3 files changed, 29 insertions(+), 6 deletions(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +1 -0
@@ -4801,6 +4801,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata) goto fail; }spin_lock_init (&uctx->sh_lock); +mutex_init (&uctx->wcdpi_lock); resp.comp_mask =BNXT_RE_UCNTX_CMASK_HAVE_CCTX ; chip_met_rev_num = rdev->chip_ctx->chip_num;
drivers/infiniband/hw/bnxt_re/ib_verbs.h +1 -0
@@ -149,6 +149,7 @@ struct bnxt_re_ucontext {struct bnxt_re_dev *rdev;struct bnxt_qplib_dpi dpi;struct bnxt_qplib_dpi wcdpi; +struct mutex wcdpi_lock;/* serialises WC DPI alloc/free */ void *shpg;spinlock_t sh_lock;/* protect shpg */ struct rdma_user_mmap_entry *shpage_mmap;
drivers/infiniband/hw/bnxt_re/uapi.c +27 -6
@@ -104,14 +104,23 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *switch (alloc_type) {case BNXT_RE_ALLOC_WC_PAGE : -if (cctx->modes.db_push) { +if (cctx->modes.db_push) { +mutex_lock (&uctx->wcdpi_lock); +/* already allocated — one WC page per context */ +if (uctx->wcdpi.dbr) { +mutex_unlock (&uctx->wcdpi_lock); +return -EEXIST ; + }if (bnxt_qplib_alloc_dpi (&rdev->qplib_res, &uctx->wcdpi, - uctx,BNXT_QPLIB_DPI_TYPE_WC )) + uctx,BNXT_QPLIB_DPI_TYPE_WC )) { +mutex_unlock (&uctx->wcdpi_lock);return -ENOMEM ; + } length =PAGE_SIZE ; dpi = uctx->wcdpi.dpi; addr = (u64 )uctx->wcdpi.umdbr; mmap_flag =BNXT_RE_MMAP_WC_DB ; +mutex_unlock (&uctx->wcdpi_lock); }else {return -EINVAL ; }
@@ -134,8 +143,15 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle * } entry =bnxt_re_mmap_entry_insert (uctx, addr, mmap_flag, &mmap_offset); -if (!entry) +if (!entry) { +if (mmap_flag ==BNXT_RE_MMAP_WC_DB ) { +mutex_lock (&uctx->wcdpi_lock); +bnxt_qplib_dealloc_dpi (&rdev->qplib_res, &uctx->wcdpi); + uctx->wcdpi.dbr =NULL ; +mutex_unlock (&uctx->wcdpi_lock); + }return -ENOMEM ; + } uobj->object = entry;uverbs_finalize_uobj_create (attrs,BNXT_RE_ALLOC_PAGE_HANDLE );
@@ -166,11 +182,16 @@ static int alloc_page_obj_cleanup(struct ib_uobject *uobject,switch (entry->mmap_flag) {case BNXT_RE_MMAP_WC_DB : -if (uctx && uctx->wcdpi.dbr) { +if (uctx) {struct bnxt_re_dev *rdev = uctx->rdev; -bnxt_qplib_dealloc_dpi (&rdev->qplib_res, &uctx->wcdpi); - uctx->wcdpi.dbr =NULL ; +mutex_lock (&uctx->wcdpi_lock); +if (uctx->wcdpi.dbr) { +bnxt_qplib_dealloc_dpi (&rdev->qplib_res, + &uctx->wcdpi); + uctx->wcdpi.dbr =NULL ; + } +mutex_unlock (&uctx->wcdpi_lock); }break ;case BNXT_RE_MMAP_DBR_BAR :
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 12/15 RDMA/bnxt_re: Fix the cleanup upon error during SRQ create
In reply to Selvin XavierFix the failure path of SRQ create. Destroy the SRQ from HW and delete from the hashlist if the page allocation fails. Wait for any concurrent bnxt_re_search_for_srq() caller to release the pointer before the RDMA core frees the object. Also add an explicit check for NULL before calling free_page.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +15 -0
@@ -2293,6 +2293,8 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, srq->uctx_srq_page = (void *)get_zeroed_page (GFP_KERNEL );if (!srq->uctx_srq_page) { rc = -ENOMEM ; +bnxt_qplib_destroy_srq (&rdev->qplib_res, + &srq->qplib_srq); goto fail; } resp.comp_mask |=BNXT_RE_SRQ_TOGGLE_PAGE_SUPPORT ;
@@ -2312,6 +2314,19 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,return 0 ; fail: +if (rdev->chip_ctx->modes.toggle_bits &BNXT_QPLIB_SRQ_TOGGLE_BIT && srq->uctx) { +mutex_lock (&rdev->srq_hash_lock); +hash_del (&srq->hash_entry); +mutex_unlock (&rdev->srq_hash_lock); +/* Drop the creator's reference and wait for any concurrent +* bnxt_re_search_for_srq() caller to release the pointer +* before the RDMA core frees the object. +*/ +kref_put (&srq->srq_ref, bnxt_re_srq_release); +wait_for_completion (&srq->srq_destroy_comp); +if (srq->uctx_srq_page) +free_page ((unsigned long )srq->uctx_srq_page); + }ib_umem_release (srq->umem); exit:return rc;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 13/15 RDMA/bnxt_re: Fix the cleanup upon error during CQ create
In reply to Selvin XavierFix the failure path of CQ create. Destroy the CQ from HW and delete from the hashlist if the page allocation fails. Also, add an explicit check for NULL before calling free_page.
--- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/infiniband/hw/bnxt_re/ib_verbs.c +16 -3
@@ -3615,14 +3615,27 @@ int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *att resp.phase = cq->qplib_cq.period; rc =ib_respond_udata (udata, resp);if (rc) - goto free_mem; + goto free_page;return 0 ; -free_mem: -free_page ((unsigned long )cq->uctx_cq_page); +free_page: +if (cq->uctx_cq_page) +free_page ((unsigned long )cq->uctx_cq_page); + destroy_cq:bnxt_qplib_destroy_cq (&rdev->qplib_res, &cq->qplib_cq); +if (cctx->modes.toggle_bits &BNXT_QPLIB_CQ_TOGGLE_BIT ) { +mutex_lock (&rdev->cq_hash_lock); +hash_del (&cq->hash_entry); +mutex_unlock (&rdev->cq_hash_lock); +/* Drop the creator's reference and wait for any concurrent +* bnxt_re_search_for_cq() caller to release the pointer +* before the RDMA core frees the object. +*/ +kref_put (&cq->cq_ref, bnxt_re_cq_release); +wait_for_completion (&cq->cq_destroy_comp); + } free_umem:ib_umem_release (cq->umem);return rc;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 14/15 RDMA/bnxt_re: Fail DBR related page allocation UAPIs if the feature is disabled
In reply to Selvin XavierNo need to support the DBR related page allocations if the pacing feature is disabled. Fail the request if pacing is disabled.
--- drivers/infiniband/hw/bnxt_re/uapi.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/infiniband/hw/bnxt_re/uapi.c +4 -0
@@ -127,12 +127,16 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *break ;case BNXT_RE_ALLOC_DBR_BAR_PAGE : +if (!rdev->pacing.dbr_pacing) +return -EOPNOTSUPP ; length =PAGE_SIZE ; addr = (u64 )rdev->pacing.dbr_bar_addr; mmap_flag =BNXT_RE_MMAP_DBR_BAR ;break ;case BNXT_RE_ALLOC_DBR_PAGE : +if (!rdev->pacing.dbr_pacing) +return -EOPNOTSUPP ; length =PAGE_SIZE ; addr = (u64 )rdev->pacing.dbr_page; mmap_flag =BNXT_RE_MMAP_DBR_PAGE ;
Signature · 1 line
2.39.3
Selvin Xavier
maintainerPATCH v2 15/15 RDMA/bnxt_re: Reject GET_TOGGLE_MEM when toggle page was not allocated
In reply to Selvin XavierIf a user calls BNXT_RE_METHOD_GET_TOGGLE_MEM on a device that does not support the CQ/SRQ toggle feature, uctx_cq_page or uctx_srq_page will be NULL.
Add an explicit -EOPNOTSUPP return after capturing the address from uctx_cq_page / uctx_srq_page if the address is zero.
--- drivers/infiniband/hw/bnxt_re/uapi.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/infiniband/hw/bnxt_re/uapi.c +4 -0
@@ -289,6 +289,8 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund addr = (u64 )cq->uctx_cq_page;bnxt_re_put_cq (cq); +if (!addr) +return -EOPNOTSUPP ;break ;case BNXT_RE_SRQ_TOGGLE_MEM : srq =bnxt_re_search_for_srq (rdev, res_id);
@@ -302,6 +304,8 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund addr = (u64 )srq->uctx_srq_page;bnxt_re_put_srq (srq); +if (!addr) +return -EOPNOTSUPP ;break ;default :
Signature · 1 line
2.39.3
Jason Gunthorpe
maintainerQuoted 11 lines · Selvin Xavier
Selvin Xavier (15):
RDMA/bnxt_re: Initialize dpi variable to zero RDMA/bnxt_re: Free SRQ toggle page after firmware teardown RDMA/bnxt_re: Free CQ toggle page after firmware teardown RDMA/bnxt_re: Avoid displaying the kernel pointer RDMA/bnxt_re: Add a max slot check for SQ
RDMA/bnxt_re: Proper rollback if the ioremap fails RDMA/bnxt_re: Avoid repeated requests to allocate WC pages RDMA/bnxt_re: Fail DBR related page allocation UAPIs if the feature is
disabled
RDMA/bnxt_re: RejectGET_TOGGLE_MEMwhen toggle page was not allocated
I picked up these ones, please redo the uobj related ones
Thanks,
Jason
Selvin Xavier
maintainerQuoted 14 lines · Jason Gunthorpe
Quoted 11 lines · Selvin Xavier
Selvin Xavier (15):
RDMA/bnxt_re: Initialize dpi variable to zero RDMA/bnxt_re: Free SRQ toggle page after firmware teardown RDMA/bnxt_re: Free CQ toggle page after firmware teardown RDMA/bnxt_re: Avoid displaying the kernel pointer RDMA/bnxt_re: Add a max slot check for SQ
RDMA/bnxt_re: Proper rollback if the ioremap fails RDMA/bnxt_re: Avoid repeated requests to allocate WC pages RDMA/bnxt_re: Fail DBR related page allocation UAPIs if the feature is
disabled
RDMA/bnxt_re: RejectGET_TOGGLE_MEMwhen toggle page was not allocated
Quoted 1 line
I picked up these ones, please redo the uobj related ones
Thanks Jason. Sure, I will rework the patches based on the comments.
Quoted 3 lines
Thanks,
Jason