diff mbox

[for-rc,v2] RDMA/bnxt_re: Fix broken RoCE driver due to recent L2 driver changes

Message ID 1527229327-31397-2-git-send-email-devesh.sharma@broadcom.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Devesh Sharma May 25, 2018, 6:22 a.m. UTC
The recent changes in Broadcom's ethernet driver(L2 driver) broke
RoCE functionality in terms of MSIx vector allocation and
de-allocation.

There is a possibility that L2 driver would initiate MSIx vector
reallocation depending upon the requests coming from administrator.
In such cases L2 driver needs to free up all the MSIx vectors
allocated previously and reallocate/initialize those.

If RoCE driver is loaded and reshuffling is attempted, there will be
kernel crashes because RoCE driver would still be holding the MSIx
vectors but L2 driver would attempt to free in-use vectors. Thus
leading to a kernel crash.

Making changes in roce driver to fix crashes described above.
As part of solution L2 driver tells RoCE driver to release
the MSIx vector whenever there is a need. When RoCE driver
get message it sync up with all the running tasklets and IRQ
handlers and releases the vectors. L2 driver send one more
message to RoCE driver to resume the MSIx vectors. L2 driver
guarantees that RoCE vector do not change during reshuffling.

Fixes: 76dda4cba264 ("Add ULP calls to stop and restart IRQs")
Fixes: 9f066b40c80f ("Change IRQ assignment for RDMA driver")
Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
---
 drivers/infiniband/hw/bnxt_re/main.c       | 55 ++++++++++++++++-
 drivers/infiniband/hw/bnxt_re/qplib_fp.c   | 95 +++++++++++++++++++-----------
 drivers/infiniband/hw/bnxt_re/qplib_fp.h   |  3 +
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 61 +++++++++++++------
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.h |  3 +
 5 files changed, 164 insertions(+), 53 deletions(-)

Comments

Jason Gunthorpe May 25, 2018, 2:43 p.m. UTC | #1
On Fri, May 25, 2018 at 02:22:07AM -0400, Devesh Sharma wrote:
> The recent changes in Broadcom's ethernet driver(L2 driver) broke
> RoCE functionality in terms of MSIx vector allocation and
> de-allocation.
> 
> There is a possibility that L2 driver would initiate MSIx vector
> reallocation depending upon the requests coming from administrator.
> In such cases L2 driver needs to free up all the MSIx vectors
> allocated previously and reallocate/initialize those.
> 
> If RoCE driver is loaded and reshuffling is attempted, there will be
> kernel crashes because RoCE driver would still be holding the MSIx
> vectors but L2 driver would attempt to free in-use vectors. Thus
> leading to a kernel crash.
> 
> Making changes in roce driver to fix crashes described above.
> As part of solution L2 driver tells RoCE driver to release
> the MSIx vector whenever there is a need. When RoCE driver
> get message it sync up with all the running tasklets and IRQ
> handlers and releases the vectors. L2 driver send one more
> message to RoCE driver to resume the MSIx vectors. L2 driver
> guarantees that RoCE vector do not change during reshuffling.
> 
> Fixes: 76dda4cba264 ("Add ULP calls to stop and restart IRQs")
> Fixes: 9f066b40c80f ("Change IRQ assignment for RDMA driver")
> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>

Come on guys..

mlx{jgg}~/oss/k.o#git describe --contains 9f066b40c80f
Could not get sha1 for 9f066b40c80f. Skipping.
mlx{jgg}~/oss/k.o#git describe  --contains 76dda4cba264
Could not get sha1 for 76dda4cba264. Skipping.

Should be

Fixes: ec86f14ea506 ("bnxt_en: Add ULP calls to stop and restart IRQs.")
Fixes: 08654eb213a8 ("bnxt_en: Change IRQ assignment for RDMA driver.")

> +	memset(nq->name, 0, 32);

Open coded size? Nope

> +	sprintf(nq->name, "bnxt_qplib_nq-%d", nq_indx);

Why the memset? Why not a snprintf? Should be

snprintf(nq->name, sizeof(nq->name), "bnxt_qplib_nq-%d", nq_indx);


> -	nq->requested = false;
> -	memset(nq->name, 0, 32);
> -	sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx);

Ditto

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Devesh Sharma May 25, 2018, 3:39 p.m. UTC | #2
Sorry, Jason I got wrong info from my team, will correct it and repost.

-Regards
Devesh

