[PATCH 6/6] dmaengine: idxd: Do not release interrupt handles on terminate_all

From: Vinicius Costa Gomes

Date: Mon Oct 12 2026 - 17:44:40 EST


idxd_wq_flush_descs() is called from the dmaengine .device_terminate_all
path, but besides flushing the pending descriptors it also releases the
interrupt handle. As the workqueue stays enabled, the handle is never
re-armed, and any subsequent submission uses an invalid handle and never
completes.

This only shows up when the same workqueue is used more than once: the
first run leaves the handle released on terminate_all, so any later run
times out on every descriptor. dmatest reproduces it by running twice.

Split the interrupt handle teardown into idxd_wq_release_int_handle() so
that terminate_all only flushes descriptors. The FLR path still needs
both, so call them together there.

Fixes: 2a93f5747d0e ("dmaengine: idxd: Flush all pending descriptors")
Reported-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@xxxxxxxxx>
---
drivers/dma/idxd/device.c | 11 ++++++++++-
drivers/dma/idxd/idxd.h | 1 +
drivers/dma/idxd/irq.c | 1 +
3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 131138483b87..06299f40f531 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -1349,6 +1349,16 @@ void idxd_wq_free_irq(struct idxd_wq *wq)
}

void idxd_wq_flush_descs(struct idxd_wq *wq)
+{
+ guard(mutex)(&wq->wq_lock);
+
+ if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL)
+ return;
+
+ idxd_flush_pending_descs(&wq->ie);
+}
+
+void idxd_wq_release_int_handle(struct idxd_wq *wq)
{
struct idxd_irq_entry *ie = &wq->ie;
struct idxd_device *idxd = wq->idxd;
@@ -1358,7 +1368,6 @@ void idxd_wq_flush_descs(struct idxd_wq *wq)
if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL)
return;

- idxd_flush_pending_descs(ie);
if (idxd->request_int_handles)
idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX);
idxd_device_clear_perm_entry(idxd, ie);
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index ce78b9a7c641..f4aed90560e0 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -804,6 +804,7 @@ int idxd_wq_init_percpu_ref(struct idxd_wq *wq);
void idxd_wq_free_irq(struct idxd_wq *wq);
int idxd_wq_request_irq(struct idxd_wq *wq);
void idxd_wq_flush_descs(struct idxd_wq *wq);
+void idxd_wq_release_int_handle(struct idxd_wq *wq);

/* submission */
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc);
diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
index 6a25e1fd0e62..26d75d744797 100644
--- a/drivers/dma/idxd/irq.c
+++ b/drivers/dma/idxd/irq.c
@@ -405,6 +405,7 @@ static void idxd_wqs_flush_descs(struct idxd_device *idxd)
struct idxd_wq *wq = idxd->wqs[i];

idxd_wq_flush_descs(wq);
+ idxd_wq_release_int_handle(wq);
}
}


--
2.56.0