]> git.baikalelectronics.ru Git - kernel.git/commitdiff
RDMA/bnxt_re: Prevent handling any completions after qp destroy
authorKashyap Desai <kashyap.desai@broadcom.com>
Fri, 14 Jul 2023 08:22:48 +0000 (01:22 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Aug 2023 08:24:04 +0000 (10:24 +0200)
[ Upstream commit b5bbc6551297447d3cca55cf907079e206e9cd82 ]

HW may generate completions that indicates QP is destroyed.
Driver should not be scheduling any more completion handlers
for this QP, after the QP is destroyed. Since CQs are active
during the QP destroy, driver may still schedule completion
handlers. This can cause a race where the destroy_cq and poll_cq
running simultaneously.

Snippet of kernel panic while doing bnxt_re driver load unload in loop.
This indicates a poll after the CQ is freed. 

[77786.481636] Call Trace:
[77786.481640]  <TASK>
[77786.481644]  bnxt_re_poll_cq+0x14a/0x620 [bnxt_re]
[77786.481658]  ? kvm_clock_read+0x14/0x30
[77786.481693]  __ib_process_cq+0x57/0x190 [ib_core]
[77786.481728]  ib_cq_poll_work+0x26/0x80 [ib_core]
[77786.481761]  process_one_work+0x1e5/0x3f0
[77786.481768]  worker_thread+0x50/0x3a0
[77786.481785]  ? __pfx_worker_thread+0x10/0x10
[77786.481790]  kthread+0xe2/0x110
[77786.481794]  ? __pfx_kthread+0x10/0x10
[77786.481797]  ret_from_fork+0x2c/0x50

To avoid this, complete all completion handlers before returning the
destroy QP. If free_cq is called soon after destroy_qp,  IB stack
will cancel the CQ work before invoking the destroy_cq verb and
this will prevent any race mentioned.

Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver")
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Link: https://lore.kernel.org/r/1689322969-25402-2-git-send-email-selvin.xavier@broadcom.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_fp.h

index 94222de1d371922f4a1e9025fd6f9d474b168118..4ed8814efde6fbac18e4b5aec2dc5840051c752b 100644 (file)
@@ -796,7 +796,10 @@ fail:
 int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
 {
        struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
+       struct bnxt_qplib_qp *qplib_qp = &qp->qplib_qp;
        struct bnxt_re_dev *rdev = qp->rdev;
+       struct bnxt_qplib_nq *scq_nq = NULL;
+       struct bnxt_qplib_nq *rcq_nq = NULL;
        unsigned int flags;
        int rc;
 
@@ -830,6 +833,15 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
        ib_umem_release(qp->rumem);
        ib_umem_release(qp->sumem);
 
+       /* Flush all the entries of notification queue associated with
+        * given qp.
+        */
+       scq_nq = qplib_qp->scq->nq;
+       rcq_nq = qplib_qp->rcq->nq;
+       bnxt_re_synchronize_nq(scq_nq);
+       if (scq_nq != rcq_nq)
+               bnxt_re_synchronize_nq(rcq_nq);
+
        return 0;
 }
 
index 74d56900387a17805d8d0f5178a46caa41720452..1011293547ef76fcb2f3930062fd5e412baaac68 100644 (file)
@@ -387,6 +387,24 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t)
        spin_unlock_bh(&hwq->lock);
 }
 
+/* bnxt_re_synchronize_nq - self polling notification queue.
+ * @nq      -     notification queue pointer
+ *
+ * This function will start polling entries of a given notification queue
+ * for all pending  entries.
+ * This function is useful to synchronize notification entries while resources
+ * are going away.
+ */
+
+void bnxt_re_synchronize_nq(struct bnxt_qplib_nq *nq)
+{
+       int budget = nq->budget;
+
+       nq->budget = nq->hwq.max_elements;
+       bnxt_qplib_service_nq(&nq->nq_tasklet);
+       nq->budget = budget;
+}
+
 static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance)
 {
        struct bnxt_qplib_nq *nq = dev_instance;
index f859710f9a7f4a5a7b147989d606a5c31b268cea..49d89c080827548db29d999743c904dc780acd0c 100644 (file)
@@ -548,6 +548,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
                                  struct bnxt_qplib_cqe *cqe,
                                  int num_cqes);
 void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp);
+void bnxt_re_synchronize_nq(struct bnxt_qplib_nq *nq);
 
 static inline void *bnxt_qplib_get_swqe(struct bnxt_qplib_q *que, u32 *swq_idx)
 {