On Fri, May 25, 2018 at 8:13 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
> On Fri, May 25, 2018 at 02:22:07AM -0400, Devesh Sharma wrote:
>> The recent changes in Broadcom's ethernet driver(L2 driver) broke
>> RoCE functionality in terms of MSIx vector allocation and
>> de-allocation.
>>
>> There is a possibility that L2 driver would initiate MSIx vector
>> reallocation depending upon the requests coming from administrator.
>> In such cases L2 driver needs to free up all the MSIx vectors
>> allocated previously and reallocate/initialize those.
>>
>> If RoCE driver is loaded and reshuffling is attempted, there will be
>> kernel crashes because RoCE driver would still be holding the MSIx
>> vectors but L2 driver would attempt to free in-use vectors. Thus
>> leading to a kernel crash.
>>
>> Making changes in roce driver to fix crashes described above.
>> As part of solution L2 driver tells RoCE driver to release
>> the MSIx vector whenever there is a need. When RoCE driver
>> get message it sync up with all the running tasklets and IRQ
>> handlers and releases the vectors. L2 driver send one more
>> message to RoCE driver to resume the MSIx vectors. L2 driver
>> guarantees that RoCE vector do not change during reshuffling.
>>
>> Fixes: 76dda4cba264 ("Add ULP calls to stop and restart IRQs")
>> Fixes: 9f066b40c80f ("Change IRQ assignment for RDMA driver")
>> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
>
> Come on guys..
>
> mlx{jgg}~/oss/k.o#git describe --contains 9f066b40c80f
> Could not get sha1 for 9f066b40c80f. Skipping.
> mlx{jgg}~/oss/k.o#git describe  --contains 76dda4cba264
> Could not get sha1 for 76dda4cba264. Skipping.
>
> Should be
>
> Fixes: ec86f14ea506 ("bnxt_en: Add ULP calls to stop and restart IRQs.")
> Fixes: 08654eb213a8 ("bnxt_en: Change IRQ assignment for RDMA driver.")
>
>> +     memset(nq->name, 0, 32);
>
> Open coded size? Nope
>
>> +     sprintf(nq->name, "bnxt_qplib_nq-%d", nq_indx);
>
> Why the memset? Why not a snprintf? Should be
>
> snprintf(nq->name, sizeof(nq->name), "bnxt_qplib_nq-%d", nq_indx);
>
>
>> -     nq->requested = false;
>> -     memset(nq->name, 0, 32);
>> -     sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx);
>
> Ditto
>
> Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Leon Romanovsky May 25, 2018, 9:45 p.m. UTC | #3
On Fri, May 25, 2018 at 09:09:05PM +0530, Devesh Sharma wrote:
> Sorry, Jason I got wrong info from my team, will correct it and repost.

Can you please stop TOP POSTING in linux kernel mailing lists?

It is my fist time in all my career that I see so many attempts
from one person to do not respect community while working with
the community and expecting something more than ignorance.

Thanks

>
> -Regards
> Devesh
>
> On Fri, May 25, 2018 at 8:13 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
> > On Fri, May 25, 2018 at 02:22:07AM -0400, Devesh Sharma wrote:
> >> The recent changes in Broadcom's ethernet driver(L2 driver) broke
> >> RoCE functionality in terms of MSIx vector allocation and
> >> de-allocation.
> >>
> >> There is a possibility that L2 driver would initiate MSIx vector
> >> reallocation depending upon the requests coming from administrator.
> >> In such cases L2 driver needs to free up all the MSIx vectors
> >> allocated previously and reallocate/initialize those.
> >>
> >> If RoCE driver is loaded and reshuffling is attempted, there will be
> >> kernel crashes because RoCE driver would still be holding the MSIx
> >> vectors but L2 driver would attempt to free in-use vectors. Thus
> >> leading to a kernel crash.
> >>
> >> Making changes in roce driver to fix crashes described above.
> >> As part of solution L2 driver tells RoCE driver to release
> >> the MSIx vector whenever there is a need. When RoCE driver
> >> get message it sync up with all the running tasklets and IRQ
> >> handlers and releases the vectors. L2 driver send one more
> >> message to RoCE driver to resume the MSIx vectors. L2 driver
> >> guarantees that RoCE vector do not change during reshuffling.
> >>
> >> Fixes: 76dda4cba264 ("Add ULP calls to stop and restart IRQs")
> >> Fixes: 9f066b40c80f ("Change IRQ assignment for RDMA driver")
> >> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com>
> >
> > Come on guys..
> >
> > mlx{jgg}~/oss/k.o#git describe --contains 9f066b40c80f
> > Could not get sha1 for 9f066b40c80f. Skipping.
> > mlx{jgg}~/oss/k.o#git describe  --contains 76dda4cba264
> > Could not get sha1 for 76dda4cba264. Skipping.
> >
> > Should be
> >
> > Fixes: ec86f14ea506 ("bnxt_en: Add ULP calls to stop and restart IRQs.")
> > Fixes: 08654eb213a8 ("bnxt_en: Change IRQ assignment for RDMA driver.")
> >
> >> +     memset(nq->name, 0, 32);
> >
> > Open coded size? Nope
> >
> >> +     sprintf(nq->name, "bnxt_qplib_nq-%d", nq_indx);
> >
> > Why the memset? Why not a snprintf? Should be
> >
> > snprintf(nq->name, sizeof(nq->name), "bnxt_qplib_nq-%d", nq_indx);
> >
> >
> >> -     nq->requested = false;
> >> -     memset(nq->name, 0, 32);
> >> -     sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx);
> >
> > Ditto
> >
> > Jason
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index f6c739e..20b9f31 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -185,12 +185,65 @@  static void bnxt_re_shutdown(void *p)
 	bnxt_re_ib_unreg(rdev, false);
 }
 
