From: sashiko-bot@kernel.org
To: "Koichiro Den" <den@valinux.co.jp>
Cc: Frank.Li@kernel.org, dmaengine@vger.kernel.org, vkoul@kernel.org
Subject: Re: [PATCH v3 2/9] dmaengine: dw-edma: Terminate all descriptors without callbacks
Date: Wed, 15 Jul 2026 18:24:57 +0000 [thread overview]
Message-ID: <20260715182457.E94211F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260715175740.1110404-3-den@valinux.co.jp>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] `dmaengine_synchronize()` explicitly waits for and causes the channel to lose its configuration, breaking generic clients that expect to reuse the channel without calling `dmaengine_slave_config()` again.
Pre-existing issues:
- [High] State updates in `dw_edma_abort_interrupt` are performed outside the channel lock, creating a data race that can permanently stall the channel.
- [High] `dw_edma_device_pause` and `dw_edma_device_resume` read and modify channel state variables without acquiring `chan->vc.lock`.
--
--- Patch [2]: [PATCH v3 2/9] dmaengine: dw-edma: Terminate all descriptors without callbacks ---
commit ca03488a0b49733d1020ab17fdc7c52f079bfb7c
Author: Koichiro Den <den@valinux.co.jp>
dmaengine: dw-edma: Terminate all descriptors without callbacks
This commit changes the termination behavior of the dw-edma driver. It
moves all issued and submitted descriptors to the terminated list without
scheduling callbacks when termination completes. It also introduces
dw_edma_device_synchronize() to wait for channel termination.
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 89a4c498a17b8..44ef5fbe3fd4a 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
[ ... ]
> @@ -306,20 +336,25 @@ static int dw_edma_device_resume(struct dma_chan *dchan)
[Severity: High]
This is a pre-existing issue, but does dw_edma_device_pause() and
dw_edma_device_resume() have a data race?
In drivers/dma/dw-edma/dw-edma-core.c:dw_edma_device_pause():
if (!chan->configured)
err = -EPERM;
else if (chan->status != EDMA_ST_BUSY)
err = -EPERM;
else if (chan->request != EDMA_REQ_NONE)
err = -EPERM;
else
chan->request = EDMA_REQ_PAUSE;
These functions read and modify chan->status and chan->request without
acquiring chan->vc.lock. If device_pause() runs concurrently with an
interrupt completing a transfer, it might overwrite chan->request to
EDMA_REQ_PAUSE on an already idle channel, preventing new transfers from
starting.
Similarly, device_resume() calls dw_edma_start_transfer() which manipulates
virt-dma lists without synchronization.
> static int dw_edma_device_terminate_all(struct dma_chan *dchan)
> {
[ ... ]
> @@ -698,7 +733,9 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
>
> spin_lock_irqsave(&chan->vc.lock, flags);
> vd = vchan_next_desc(&chan->vc);
> - if (vd) {
> + if (vd && chan->request == EDMA_REQ_STOP) {
> + dw_edma_terminate_all_descs(chan);
> + } else if (vd) {
> dw_hdma_set_callback_result(vd, DMA_TRANS_ABORTED);
> list_del(&vd->node);
> vchan_cookie_complete(vd);
[Severity: High]
This is a pre-existing issue, but can this sequence permanently stall the
channel?
The end of dw_edma_abort_interrupt() looks like this:
spin_unlock_irqrestore(&chan->vc.lock, flags);
chan->request = EDMA_REQ_NONE;
chan->status = EDMA_ST_IDLE;
}
Because chan->request and chan->status are updated after releasing
chan->vc.lock, a concurrent client completion callback could queue a new
descriptor and call dma_async_issue_pending().
The issue_pending() call would acquire the lock, observe the stale
chan->status (e.g. EDMA_ST_BUSY), and fail to start the hardware. The
interrupt handler then unconditionally writes EDMA_ST_IDLE, leaving the
hardware idle while the descriptor is stuck in the desc_issued list.
[ ... ]
> @@ -856,21 +893,48 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> return 0;
> }
>
> -static void dw_edma_free_chan_resources(struct dma_chan *dchan)
> +static void dw_edma_wait_termination(struct dma_chan *dchan)
> {
> + struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> unsigned long timeout = jiffies + msecs_to_jiffies(5000);
> - int ret;
> + unsigned long flags;
> + bool configured = true;
>
> + /*
> + * dw_edma_device_terminate_all() may defer cleanup to a later interrupt
> + * while the channel is still running. Retry until the channel is
> + * deconfigured, which means termination is complete.
> + */
> while (time_before(jiffies, timeout)) {
> - ret = dw_edma_device_terminate_all(dchan);
> - if (!ret)
> - break;
> + dw_edma_device_terminate_all(dchan);
>
> - if (time_after_eq(jiffies, timeout))
> + spin_lock_irqsave(&chan->vc.lock, flags);
> + configured = chan->configured;
> + spin_unlock_irqrestore(&chan->vc.lock, flags);
> + if (!configured)
> return;
>
[Severity: High]
Will this break generic dmaengine clients?
The loop in dw_edma_wait_termination() forces the channel to become
unconfigured by polling dw_edma_device_terminate_all() until
chan->configured is set to false.
However, dw_edma_wait_termination() is called by dw_edma_device_synchronize().
Generic dmaengine clients expect the channel configuration to persist across
dmaengine_terminate_sync(). Because this explicitly clears the configuration,
subsequent dmaengine_prep_* calls from generic clients will return NULL
and fail.
> - cpu_relax();
> + usleep_range(1000, 2000);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260715175740.1110404-1-den@valinux.co.jp?part=2
next prev parent reply other threads:[~2026-07-15 18:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 17:57 [PATCH v3 0/9] dmaengine: dw-edma: Fixes and interrupt-path groundwork Koichiro Den
2026-07-15 17:57 ` [PATCH v3 1/9] dmaengine: dw-edma: Fix HDMA channel status register access Koichiro Den
2026-07-15 17:57 ` [PATCH v3 2/9] dmaengine: dw-edma: Terminate all descriptors without callbacks Koichiro Den
2026-07-15 18:24 ` sashiko-bot [this message]
2026-07-15 18:54 ` Frank Li
2026-07-15 17:57 ` [PATCH v3 3/9] dmaengine: dw-edma: Serialize abort state updates Koichiro Den
2026-07-15 18:15 ` sashiko-bot
2026-07-15 18:55 ` Frank Li
2026-07-15 17:57 ` [PATCH v3 4/9] dmaengine: dw-edma: Complete descriptors before pausing Koichiro Den
2026-07-15 18:15 ` sashiko-bot
2026-07-15 18:56 ` Frank Li
2026-07-15 17:57 ` [PATCH v3 5/9] dmaengine: dw-edma: Serialize channel state checks Koichiro Den
2026-07-15 18:19 ` sashiko-bot
2026-07-15 18:58 ` Frank Li
2026-07-15 17:57 ` [PATCH v3 6/9] dmaengine: dw-edma: Clear stale requests on termination Koichiro Den
2026-07-15 18:19 ` sashiko-bot
2026-07-15 19:00 ` Frank Li
2026-07-15 17:57 ` [PATCH v3 7/9] dmaengine: dw-edma-pcie: Drop redundant pci_free_irq_vectors() Koichiro Den
2026-07-15 17:57 ` [PATCH v3 8/9] dmaengine: dw-edma: Snapshot the v0 interrupt status once per handler pass Koichiro Den
2026-07-15 17:57 ` [PATCH v3 9/9] dmaengine: dw-edma: Defer channel IRQ handling to workqueue Koichiro Den
2026-07-15 18:33 ` sashiko-bot
2026-07-15 19:02 ` Frank Li
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=20260715182457.E94211F00A3A@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.