Skip to content

Commit

Permalink
dmaengine: idxd: fix misc interrupt completion
Browse files Browse the repository at this point in the history
Nikhil reported the misc interrupt handler can sometimes miss handling
the command interrupt when an error interrupt happens near the same time.
Have the irq handling thread continue to process the misc interrupts until
all interrupts are processed. This is a low usage interrupt and is not
expected to handle high volume traffic. Therefore there is no concern of
this thread running for a long time.

Fixes: 0d5c10b ("dmaengine: idxd: add work queue drain support")
Reported-by: Nikhil Rao <nikhil.rao@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/161074755329.2183844.13295528344116907983.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
davejiang authored and vinodkoul committed Jan 17, 2021
1 parent 16e19e1 commit f5cc9ac
Showing 1 changed file with 27 additions and 9 deletions.
36 changes: 27 additions & 9 deletions drivers/dma/idxd/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,14 @@ irqreturn_t idxd_irq_handler(int vec, void *data)
return IRQ_WAKE_THREAD;
}

irqreturn_t idxd_misc_thread(int vec, void *data)
static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
{
struct idxd_irq_entry *irq_entry = data;
struct idxd_device *idxd = irq_entry->idxd;
struct device *dev = &idxd->pdev->dev;
union gensts_reg gensts;
u32 cause, val = 0;
u32 val = 0;
int i;
bool err = false;

cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);

if (cause & IDXD_INTC_ERR) {
spin_lock_bh(&idxd->dev_lock);
for (i = 0; i < 4; i++)
Expand Down Expand Up @@ -181,7 +176,7 @@ irqreturn_t idxd_misc_thread(int vec, void *data)
val);

if (!err)
goto out;
return 0;

/*
* This case should rarely happen and typically is due to software
Expand Down Expand Up @@ -211,10 +206,33 @@ irqreturn_t idxd_misc_thread(int vec, void *data)
gensts.reset_type == IDXD_DEVICE_RESET_FLR ?
"FLR" : "system reset");
spin_unlock_bh(&idxd->dev_lock);
return -ENXIO;
}
}

out:
return 0;
}

irqreturn_t idxd_misc_thread(int vec, void *data)
{
struct idxd_irq_entry *irq_entry = data;
struct idxd_device *idxd = irq_entry->idxd;
int rc;
u32 cause;

cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
if (cause)
iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);

while (cause) {
rc = process_misc_interrupts(idxd, cause);
if (rc < 0)
break;
cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
if (cause)
iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);
}

idxd_unmask_msix_vector(idxd, irq_entry->id);
return IRQ_HANDLED;
}
Expand Down

0 comments on commit f5cc9ac

Please sign in to comment.