+static void bnxt_re_stop_irq(void *handle)
+{
+	struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle;
+	struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw;
+	struct bnxt_qplib_nq *nq;
+	int indx;
+
+	for (indx = BNXT_RE_NQ_IDX; indx < rdev->num_msix; indx++) {
+		nq = &rdev->nq[indx - 1];
+		bnxt_qplib_nq_stop_irq(nq, false);
+	}
+
+	bnxt_qplib_rcfw_stop_irq(rcfw, false);
+}
+
+static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent)
+{
+	struct bnxt_re_dev *rdev = (struct bnxt_re_dev *)handle;
+	struct bnxt_msix_entry *msix_ent = rdev->msix_entries;
+	struct bnxt_qplib_rcfw *rcfw = &rdev->rcfw;
+	struct bnxt_qplib_nq *nq;
+	int indx, rc;
+
+	if (!ent) {
+		/* Not setting the f/w timeout bit in rcfw.
+		 * During the driver unload the first command
+		 * to f/w will timeout and that will set the
+		 * timeout bit.
+		 */
+		dev_err(rdev_to_dev(rdev), "Failed to re-start IRQs\n");
+		return;
+	}
+
+	/* Vectors may change after restart, so update with new vectors
+	 * in device sctructure.
+	 */
+	for (indx = 0; indx < rdev->num_msix; indx++)
+		rdev->msix_entries[indx].vector = ent[indx].vector;
+
+	bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector,
+				  false);
+	for (indx = BNXT_RE_NQ_IDX ; indx < rdev->num_msix; indx++) {
+		nq = &rdev->nq[indx - 1];
+		rc = bnxt_qplib_nq_start_irq(nq, indx - 1,
+					     msix_ent[indx].vector, false);
+		if (rc)
+			dev_warn(rdev_to_dev(rdev),
+				 "Failed to reinit NQ index %d\n", indx - 1);
+	}
+}
+
 static struct bnxt_ulp_ops bnxt_re_ulp_ops = {
 	.ulp_async_notifier = NULL,
 	.ulp_stop = bnxt_re_stop,
 	.ulp_start = bnxt_re_start,
 	.ulp_sriov_config = bnxt_re_sriov_config,
-	.ulp_shutdown = bnxt_re_shutdown
+	.ulp_shutdown = bnxt_re_shutdown,
+	.ulp_irq_stop = bnxt_re_stop_irq,
+	.ulp_irq_restart = bnxt_re_start_irq
 };
 
 /* RoCE -> Net driver */
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 3a78fab..b0d343d 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -336,22 +336,32 @@  static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance)
 	return IRQ_HANDLED;
 }
 
+void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill)
+{
+	tasklet_disable(&nq->worker);
+	/* Mask h/w interrupt */
+	NQ_DB(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements);
+	/* Sync with last running IRQ handler */
+	synchronize_irq(nq->vector);
+	if (kill)
+		tasklet_kill(&nq->worker);
+	if (nq->requested) {
+		irq_set_affinity_hint(nq->vector, NULL);
+		free_irq(nq->vector, nq);
+		nq->requested = false;
+	}
+}
+
 void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
 {
 	if (nq->cqn_wq) {
 		destroy_workqueue(nq->cqn_wq);
 		nq->cqn_wq = NULL;
 	}
+
 	/* Make sure the HW is stopped! */
-	synchronize_irq(nq->vector);
-	tasklet_disable(&nq->worker);
-	tasklet_kill(&nq->worker);
+	bnxt_qplib_nq_stop_irq(nq, true);
 
-	if (nq->requested) {
-		irq_set_affinity_hint(nq->vector, NULL);
-		free_irq(nq->vector, nq);
-		nq->requested = false;
-	}
 	if (nq->bar_reg_iomem)
 		iounmap(nq->bar_reg_iomem);
 	nq->bar_reg_iomem = NULL;
@@ -361,6 +371,41 @@  void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
 	nq->vector = 0;
 }
 
+int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx,
+			    int msix_vector, bool need_init)
+{
+	int rc;
+
+	if (nq->requested)
+		return -EFAULT;
+
+	nq->vector = msix_vector;
+	if (need_init)
+		tasklet_init(&nq->worker, bnxt_qplib_service_nq,
+			     (unsigned long)nq);
+	else
+		tasklet_enable(&nq->worker);
+
+	memset(nq->name, 0, 32);
+	sprintf(nq->name, "bnxt_qplib_nq-%d", nq_indx);
+	rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, nq->name, nq);
+	if (rc)
+		return rc;
+
+	cpumask_clear(&nq->mask);
+	cpumask_set_cpu(nq_indx, &nq->mask);
+	rc = irq_set_affinity_hint(nq->vector, &nq->mask);
+	if (rc) {
+		dev_warn(&nq->pdev->dev,
+			 "QPLIB: set affinity failed; vector: %d nq_idx: %d\n",
+			 nq->vector, nq_indx);
+	}
+	nq->requested = true;
+	NQ_DB_REARM(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements);
+
+	return rc;
+}
+
 int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 			 int nq_idx, int msix_vector, int bar_reg_offset,
 			 int (*cqn_handler)(struct bnxt_qplib_nq *nq,
@@ -372,41 +417,17 @@  int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 	resource_size_t nq_base;
 	int rc = -1;
 
-	nq->pdev = pdev;
-	nq->vector = msix_vector;
 	if (cqn_handler)
 		nq->cqn_handler = cqn_handler;
 
 	if (srqn_handler)
 		nq->srqn_handler = srqn_handler;
 
-	tasklet_init(&nq->worker, bnxt_qplib_service_nq, (unsigned long)nq);
-
 	/* Have a task to schedule CQ notifiers in post send case */
 	nq->cqn_wq  = create_singlethread_workqueue("bnxt_qplib_nq");
 	if (!nq->cqn_wq)
-		goto fail;
-
-	nq->requested = false;
-	memset(nq->name, 0, 32);
-	sprintf(nq->name, "bnxt_qplib_nq-%d", nq_idx);
-	rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, nq->name, nq);
-	if (rc) {
-		dev_err(&nq->pdev->dev,
-			"Failed to request IRQ for NQ: %#x", rc);
-		goto fail;
-	}
-
-	cpumask_clear(&nq->mask);
-	cpumask_set_cpu(nq_idx, &nq->mask);
-	rc = irq_set_affinity_hint(nq->vector, &nq->mask);
-	if (rc) {
-		dev_warn(&nq->pdev->dev,
-			 "QPLIB: set affinity failed; vector: %d nq_idx: %d\n",
-			 nq->vector, nq_idx);
-	}
+		return -ENOMEM;
 
-	nq->requested = true;
 	nq->bar_reg = NQ_CONS_PCI_BAR_REGION;
 	nq->bar_reg_off = bar_reg_offset;
 	nq_base = pci_resource_start(pdev, nq->bar_reg);
@@ -419,7 +440,13 @@  int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 		rc = -ENOMEM;
 		goto fail;
 	}
