RDMA/bnxt_re: Avoid calling wake_up threads from spin_lock context
authorKashyap Desai <kashyap.desai@broadcom.com>
Fri, 9 Jun 2023 11:01:39 +0000 (04:01 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Jul 2023 14:21:29 +0000 (16:21 +0200)
[ Upstream commit 3099bcdc19b701f732f638ee45679858c08559bb ]

bnxt_qplib_service_creq can be called from interrupt or tasklet or
process context. So the function take irq variant  of spin_lock.
But when wake_up is invoked with the lock held, it is putting the
calling context to sleep.

[exception RIP: __wake_up_common+190]
RIP: ffffffffb7539d7e  RSP: ffffa73300207ad8  RFLAGS: 00000083
RAX: 0000000000000001  RBX: ffff91fa295f69b8  RCX: dead000000000200
RDX: ffffa733344af940  RSI: ffffa73336527940  RDI: ffffa73336527940
RBP: 000000000000001c   R8: 0000000000000002   R9: 00000000000299c0
R10: 0000017230de82c5  R11: 0000000000000002  R12: ffffa73300207b28
R13: 0000000000000000  R14: ffffa733341bf928  R15: 0000000000000000
ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018

Call the wakeup after releasing the lock.

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/1686308514-11996-3-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/qplib_rcfw.c

index 3d76fa7..75e0c42 100644 (file)
@@ -299,7 +299,8 @@ static int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw,
 }
 
 static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
-                                      struct creq_qp_event *qp_event)
+                                      struct creq_qp_event *qp_event,
+                                      u32 *num_wait)
 {
        struct creq_qp_error_notification *err_event;
        struct bnxt_qplib_hwq *hwq = &rcfw->cmdq.hwq;
@@ -308,6 +309,7 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
        u16 cbit, blocked = 0;
        struct pci_dev *pdev;
        unsigned long flags;
+       u32 wait_cmds = 0;
        __le16  mcookie;
        u16 cookie;
        int rc = 0;
@@ -367,9 +369,10 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
                crsqe->req_size = 0;
 
                if (!blocked)
-                       wake_up(&rcfw->cmdq.waitq);
+                       wait_cmds++;
                spin_unlock_irqrestore(&hwq->lock, flags);
        }
+       *num_wait += wait_cmds;
        return rc;
 }
 
@@ -383,6 +386,7 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
        struct creq_base *creqe;
        u32 sw_cons, raw_cons;
        unsigned long flags;
+       u32 num_wakeup = 0;
 
        /* Service the CREQ until budget is over */
        spin_lock_irqsave(&hwq->lock, flags);
@@ -401,7 +405,8 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
                switch (type) {
                case CREQ_BASE_TYPE_QP_EVENT:
                        bnxt_qplib_process_qp_event
-                               (rcfw, (struct creq_qp_event *)creqe);
+                               (rcfw, (struct creq_qp_event *)creqe,
+                                &num_wakeup);
                        creq->stats.creq_qp_event_processed++;
                        break;
                case CREQ_BASE_TYPE_FUNC_EVENT:
@@ -429,6 +434,8 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
                                      rcfw->res->cctx, true);
        }
        spin_unlock_irqrestore(&hwq->lock, flags);
+       if (num_wakeup)
+               wake_up_nr(&rcfw->cmdq.waitq, num_wakeup);
 }
 
 static irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance)