[PATCH v3 06/24] dmaengine: dw-edma: Dispatch DONE interrupts by channel request

From: Koichiro Den

Date: Mon Jul 27 2026 - 13:15:40 EST


Prepare for LL progress reclamation, which can complete and remove the
last issued descriptor before DONE request handling runs. STOP and PAUSE
still have state to update even when no descriptor remains.

Move the request switch outside the descriptor check, and look up a
descriptor only in the cases that need one. Keep this non-functional
reordering separate from progress accounting.

No functional change.

Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
Changes in v3:
- Explain that this reordering prepares for LL progress reclamation.
(Frank)

drivers/dma/dw-edma/dw-edma-core.c | 56 ++++++++++++++++--------------
1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 6e7d1f7c20f9..b419ff2becf9 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -697,39 +697,41 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
return;
}

- vd = vchan_next_desc(&chan->vc);
- if (vd) {
- switch (chan->request) {
- case EDMA_REQ_NONE:
- case EDMA_REQ_PAUSE:
- desc = vd2dw_edma_desc(vd);
- if (desc->start_burst >= desc->nburst) {
- dw_hdma_set_callback_result(vd,
- DMA_TRANS_NOERROR);
- list_del(&vd->node);
- vchan_cookie_complete(vd);
- if (!chan->non_ll)
- chan->ll_done = chan->ll_head;
- }
+ switch (chan->request) {
+ case EDMA_REQ_NONE:
+ case EDMA_REQ_PAUSE:
+ vd = vchan_next_desc(&chan->vc);
+ if (!vd)
+ break;

- if (chan->request == EDMA_REQ_PAUSE) {
- chan->request = EDMA_REQ_NONE;
- chan->status = EDMA_ST_PAUSE;
- break;
- }
+ desc = vd2dw_edma_desc(vd);
+ if (desc->start_burst >= desc->nburst) {
+ dw_hdma_set_callback_result(vd, DMA_TRANS_NOERROR);
+ list_del(&vd->node);
+ vchan_cookie_complete(vd);
+ if (!chan->non_ll)
+ chan->ll_done = chan->ll_head;
+ }

- /* Continue transferring if there are remaining chunks or issued requests.
- */
- chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
+ if (chan->request == EDMA_REQ_PAUSE) {
+ chan->request = EDMA_REQ_NONE;
+ chan->status = EDMA_ST_PAUSE;
break;
+ }

- case EDMA_REQ_STOP:
- dw_edma_finish_termination(chan);
- break;
+ chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
+ break;

- default:
+ case EDMA_REQ_STOP:
+ vd = vchan_next_desc(&chan->vc);
+ if (!vd)
break;
- }
+
+ dw_edma_finish_termination(chan);
+ break;
+
+ default:
+ break;
}
spin_unlock_irqrestore(&chan->vc.lock, flags);
}
--
2.51.0