Skip to content

Commit c0409dd

Browse files
zhangl6vinodkoul
authored andcommitted
dmaengine: idxd: use spin_lock_irqsave before wait_event_lock_irq
In idxd_cmd_exec(), wait_event_lock_irq() explicitly calls spin_unlock_irq()/spin_lock_irq(). If the interrupt is on before entering wait_event_lock_irq(), it will become off status after wait_event_lock_irq() is called. Later, wait_for_completion() may go to sleep but irq is disabled. The scenario is warned in might_sleep(). Fix it by using spin_lock_irqsave() instead of the primitive spin_lock() to save the irq status before entering wait_event_lock_irq() and using spin_unlock_irqrestore() instead of the primitive spin_unlock() to restore the irq status before entering wait_for_completion(). Before the change: idxd_cmd_exec() { interrupt is on spin_lock() // interrupt is on wait_event_lock_irq() spin_unlock_irq() // interrupt is enabled ... spin_lock_irq() // interrupt is disabled spin_unlock() // interrupt is still disabled wait_for_completion() // report "BUG: sleeping function // called from invalid context... // in_atomic() irqs_disabled()" } After applying spin_lock_irqsave(): idxd_cmd_exec() { interrupt is on spin_lock_irqsave() // save the on state // interrupt is disabled wait_event_lock_irq() spin_unlock_irq() // interrupt is enabled ... spin_lock_irq() // interrupt is disabled spin_unlock_irqrestore() // interrupt is restored to on wait_for_completion() // No Call trace } Fixes: f9f4082 ("dmaengine: idxd: remove interrupt disable for cmd_lock") Signed-off-by: Rex Zhang <[email protected]> Signed-off-by: Lijun Pan <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Fenghua Yu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 3f4b821 commit c0409dd

File tree

1 file changed

+3
-2
lines changed

1 file changed

+3
-2
lines changed

drivers/dma/idxd/device.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
477477
union idxd_command_reg cmd;
478478
DECLARE_COMPLETION_ONSTACK(done);
479479
u32 stat;
480+
unsigned long flags;
480481

481482
if (idxd_device_is_halted(idxd)) {
482483
dev_warn(&idxd->pdev->dev, "Device is HALTED!\n");
@@ -490,7 +491,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
490491
cmd.operand = operand;
491492
cmd.int_req = 1;
492493

493-
spin_lock(&idxd->cmd_lock);
494+
spin_lock_irqsave(&idxd->cmd_lock, flags);
494495
wait_event_lock_irq(idxd->cmd_waitq,
495496
!test_bit(IDXD_FLAG_CMD_RUNNING, &idxd->flags),
496497
idxd->cmd_lock);
@@ -507,7 +508,7 @@ static void idxd_cmd_exec(struct idxd_device *idxd, int cmd_code, u32 operand,
507508
* After command submitted, release lock and go to sleep until
508509
* the command completes via interrupt.
509510
*/
510-
spin_unlock(&idxd->cmd_lock);
511+
spin_unlock_irqrestore(&idxd->cmd_lock, flags);
511512
wait_for_completion(&done);
512513
stat = ioread32(idxd->reg_base + IDXD_CMDSTS_OFFSET);
513514
spin_lock(&idxd->cmd_lock);

0 commit comments

Comments
 (0)