-	NQ_DB_REARM(nq->bar_reg_iomem, nq->hwq.cons, nq->hwq.max_elements);
+
+	rc = bnxt_qplib_nq_start_irq(nq, nq_idx, msix_vector, true);
+	if (rc) {
+		dev_err(&nq->pdev->dev,
+			"QPLIB: Failed to request irq for nq-idx %d", nq_idx);
+		goto fail;
+	}
 
 	return 0;
 fail:
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
index ade9f13..72352ca 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
@@ -467,7 +467,10 @@  struct bnxt_qplib_nq_work {
 	struct bnxt_qplib_cq    *cq;
 };
 
+void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill);
 void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
+int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx,
+			    int msix_vector, bool need_init);
 int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 			 int nq_idx, int msix_vector, int bar_reg_offset,
 			 int (*cqn_handler)(struct bnxt_qplib_nq *nq,
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
index 80027a4..2852d35 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -582,19 +582,29 @@  int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
 	return -ENOMEM;
 }
 
-void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
+void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill)
 {
-	unsigned long indx;
-
-	/* Make sure the HW channel is stopped! */
-	synchronize_irq(rcfw->vector);
 	tasklet_disable(&rcfw->worker);
-	tasklet_kill(&rcfw->worker);
+	/* Mask h/w interrupts */
+	CREQ_DB(rcfw->creq_bar_reg_iomem, rcfw->creq.cons,
+		rcfw->creq.max_elements);
+	/* Sync with last running IRQ-handler */
+	synchronize_irq(rcfw->vector);
+	if (kill)
+		tasklet_kill(&rcfw->worker);
 
 	if (rcfw->requested) {
 		free_irq(rcfw->vector, rcfw);
 		rcfw->requested = false;
 	}
+}
+
+void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
+{
+	unsigned long indx;
+
+	bnxt_qplib_rcfw_stop_irq(rcfw, true);
+
 	if (rcfw->cmdq_bar_reg_iomem)
 		iounmap(rcfw->cmdq_bar_reg_iomem);
 	rcfw->cmdq_bar_reg_iomem = NULL;
@@ -614,6 +624,31 @@  void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
 	rcfw->vector = 0;
 }
 
+int bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector,
+			      bool need_init)
+{
+	int rc;
+
+	if (rcfw->requested)
+		return -EFAULT;
+
+	rcfw->vector = msix_vector;
+	if (need_init)
+		tasklet_init(&rcfw->worker,
+			     bnxt_qplib_service_creq, (unsigned long)rcfw);
+	else
+		tasklet_enable(&rcfw->worker);
+	rc = request_irq(rcfw->vector, bnxt_qplib_creq_irq, 0,
+			 "bnxt_qplib_creq", rcfw);
+	if (rc)
+		return rc;
+	rcfw->requested = true;
+	CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, rcfw->creq.cons,
+		      rcfw->creq.max_elements);
+
+	return 0;
+}
+
 int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
 				   struct bnxt_qplib_rcfw *rcfw,
 				   int msix_vector,
@@ -675,27 +710,17 @@  int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
 	rcfw->creq_qp_event_processed = 0;
 	rcfw->creq_func_event_processed = 0;
 
-	rcfw->vector = msix_vector;
 	if (aeq_handler)
 		rcfw->aeq_handler = aeq_handler;
+	init_waitqueue_head(&rcfw->waitq);
 
-	tasklet_init(&rcfw->worker, bnxt_qplib_service_creq,
-		     (unsigned long)rcfw);
-
-	rcfw->requested = false;
-	rc = request_irq(rcfw->vector, bnxt_qplib_creq_irq, 0,
-			 "bnxt_qplib_creq", rcfw);
+	rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true);
 	if (rc) {
 		dev_err(&rcfw->pdev->dev,
 			"QPLIB: Failed to request IRQ for CREQ rc = 0x%x", rc);
 		bnxt_qplib_disable_rcfw_channel(rcfw);
 		return rc;
 	}
-	rcfw->requested = true;
-
-	init_waitqueue_head(&rcfw->waitq);
-
-	CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, 0, rcfw->creq.max_elements);
 
 	init.cmdq_pbl = cpu_to_le64(rcfw->cmdq.pbl[PBL_LVL_0].pg_map_arr[0]);
 	init.cmdq_size_cmdq_lvl = cpu_to_le16(
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
index c7cce2e..46416df 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
@@ -195,7 +195,10 @@  struct bnxt_qplib_rcfw {
 void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
 int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
 				  struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz);
+void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill);
 void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
+int bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector,
+			      bool need_init);
 int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
 				   struct bnxt_qplib_rcfw *rcfw,
 				   int msix_vector,