]> git.openfabrics.org - ~aditr/compat-rdma.git/commitdiff
bnxt_re: BZ 2655 Fix nfs client hang with a call trace on stress traffic
authorSelvin Xavier <selvin.xavier@broadcom.com>
Mon, 6 Nov 2017 16:18:13 +0000 (08:18 -0800)
committerSelvin Xavier <selvin.xavier@broadcom.com>
Mon, 6 Nov 2017 16:18:13 +0000 (08:18 -0800)
Adding memory barriers before processing a completion. Also, fixes some
race condition in moving the QP to error state during an Rx CQE error and
synchronize poll_cq and req_notify_cq.

Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
linux-next-pending/0015-RDMA-bnxt_re-Add-memory-barriers-when-processing-CQ-.patch [new file with mode: 0644]
linux-next-pending/0016-RDMA-bnxt_re-Set-QP-state-in-case-of-response-comple.patch [new file with mode: 0644]
linux-next-pending/0017-RDMA-bnxt_re-Flush-CQ-notification-Work-Queue-before.patch [new file with mode: 0644]
linux-next-pending/0018-RDMA-bnxt_re-synchronize-poll_cq-and-req_notify_cq-v.patch [new file with mode: 0644]

diff --git a/linux-next-pending/0015-RDMA-bnxt_re-Add-memory-barriers-when-processing-CQ-.patch b/linux-next-pending/0015-RDMA-bnxt_re-Add-memory-barriers-when-processing-CQ-.patch
new file mode 100644 (file)
index 0000000..ab49143
--- /dev/null
@@ -0,0 +1,89 @@
+From 164b323b3bb95757b65087555a33f29c3a792fdc Mon Sep 17 00:00:00 2001
+From: Somnath Kotur <somnath.kotur@broadcom.com>
+Date: Fri, 3 Nov 2017 19:19:01 -0700
+Subject: [PATCH 1/4] RDMA/bnxt_re: Add memory barriers when processing CQ/EQ
+ entries
+
+The code determines if the next ring entry is valid before proceeding
+further to read the rest of the entry. The CPU can re-order and read
+the rest of the entry first, possibly reading a stale entry, if DMA
+of a new entry happens right after reading it.
+
+Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com>
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+---
+ drivers/infiniband/hw/bnxt_re/qplib_fp.c   | 21 +++++++++++++++++++++
+ drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |  4 ++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+index a82044d..31ea9f4 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+@@ -292,6 +292,12 @@ static void bnxt_qplib_service_nq(unsigned long data)
+               if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements))
+                       break;
++              /*
++               * The valid test of the entry must be done first before
++               * reading any further.
++               */
++              dma_rmb();
++
+               type = le16_to_cpu(nqe->info10_type) & NQ_BASE_TYPE_MASK;
+               switch (type) {
+               case NQ_BASE_TYPE_CQ_NOTIFICATION:
+@@ -1113,6 +1119,11 @@ static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp)
+               hw_cqe = &hw_cqe_ptr[CQE_PG(i)][CQE_IDX(i)];
+               if (!CQE_CMP_VALID(hw_cqe, i, cq_hwq->max_elements))
+                       continue;
++              /*
++               * The valid test of the entry must be done first before
++               * reading any further.
++               */
++              dma_rmb();
+               switch (hw_cqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK) {
+               case CQ_BASE_CQE_TYPE_REQ:
+               case CQ_BASE_CQE_TYPE_TERMINAL:
+@@ -1896,6 +1907,11 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
+                       /* If the next hwcqe is VALID */
+                       if (CQE_CMP_VALID(peek_hwcqe, peek_raw_cq_cons,
+                                         cq->hwq.max_elements)) {
++                      /*
++                       * The valid test of the entry must be done first before
++                       * reading any further.
++                       */
++                              dma_rmb();
+                               /* If the next hwcqe is a REQ */
+                               if ((peek_hwcqe->cqe_type_toggle &
+                                   CQ_BASE_CQE_TYPE_MASK) ==
+@@ -2440,6 +2456,11 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
+               if (!CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements))
+                       break;
++              /*
++               * The valid test of the entry must be done first before
++               * reading any further.
++               */
++              dma_rmb();
+               /* From the device's respective CQE format to qplib_wc*/
+               switch (hw_cqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK) {
+               case CQ_BASE_CQE_TYPE_REQ:
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+index 6d11614..751170a 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+@@ -357,6 +357,10 @@ static void bnxt_qplib_service_creq(unsigned long data)
+               creqe = &creq_ptr[get_creq_pg(sw_cons)][get_creq_idx(sw_cons)];
+               if (!CREQ_CMP_VALID(creqe, raw_cons, creq->max_elements))
+                       break;
++              /* The valid test of the entry must be done first before
++               * reading any further.
++               */
++              dma_rmb();
+               type = creqe->type & CREQ_BASE_TYPE_MASK;
+               switch (type) {
+-- 
+2.5.5
+
diff --git a/linux-next-pending/0016-RDMA-bnxt_re-Set-QP-state-in-case-of-response-comple.patch b/linux-next-pending/0016-RDMA-bnxt_re-Set-QP-state-in-case-of-response-comple.patch
new file mode 100644 (file)
index 0000000..4421f85
--- /dev/null
@@ -0,0 +1,45 @@
+From 1faffd689e54c314a6b5d5bbe06804c6bf357fc0 Mon Sep 17 00:00:00 2001
+From: Selvin Xavier <selvin.xavier@broadcom.com>
+Date: Fri, 3 Nov 2017 19:28:19 -0700
+Subject: [PATCH 2/4] RDMA/bnxt_re: Set QP state in case of response completion
+ errors
+
+Moves the driver QP state to error in case of response completion
+errors. Handles the scenarios which doesn't generate a terminal CQE.
+
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+---
+ drivers/infiniband/hw/bnxt_re/qplib_fp.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+index 31ea9f4..805a612 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+@@ -2118,6 +2118,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
+       *pcqe = cqe;
+       if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
++              qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
+                /* Add qp to flush list of the CQ */
+               bnxt_qplib_lock_buddy_cq(qp, cq);
+               __bnxt_qplib_add_flush_qp(qp);
+@@ -2181,6 +2182,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
+       *pcqe = cqe;
+       if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
++              qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
+               /* Add qp to flush list of the CQ */
+               bnxt_qplib_lock_buddy_cq(qp, cq);
+               __bnxt_qplib_add_flush_qp(qp);
+@@ -2268,6 +2270,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
+       *pcqe = cqe;
+       if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
++              qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
+               /* Add qp to flush list of the CQ */
+               bnxt_qplib_lock_buddy_cq(qp, cq);
+               __bnxt_qplib_add_flush_qp(qp);
+-- 
+2.5.5
+
diff --git a/linux-next-pending/0017-RDMA-bnxt_re-Flush-CQ-notification-Work-Queue-before.patch b/linux-next-pending/0017-RDMA-bnxt_re-Flush-CQ-notification-Work-Queue-before.patch
new file mode 100644 (file)
index 0000000..675d464
--- /dev/null
@@ -0,0 +1,57 @@
+From ddbb03a013b2ab9415456b4bd7b035f0d1d597d2 Mon Sep 17 00:00:00 2001
+From: Selvin Xavier <selvin.xavier@broadcom.com>
+Date: Fri, 3 Nov 2017 19:41:07 -0700
+Subject: [PATCH 3/4] RDMA/bnxt_re: Flush CQ notification Work Queue before
+ destroying QP
+
+Destroy_qp shall wait for any outstanding CQ notification to be
+flushed out before proceeding with QP destroy. Flushing the WQ
+before destroying the QP.
+
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+---
+ drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 +
+ drivers/infiniband/hw/bnxt_re/qplib_fp.c | 7 +++++++
+ drivers/infiniband/hw/bnxt_re/qplib_fp.h | 1 +
+ 3 files changed, 9 insertions(+)
+
+diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+index ebcdfb4..96ec797 100644
+--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+@@ -788,6 +788,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
+       struct bnxt_re_dev *rdev = qp->rdev;
+       int rc;
++      bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);
+       bnxt_qplib_del_flush_qp(&qp->qplib_qp);
+       rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
+       if (rc) {
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+index 805a612..c0f8133 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+@@ -2537,3 +2537,10 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type)
+       atomic_set(&cq->arm_state, 1);
+       spin_unlock_irqrestore(&cq->hwq.lock, flags);
+ }
++
++void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp)
++{
++      flush_workqueue(qp->scq->nq->cqn_wq);
++      if (qp->scq != qp->rcq)
++              flush_workqueue(qp->rcq->nq->cqn_wq);
++}
+diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+index 8ead70c..c582d4e 100644
+--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
++++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+@@ -478,4 +478,5 @@ void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp,
+ 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);
+ #endif /* __BNXT_QPLIB_FP_H__ */
+-- 
+2.5.5
+
diff --git a/linux-next-pending/0018-RDMA-bnxt_re-synchronize-poll_cq-and-req_notify_cq-v.patch b/linux-next-pending/0018-RDMA-bnxt_re-synchronize-poll_cq-and-req_notify_cq-v.patch
new file mode 100644 (file)
index 0000000..22c0815
--- /dev/null
@@ -0,0 +1,52 @@
+From b53367bb0452d8f92cdb7dadc6ba192cff035c4b Mon Sep 17 00:00:00 2001
+From: Selvin Xavier <selvin.xavier@broadcom.com>
+Date: Sat, 4 Nov 2017 01:27:30 -0700
+Subject: [PATCH 4/4] RDMA/bnxt_re: synchronize poll_cq and req_notify_cq verbs
+
+Synchronize poll_cq and req_notify_cq verbs using cq_lock,
+instead of the lower level qplib->hwq.lock.
+
+Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
+---
+ drivers/infiniband/hw/bnxt_re/ib_verbs.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+index 96ec797..d5770aa 100644
+--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
++++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+@@ -2999,8 +2999,10 @@ int bnxt_re_req_notify_cq(struct ib_cq *ib_cq,
+                         enum ib_cq_notify_flags ib_cqn_flags)
+ {
+       struct bnxt_re_cq *cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq);
+-      int type = 0;
++      int type = 0, rc = 0;
++      unsigned long flags;
++      spin_lock_irqsave(&cq->cq_lock, flags);
+       /* Trigger on the very next completion */
+       if (ib_cqn_flags & IB_CQ_NEXT_COMP)
+               type = DBR_DBR_TYPE_CQ_ARMALL;
+@@ -3010,12 +3012,15 @@ int bnxt_re_req_notify_cq(struct ib_cq *ib_cq,
+       /* Poll to see if there are missed events */
+       if ((ib_cqn_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+-          !(bnxt_qplib_is_cq_empty(&cq->qplib_cq)))
+-              return 1;
+-
++          !(bnxt_qplib_is_cq_empty(&cq->qplib_cq))) {
++              rc = 1;
++              goto exit;
++      }
+       bnxt_qplib_req_notify_cq(&cq->qplib_cq, type);
+-      return 0;
++exit:
++      spin_unlock_irqrestore(&cq->cq_lock, flags);
++      return rc;
+ }
+ /* Memory Regions */
+-- 
+2.5.5
+