From: sashiko-bot@kernel.org
To: "Koichiro Den" <den@valinux.co.jp>
Cc: vkoul@kernel.org, dmaengine@vger.kernel.org, Frank.Li@kernel.org
Subject: Re: [PATCH v2 16/19] dmaengine: dw-edma: Add engine recovery infrastructure
Date: Thu, 23 Jul 2026 09:14:28 +0000 [thread overview]
Message-ID: <20260723091434.F0A131F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260723084150.521366-17-den@valinux.co.jp>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] Hardware interrupts are disabled via free_irq() before the hardware engine is stopped, risking an interrupt storm.
- [High] Passive stall detection will fail to trigger recovery for sleeping clients, leading to indefinite hangs.
- [High] Queueing work on a destroyed workqueue during driver removal leads to a kernel crash.
- [Low] Mixing goto-based cleanup labels with guard()/scoped_guard() declarations in the same function.
Pre-existing issues:
- [High] IRQs are requested before channels are fully initialized, leading to potential crashes from early interrupts.
--
--- Patch [16]: [PATCH v2 16/19] dmaengine: dw-edma: Add engine recovery infrastructure ---
commit 348674e8eed041726892cbce36b8d539a278c6d1
Author: Koichiro Den <den@valinux.co.jp>
Subject: dmaengine: dw-edma: Add engine recovery infrastructure
This commit adds a worker to coordinate engine recovery in the dw-edma
driver. It gates publication and doorbells, waits for channels to stop,
and rebuilds linked-list contexts after resetting the engine.
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 9305137f85f67..14cd0038dbd27 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
[ ... ]
> +static void dw_edma_engine_recovery_work(struct work_struct *work)
> +{
> + struct dw_edma_engine_recovery *rec =
> + container_of(work, struct dw_edma_engine_recovery, work);
> + struct dw_edma *dw = rec->dw;
> + const char *dir_name = str_write_read(rec->dir == EDMA_DIR_WRITE);
> + u16 off = rec->dir == EDMA_DIR_WRITE ? 0 : dw->wr_ch_cnt;
> + u16 cnt = rec->dir == EDMA_DIR_WRITE ? dw->wr_ch_cnt : dw->rd_ch_cnt;
> + unsigned long timeout =
> + jiffies + msecs_to_jiffies(DW_EDMA_ENGINE_QUIESCE_TIMEOUT_MS);
> + struct dw_edma_chan *chan;
> + bool configured_ll;
> + bool busy;
> + u16 i;
> +
> + if (!dw_edma_engine_recovery_needed(rec)) {
> + if (READ_ONCE(rec->active))
> + dw_edma_engine_recovery_release(rec);
> + return;
> + }
> +
> + WRITE_ONCE(rec->active, true);
> +
> + /* Gate each channel before inspecting or resetting the direction. */
> + for (i = 0; i < cnt; i++) {
> + chan = &dw->chan[off + i];
> + guard(spinlock_irqsave)(&chan->vc.lock);
[Severity: Low]
Does this code violate the cleanup subsystem guidelines by mixing goto-based
cleanup labels with scope-based guards?
The cleanup subsystem guide explicitly states that functions must not mix
goto-based cleanup labels with guard() or scoped_guard() declarations. This
function uses a goto out_release; label further down, while declaring
guard(spinlock_irqsave) here in the loop.
[ ... ]
> + if (moving) {
> + dev_warn_ratelimited(dw->chip->dev,
> + "%s engine quiesce timed out with transfers still progressing, retrying\n",
> + dir_name);
> + queue_work(dw->wq, &rec->work);
> + return;
> + }
> +
> + dev_warn(dw->chip->dev,
> + "%s engine reset with a channel frozen mid-element\n",
> + dir_name);
> + }
> +
> + if (!dw_edma_engine_recovery_needed(rec))
> + goto out_release;
[ ... ]
> + if (!dw->core->engine_reset(dw, rec->dir)) {
> + /*
> + * Keep channels gated and do not re-enable the engine unless
> + * ENGINE_EN clears.
> + */
> + 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;
> + }
> + queue_work(dw->wq, &rec->work);
[Severity: High]
Can passive stall detection fail to trigger this recovery for clients that
are sleeping?
The stall check relies on dw_edma_ll_stall_check() reading timeouts, but
it appears to only be invoked when dw_edma_core_ch_maybe_doorbell() is
called. If a hardware channel freezes and generates no further interrupts
while a client waits via wait_for_completion(), could the stall go
completely undetected because the status is never actively polled?
[ ... ]
> @@ -1640,6 +1905,13 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>
> raw_spin_lock_init(&dw->lock);
>
> + for (i = 0; i < ARRAY_SIZE(dw->eng_recovery); i++) {
> + dw->eng_recovery[i].dw = dw;
> + dw->eng_recovery[i].dir = i;
> + INIT_WORK(&dw->eng_recovery[i].work,
> + dw_edma_engine_recovery_work);
> + }
> +
[Severity: High]
This is a pre-existing issue, but does dw_edma_probe() register interrupts
before the driver's internal channel state is initialized?
In dw_edma_probe(), the interrupt handler is registered by calling
dw_edma_irq_request() before the channel structures and work items are
fully initialized via dw_edma_channel_setup().
If a spurious or shared interrupt fires immediately after registration:
dw_edma_probe()
dw_edma_irq_request(dw, &wr_alloc, &rd_alloc);
...
dw_edma_channel_setup(dw, wr_alloc, rd_alloc);
Could this attempt to access or queue work using zeroed memory, leading to
a kernel crash?
[ ... ]
> @@ -1738,11 +2010,6 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> if (!dw)
> return -ENODEV;
>
> - if (chip->flags & DW_EDMA_CHIP_PARTIAL)
> - err = dw_edma_core_quiesce(dw);
> - else
> - dw_edma_core_off(dw);
> -
> /* Free irqs */
> for (i = (dw->nr_irqs - 1); i >= 0; i--)
> free_irq(chip->ops->irq_vector(dev, i), &dw->irq[i]);
> @@ -1751,6 +2018,16 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> for (i = 0; i < dw->wr_ch_cnt + dw->rd_ch_cnt; i++)
> cancel_work_sync(&dw->chan[i].irq_work);
>
> + /* Prevent a running recovery worker from requeueing itself. */
> + disable_work_sync(&dw->eng_recovery[0].work);
> + disable_work_sync(&dw->eng_recovery[1].work);
> +
> + /* A recovery worker can re-enable the engine, so stop it last. */
> + if (chip->flags & DW_EDMA_CHIP_PARTIAL)
> + err = dw_edma_core_quiesce(dw);
> + else
> + dw_edma_core_off(dw);
> +
[Severity: High]
Will moving dw_edma_core_off() after free_irq() risk an interrupt storm?
By tearing down the interrupt handler before stopping the hardware, the
hardware remains fully active while its handler is unregistered. If the
engine generates an interrupt, a shared interrupt handler would return
IRQ_NONE. Because the hardware interrupt is never cleared, won't the CPU
get stuck in an interrupt loop until the kernel disables the shared IRQ
line completely?
> destroy_workqueue(dw->wq);
>
> /* Deregister eDMA device */
[Severity: High]
Could destroying the workqueue before unregistering the DMA device cause
a use-after-free crash?
Since destroy_workqueue() is called before dma_async_device_unregister(),
the device is still visible to clients. If a client software calls
dmaengine_tx_status() during driver unload, it can invoke
dw_edma_core_ch_maybe_doorbell(). With this patch, the doorbell logic now
eventually hits dw_edma_ll_stall_check(), which can call
queue_work(chan->dw->wq, &rec->work).
Could this attempt to queue work on the already-destroyed workqueue?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260723084150.521366-1-den@valinux.co.jp?part=16
next prev parent reply other threads:[~2026-07-23 9:14 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 8:41 [PATCH v2 00/19] dmaengine: dw-edma: Support dynamic LL appends Koichiro Den
2026-07-23 8:41 ` [PATCH v2 01/19] dmaengine: dw-edma: Add dw_edma_core_ll_cur_idx() to get current LL entry index Koichiro Den
2026-07-23 16:25 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 02/19] dmaengine: dw-edma: Add dw_edma_core_ll_clear() to clear LL control-word Koichiro Den
2026-07-23 18:53 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 03/19] dmaengine: dw-edma: Factor out linked-list transfer start Koichiro Den
2026-07-23 16:31 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 04/19] dmaengine: dw-edma: Make DMA link list work as a circular buffer Koichiro Den
2026-07-23 9:07 ` sashiko-bot
2026-07-23 16:43 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 05/19] dmaengine: dw-edma: Add LL interrupt placement policy Koichiro Den
2026-07-23 19:58 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 06/19] dmaengine: dw-edma: Move callback result helper before LL helpers Koichiro Den
2026-07-23 16:51 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 07/19] dmaengine: dw-edma: Dispatch DONE interrupts by channel request Koichiro Den
2026-07-23 8:55 ` sashiko-bot
2026-07-23 16:57 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 08/19] dmaengine: dw-edma: Centralize LL doorbell decisions Koichiro Den
2026-07-23 9:09 ` sashiko-bot
2026-07-23 17:02 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 09/19] dmaengine: dw-edma: Reclaim issued descriptors from IRQ-paired LL progress Koichiro Den
2026-07-23 9:01 ` sashiko-bot
2026-07-23 20:56 ` Frank Li
2026-07-23 8:41 ` [PATCH v2 10/19] dmaengine: dw-edma: Use HDMA watermarks as progress events Koichiro Den
2026-07-23 8:41 ` [PATCH v2 11/19] dmaengine: dw-edma: Reconcile lost completions from a stopped LLP re-sample Koichiro Den
2026-07-23 8:41 ` [PATCH v2 12/19] dmaengine: dw-edma: Recover stopped channels from tx_status() Koichiro Den
2026-07-23 8:59 ` sashiko-bot
2026-07-23 8:41 ` [PATCH v2 13/19] dmaengine: dw-edma: Make the LL ring reset a full channel resync Koichiro Den
2026-07-23 9:10 ` sashiko-bot
2026-07-23 8:41 ` [PATCH v2 14/19] dmaengine: dw-edma: Reset LL state after terminate and abort Koichiro Den
2026-07-23 9:14 ` sashiko-bot
2026-07-23 8:41 ` [PATCH v2 15/19] dmaengine: dw-edma: Add engine reset and enable operations Koichiro Den
2026-07-23 9:11 ` sashiko-bot
2026-07-23 8:41 ` [PATCH v2 16/19] dmaengine: dw-edma: Add engine recovery infrastructure Koichiro Den
2026-07-23 9:14 ` sashiko-bot [this message]
2026-07-23 8:41 ` [PATCH v2 17/19] dmaengine: dw-edma: Detect and recover a stalled eDMA engine Koichiro Den
2026-07-23 9:12 ` sashiko-bot
2026-07-23 8:41 ` [PATCH v2 18/19] dmaengine: dw-edma: Dynamically append requests while running Koichiro Den
2026-07-23 8:41 ` [PATCH v2 19/19] dmaengine: dw-edma: Add trace support Koichiro Den
2026-07-23 9:11 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260723091434.F0A131F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=den@valinux.co.jp \
--cc=dmaengine@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.