| From 87eb45709b1425895f12cad10f52193948a114b9 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 18 May 2023 23:48:11 -0700 |
| Subject: RDMA/bnxt_re: Disable/kill tasklet only if it is enabled |
| |
| From: Selvin Xavier <selvin.xavier@broadcom.com> |
| |
| [ 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 | 12 +++++++++--- |
| drivers/infiniband/hw/bnxt_re/qplib_fp.c | 16 ++++++++++------ |
| drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 14 +++++++++----- |
| 3 files changed, 28 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c |
| index 85e36c9f8e797..a9cc65614a9ee 100644 |
| --- a/drivers/infiniband/hw/bnxt_re/main.c |
| +++ b/drivers/infiniband/hw/bnxt_re/main.c |
| @@ -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; |
| + } |
| } |
| } |
| |
| diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c |
| index ab2cc1c67f70b..a143bd3580a27 100644 |
| --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c |
| +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c |
| @@ -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); |
| diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |
| index 061b2895dd9b5..e28f0eb5b55d4 100644 |
| --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |
| +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |
| @@ -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); |
| -- |
| 2.39.2 |
| |