From: sashiko-bot@kernel.org
To: "Li Youhong" <dayou5941@163.com>
Cc: vkoul@kernel.org, dmaengine@vger.kernel.org, Frank.Li@kernel.org
Subject: Re: [PATCH v3] dmaengine: dw-axi-dmac: convert to clk bulk APIs
Date: Wed, 02 Sep 2026 01:45:03 +0000 [thread overview]
Message-ID: <20260902014504.065151F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260902013016.3381788-1-dayou5941@163.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] Unchecked clk_bulk_prepare_enable() in dw_remove() introduces a regression where a partial clock failure guarantees an external abort.
Pre-existing issues:
- [High] Virt-dma tasklets are not killed on probe error paths, risking Use-After-Free if scheduled.
- [High] Premature IRQ registration before channel registers are mapped and clocks are enabled risks NULL pointer dereference and bus faults.
- [High] `dw_remove()` modifies per-channel hardware state without holding the required `chan->vc.lock`, allowing concurrent DMA operations to unsafely re-enable channels.
- [High] The driver relies on devres to unregister the DMA engine asynchronously after `dw_remove()` completes, exposing suspended hardware to concurrent DMA clients.
--
commit 40975e504ffaf6727d542d4c2cde656ef32bc7dc
Author: Li Youhong <liyouhong@kylinos.cn>
dmaengine: dw-axi-dmac: convert to clk bulk APIs
axi_dma_resume() enables cfgr_clk then core_clk. If enabling
core_clk fails, return without disabling cfgr_clk, leaking the
already-enabled clock.
Switch both clocks to the clk bulk helpers so prepare/enable
failures roll back automatically, and update probe/remove/
suspend/resume accordingly.
> diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> index eebed2474210d..cf743450f629e 100644
> --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
> +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
[ ... ]
> @@ -1524,13 +1519,11 @@ static int dw_probe(struct platform_device *pdev)
>
> chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2);
>
> - chip->core_clk = devm_clk_get(chip->dev, "core-clk");
> - if (IS_ERR(chip->core_clk))
> - return PTR_ERR(chip->core_clk);
> -
> - chip->cfgr_clk = devm_clk_get(chip->dev, "cfgr-clk");
> - if (IS_ERR(chip->cfgr_clk))
> - return PTR_ERR(chip->cfgr_clk);
> + chip->clks[0].id = "cfgr-clk";
> + chip->clks[1].id = "core-clk";
> + ret = devm_clk_bulk_get(chip->dev, DW_AXI_DMA_MAX_CLKS, chip->clks);
> + if (ret)
> + return ret;
[Severity: High]
This isn't a bug introduced by this patch, but are the virt-dma tasklets
properly cleaned up if probe fails?
Later in dw_probe(), vchan_init() initializes a tasklet for each channel:
vchan_init(&chan->vc, &dw->dma);
If a subsequent step like dmaenginem_async_device_register() fails, the driver
returns without calling tasklet_kill().
Since devm_request_irq() was called earlier with IRQF_SHARED, a shared
interrupt could fire and schedule the tasklet before the error path completes,
leading to a use-after-free when devres frees the channel memory.
[Severity: High]
This is also a pre-existing issue, but does requesting the shared IRQ early
risk a NULL pointer dereference or bus fault?
In dw_probe(), devm_request_irq() is called with IRQF_SHARED:
ret = axi_req_irqs(pdev, chip);
This happens before the hardware clocks are enabled and before chan->chan_regs
is populated later in dw_probe():
chan->chan_regs = chip->regs + COMMON_REG_LEN + i * CHAN_REG_LEN;
If a shared interrupt fires immediately, dw_axi_dma_interrupt() executes and
calls axi_dma_irq_disable(), which reads DMAC_CFG while clocks are off, causing
a bus fault. It also reads chan->chan_regs + CH_INTSTATUS, which is NULL,
resulting in a crash.
[ ... ]
> @@ -1642,8 +1635,7 @@ static void dw_remove(struct platform_device *pdev)
> u32 i;
>
> /* Enable clk before accessing to registers */
> - clk_prepare_enable(chip->cfgr_clk);
> - clk_prepare_enable(chip->core_clk);
> + clk_bulk_prepare_enable(DW_AXI_DMA_MAX_CLKS, chip->clks);
> axi_dma_irq_disable(chip);
[Severity: High]
Does this unchecked bulk prepare/enable create a regression where a partial
clock failure leads to a bus fault?
During driver removal, if cfgr-clk enables successfully but core-clk fails, the
clk_bulk API automatically rolls back and disables cfgr-clk. Because the return
value isn't checked, the code unconditionally proceeds to call
axi_dma_irq_disable().
axi_dma_irq_disable() reads the DMAC_CFG APB register while the APB clock is
disabled, causing a bus fault.
Before this patch, the individual clk_prepare_enable() calls did not roll back
cfgr-clk on core-clk failure, allowing the APB access to succeed safely.
> for (i = 0; i < dw->hdata->nr_channels; i++) {
> axi_chan_disable(&chip->dw->chan[i]);
[Severity: High]
This is a pre-existing issue, but does this loop unsafely modify hardware
state without holding chan->vc.lock?
In dw_remove(), axi_chan_disable() and axi_chan_irq_disable() are called
without acquiring the lock. Concurrently, a virt-dma tasklet or client can call
axi_chan_start_first_queued(), which acquires the lock and writes to DMAC_CHEN
to enable the channel.
This race could allow a channel to be re-enabled after dw_remove() attempted to
disable it. When dw_remove() subsequently suspends the clocks, it could crash
the bus if the channel is actively transferring.
> axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL);
> }
> axi_dma_disable(chip);
>
> pm_runtime_disable(chip->dev);
> axi_dma_suspend(chip);
>
> for (i = 0; i < DMAC_MAX_CHANNELS; i++)
> if (chip->irq[i] > 0)
> devm_free_irq(chip->dev, chip->irq[i], chip);
[Severity: High]
This isn't a bug introduced by this patch, but does this driver leave
suspended hardware exposed to concurrent DMA clients during unbind?
Because dw_probe() uses dmaenginem_async_device_register() (devm), the DMA
engine is only unregistered asynchronously by devres after dw_remove() fully
returns.
During dw_remove(), the hardware clocks are manually turned off via
axi_dma_suspend(). Since the DMA engine remains visible to clients throughout
this process, a concurrent DMA request invoking dma_chan_issue_pending() will
attempt to write to hardware registers with disabled clocks, leading to a bus
fault.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260902013016.3381788-1-dayou5941@163.com?part=1
next prev parent reply other threads:[~2026-09-02 1:45 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 1:30 [PATCH v3] dmaengine: dw-axi-dmac: convert to clk bulk APIs Li Youhong
2026-09-02 1:45 ` sashiko-bot [this message]
2026-09-02 10:57 ` kernel test robot
2026-09-02 19:48 ` kernel test robot
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=20260902014504.065151F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=dayou5941@163.com \
--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.