Skip to content

Commit 4f30264

Browse files
davejiangvinodkoul
authored andcommitted
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: 8f47d1a ("dmaengine: idxd: connect idxd to dmaengine subsystem") Reported-by: Sanjay Kumar <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/158834641769.35613.1341160109892008587.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <[email protected]>
1 parent f8f482d commit 4f30264

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

drivers/dma/idxd/device.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ int idxd_unmask_msix_vector(struct idxd_device *idxd, int vec_id)
6262
perm.ignore = 0;
6363
iowrite32(perm.bits, idxd->reg_base + offset);
6464

65+
/*
66+
* A readback from the device ensures that any previously generated
67+
* completion record writes are visible to software based on PCI
68+
* ordering rules.
69+
*/
70+
perm.bits = ioread32(idxd->reg_base + offset);
71+
6572
return 0;
6673
}
6774

drivers/dma/idxd/irq.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ static int irq_process_pending_llist(struct idxd_irq_entry *irq_entry,
173173
struct llist_node *head;
174174
int queued = 0;
175175

176+
*processed = 0;
176177
head = llist_del_all(&irq_entry->pending_llist);
177178
if (!head)
178179
return 0;
@@ -197,6 +198,7 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
197198
struct list_head *node, *next;
198199
int queued = 0;
199200

201+
*processed = 0;
200202
if (list_empty(&irq_entry->work_list))
201203
return 0;
202204

@@ -218,10 +220,9 @@ static int irq_process_work_list(struct idxd_irq_entry *irq_entry,
218220
return queued;
219221
}
220222

221-
irqreturn_t idxd_wq_thread(int irq, void *data)
223+
static int idxd_desc_process(struct idxd_irq_entry *irq_entry)
222224
{
223-
struct idxd_irq_entry *irq_entry = data;
224-
int rc, processed = 0, retry = 0;
225+
int rc, processed, total = 0;
225226

226227
/*
227228
* 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)
244245
*/
245246
do {
246247
rc = irq_process_work_list(irq_entry, &processed);
247-
if (rc != 0) {
248-
retry++;
248+
total += processed;
249+
if (rc != 0)
249250
continue;
250-
}
251251

252252
rc = irq_process_pending_llist(irq_entry, &processed);
253-
} while (rc != 0 && retry != 10);
253+
total += processed;
254+
} while (rc != 0);
255+
256+
return total;
257+
}
258+
259+
irqreturn_t idxd_wq_thread(int irq, void *data)
260+
{
261+
struct idxd_irq_entry *irq_entry = data;
262+
int processed;
254263

264+
processed = idxd_desc_process(irq_entry);
255265
idxd_unmask_msix_vector(irq_entry->idxd, irq_entry->id);
266+
/* catch anything unprocessed after unmasking */
267+
processed += idxd_desc_process(irq_entry);
256268

257269
if (processed == 0)
258270
return IRQ_NONE;

0 commit comments

Comments
 (0)