Commit 4f302642 authored by Dave Jiang's avatar Dave Jiang Committed by Vinod Koul

dmaengine: idxd: fix interrupt completion after unmasking

The current implementation may miss completions after we unmask the
interrupt. In order to make sure we process all competions, we need to:
1. Do an MMIO read from the device as a barrier to ensure that all PCI
   writes for completions have arrived.
2. Check for any additional completions that we missed.

Fixes: 8f47d1a5 ("dmaengine: idxd: connect idxd to dmaengine subsystem")
Reported-by: default avatarSanjay Kumar <sanjay.k.kumar@intel.com>
Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/158834641769.35613.1341160109892008587.stgit@djiang5-desk3.ch.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent f8f482de
...@@ -62,6 +62,13 @@ int idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id) ...@@ -62,6 +62,13 @@ int idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id)
perm.ignore = 0; perm.ignore = 0;
iowrite32(perm.bits, idxd->reg_base + offset); iowrite32(perm.bits, idxd->reg_base + offset);
/*
* A readback from the device ensures that any previously generated
* completion record writes are visible to software based on PCI
* ordering rules.
*/
perm.bits = ioread32(idxd->reg_base + offset);
return 0; return 0;
} }
......
...@@ -173,6 +173,7 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry, ...@@ -173,6 +173,7 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
struct llist_node *head; struct llist_node *head;
int queued = 0; int queued = 0;
*processed = 0;
head = llist_del_all(&irq_entry->pending_llist); head = llist_del_all(&irq_entry->pending_llist);
if (!head) if (!head)
return 0; return 0;
...@@ -197,6 +198,7 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, ...@@ -197,6 +198,7 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
struct list_head *node, *next; struct list_head *node, *next;
int queued = 0; int queued = 0;
*processed = 0;
if (list_empty(&irq_entry->work_list)) if (list_empty(&irq_entry->work_list))
return 0; return 0;
...@@ -218,10 +220,9 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry, ...@@ -218,10 +220,9 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
return queued; return queued;
} }
irqreturn_t idxd_wq_thread(int irq, void *data) static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
{ {
struct idxd_irq_entry *irq_entry = data; int rc, processed, total = 0;
int rc, processed = 0, retry = 0;
/* /*
* There are two lists we are processing. The pending_llist is where * There are two lists we are processing. The pending_llist is where
...@@ -244,15 +245,26 @@ irqreturn_t idxd_wq_thread(int irq, void *data) ...@@ -244,15 +245,26 @@ irqreturn_t idxd_wq_thread(int irq, void *data)
*/ */
do { do {
rc = irq_process_work_list(irq_entry, &processed); rc = irq_process_work_list(irq_entry, &processed);
if (rc != 0) { total += processed;
retry++; if (rc != 0)
continue; continue;
}
rc = irq_process_pending_llist(irq_entry, &processed); rc = irq_process_pending_llist(irq_entry, &processed);
} while (rc != 0 && retry != 10); total += processed;
} while (rc != 0);
return total;
}
irqreturn_t idxd_wq_thread(int irq, void *data)
{
struct idxd_irq_entry *irq_entry = data;
int processed;
processed = idxd_desc_process(irq_entry);
idxd_unmask_msix_vector(irq_entry->idxd, irq_entry->id); idxd_unmask_msix_vector(irq_entry->idxd, irq_entry->id);
/* catch anything unprocessed after unmasking */
processed += idxd_desc_process(irq_entry);
if (processed == 0) if (processed == 0)
return IRQ_NONE; return IRQ_NONE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment