Re: [PATCH v3 23/24] dmaengine: dw-edma: Detect and recover a stalled eDMA engine

[email protected] Mon, 27 Jul 2026 17:37:18 +0000
Newsgroups org.kernel.vger.dmaengine
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unkillable hang in dw_edma_wait_termination() if the engine fails to recover from a stall.
--

--- Patch [23]: [PATCH v3 23/24] dmaengine: dw-edma: Detect and recover a stalled eDMA engine ---
commit 8c110ba5f33df8c06f35fa69ddd95a9b7e7cab52
Author: Koichiro Den <[email protected]>

dmaengine: dw-edma: Detect and recover a stalled eDMA engine

This commit introduces passive stall detection for write channels under
sustained multi-channel traffic. It reuses the bounded LL recheck and queues a
recovery request if a channel remains stopped with no progress for 30 ms.

> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 56032137a4bb0..262ea893174f3 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
[ ... ]
> @@ -291,6 +292,54 @@ static bool dw_edma_ll_pending(struct dw_edma_chan *chan)
>  	return chan->ll_head != chan->ll_done;
>  }
>  
[ ... ]
> +/*
> + * Called with vc.lock held for a stopped channel with LL work pending. Queue
> + * direction recovery if repeated doorbells show no progress for one recheck
> + * interval.
> + */
> +static bool dw_edma_ll_stall_check(struct dw_edma_chan *chan)
> +{
> +	struct dw_edma_engine_recovery *rec;
> +
[ ... ]
> +	rec = &chan->dw->eng_recovery[chan->dir];
> +	chan->ll_recovery_pending = true;
> +	dw_edma_engine_recovery_queue(rec);

[Severity: High]
If the hardware stalls and the recovery work queued here fails to reset it,
can this lead to an unkillable hang later when the channel is freed?

Looking at dw_edma_engine_recovery_work(), if the maximum reset attempts are
reached, the worker exits without clearing chan->ll_recovering:

drivers/dma/dw-edma/dw-edma-core.c:dw_edma_engine_recovery_work() {
    ...
		if (++rec->fails >= DW_EDMA_ENGINE_RESET_MAX_FAILS) {
			dev_err(dw->chip->dev,
				"%s engine did not drain after %u attempts; leaving channels gated\n",
				dir_name, rec->fails);
			return;
		}
    ...
}

If chan->ll_recovering remains true, the doorbell logic aborts early and does
not process the stop request when releasing the channel. 

This causes dw_edma_wait_termination() to loop indefinitely because the loop
lacks a hard timeout break and the stop request is never cleared:

drivers/dma/dw-edma/dw-edma-core.c:dw_edma_wait_termination() {
    ...
	for (;;) {
		scoped_guard(spinlock_irqsave, &chan->vc.lock)
			stopping = chan->request == EDMA_REQ_STOP;

		if (!stopping)
			return;

		if (time_after_eq(jiffies, timeout)) {
			dev_warn(chan->dw->chip->dev,
				 "timeout waiting for channel termination; still waiting\n");
			timeout = jiffies + msecs_to_jiffies(5000);
		}

		fsleep(1000);
	}
    ...
}

Could this result in an unkillable process hang when dw_edma_wait_termination()
polls indefinitely?

> +
> +	return false;
> +}

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=23