]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
RDMA/bnxt_re: Disable/kill tasklet only if it is enabled
authorSelvin Xavier <selvin.xavier@broadcom.com>
Fri, 19 May 2023 06:48:11 +0000 (23:48 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Jul 2023 17:39:35 +0000 (19:39 +0200)
[ Upstream commit ab112ee7899d6171da5acd77a7ed7ae103f488de ]

When the ulp hook to start the IRQ fails because the rings are not
available, tasklets are not enabled. In this case when the driver is
unloaded, driver calls CREQ tasklet_kill. This causes an indefinite hang
as the tasklet is not enabled.

Driver shouldn't call tasklet_kill if it is not enabled. So using the
creq->requested and nq->requested flags to identify if both tasklets/irqs
are registered. Checking this flag while scheduling the tasklet from
ISR. Also, added a cleanup for disabling tasklet, in case request_irq
fails during start_irq.

Check for return value for bnxt_qplib_rcfw_start_irq and in case the
bnxt_qplib_rcfw_start_irq fails, return bnxt_re_start_irq without
attempting to start NQ IRQs.

Fixes: 1ac5a4047975 ("RDMA/bnxt_re: Add bnxt_re RoCE driver")
Link: https://lore.kernel.org/r/1684478897-12247-2-git-send-email-selvin.xavier@broadcom.com
Signed-off-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c

index 85e36c9f8e79747e962c186fd3e6246c60dfa788..a9cc65614a9eed4c2157c1d84e8cc7ff25bee348 100644 (file)
@@ -283,15 +283,21 @@ static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent)
        for (indx = 0; indx < rdev->num_msix; indx++)
                rdev->en_dev->msix_entries[indx].vector = ent[indx].vector;
 
-       bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector,
-                                 false);
+       rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector,
+                                      false);
+       if (rc) {
+               ibdev_warn(&rdev->ibdev, "Failed to reinit CREQ\n");
+               return;
+       }
        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)
+               if (rc) {
                        ibdev_warn(&rdev->ibdev, "Failed to reinit NQ index %d\n",
                                   indx - 1);
+                       return;
+               }
        }
 }
 
index ab2cc1c67f70b42adc3f8683047c318f291c3deb..a143bd3580a27ab8e863e6e91324415425e98e2f 100644 (file)
@@ -405,6 +405,9 @@ static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance)
 
 void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill)
 {
+       if (!nq->requested)
+               return;
+
        tasklet_disable(&nq->nq_tasklet);
        /* Mask h/w interrupt */
        bnxt_qplib_ring_nq_db(&nq->nq_db.dbinfo, nq->res->cctx, false);
@@ -412,11 +415,10 @@ void bnxt_qplib_nq_stop_irq(struct bnxt_qplib_nq *nq, bool kill)
        synchronize_irq(nq->msix_vec);
        if (kill)
                tasklet_kill(&nq->nq_tasklet);
-       if (nq->requested) {
-               irq_set_affinity_hint(nq->msix_vec, NULL);
-               free_irq(nq->msix_vec, nq);
-               nq->requested = false;
-       }
+
+       irq_set_affinity_hint(nq->msix_vec, NULL);
+       free_irq(nq->msix_vec, nq);
+       nq->requested = false;
 }
 
 void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
@@ -455,8 +457,10 @@ int bnxt_qplib_nq_start_irq(struct bnxt_qplib_nq *nq, int nq_indx,
 
        snprintf(nq->name, sizeof(nq->name), "bnxt_qplib_nq-%d", nq_indx);
        rc = request_irq(nq->msix_vec, bnxt_qplib_nq_irq, 0, nq->name, nq);
-       if (rc)
+       if (rc) {
+               tasklet_disable(&nq->nq_tasklet);
                return rc;
+       }
 
        cpumask_clear(&nq->mask);
        cpumask_set_cpu(nq_indx, &nq->mask);
index 061b2895dd9b575145244476ec084de08cce71ac..e28f0eb5b55d49be53a214f7d1ba1fbce9a7b625 100644 (file)
@@ -635,6 +635,10 @@ void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill)
        struct bnxt_qplib_creq_ctx *creq;
 
        creq = &rcfw->creq;
+
+       if (!creq->requested)
+               return;
+
        tasklet_disable(&creq->creq_tasklet);
        /* Mask h/w interrupts */
        bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, false);
@@ -643,10 +647,8 @@ void bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill)
        if (kill)
                tasklet_kill(&creq->creq_tasklet);
 
-       if (creq->requested) {
-               free_irq(creq->msix_vec, rcfw);
-               creq->requested = false;
-       }
+       free_irq(creq->msix_vec, rcfw);
+       creq->requested = false;
 }
 
 void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
@@ -692,8 +694,10 @@ int bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector,
                tasklet_enable(&creq->creq_tasklet);
        rc = request_irq(creq->msix_vec, bnxt_qplib_creq_irq, 0,
                         "bnxt_qplib_creq", rcfw);
-       if (rc)
+       if (rc) {
+               tasklet_disable(&creq->creq_tasklet);
                return rc;
+       }
        creq->requested = true;
 
        bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, true);