Re: [PATCH v2 60/64] dmaengine: bam-dma: use dma_chan_kill_bh

[email protected] Mon, 27 Jul 2026 21:19:46 +0000
Newsgroups org.kernel.vger.dmaengine
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:

Pre-existing issues:
- [High] In the probe error path, the BAM interrupts are not masked and the IRQ is not freed before disabling clocks and cleaning up state.
- [High] Hardware registers are accessed while the peripheral clock is disabled in `bam_dma_remove`, leading to bus faults (Data Abort).
- [High] Failing to drop the PM runtime usage counter on error paths prevents the device from ever entering runtime suspend.
- [High] The driver fails to implement the `device_synchronize` DMA engine callback, rendering `dmaengine_synchronize()` a no-op.
- [Medium] Calling `clk_disable_unprepare` in `bam_dma_remove` underflows the clock enable count.
--

--- Patch [60]: [PATCH v2 60/64] dmaengine: bam-dma: use dma_chan_kill_bh ---
commit 66f1d34a1a1de31180ac528ea6a897680d6ee0d9
Author: Allen Pais <[email protected]>

dmaengine: bam-dma: use dma_chan_kill_bh

virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.

> diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
> index 1bb26af0405f3..74bc2fe445b32 100644
> --- a/drivers/dma/qcom/bam_dma.c
> +++ b/drivers/dma/qcom/bam_dma.c
> @@ -1387,7 +1387,7 @@ static int bam_dma_probe(struct platform_device *pdev)
>  	dma_async_device_unregister(&bdev->common);
>  err_bam_channel_exit:
>  	for (i = 0; i < bdev->num_channels; i++)
> -		tasklet_kill(&bdev->channels[i].vc.task);
> +		dma_chan_kill_bh(&bdev->channels[i].vc.chan);

[Severity: High]
This isn't a bug introduced by this patch, but the driver fails to implement
the device_synchronize DMA engine callback here in bam_dma_probe().

Because bdev->common.device_synchronize is never assigned,
dmaengine_synchronize() returns immediately. This could allow DMA clients
to free memory while the completion bottom-half work is still executing
concurrently. 

Should the driver provide a wrapper that calls vchan_synchronize()?

>  err_tasklet_kill:
>  	tasklet_kill(&bdev->task);
>  err_disable_clk:
>  	clk_disable_unprepare(bdev->bamclk);

[Severity: High]
This is a pre-existing issue, but does this error path leave the BAM
interrupts active before disabling the clock?

Because devm_request_irq() is used, the interrupt is not freed until after
probe() returns. If an interrupt fires during this window, bam_dma_irq()
will access BAM hardware registers while the clock is disabled via
clk_disable_unprepare(), which can trigger a synchronous external abort on
QCOM platforms.

Could we mask interrupts and free the IRQ explicitly before disabling clocks?

> @@ -1413,7 +1413,7 @@ static void bam_dma_remove(struct platform_device *pdev)
>  
>  	for (i = 0; i < bdev->num_channels; i++) {
>  		bam_dma_terminate_all(&bdev->channels[i].vc.chan);
> -		tasklet_kill(&bdev->channels[i].vc.task);
> +		dma_chan_kill_bh(&bdev->channels[i].vc.chan);

[Severity: High]
This isn't a bug introduced by this patch, but are hardware registers
accessed after the clock is disabled?

Looking at bam_dma_remove(), pm_runtime_force_suspend() is called early,
which disables the clock. Immediately after, writel_relaxed() is called to
mask interrupts, and bam_dma_terminate_all() accesses hardware. Accessing
unclocked peripheral registers on QCOM platforms triggers a fatal
synchronous external abort.

Should the hardware shutdown logic occur before forcing PM suspend?

[Severity: Medium]
This is a pre-existing issue, but is there a double-disable of the clock in
bam_dma_remove()?

Since pm_runtime_force_suspend() has already suspended the device and
disabled the clock, the later call to clk_disable_unprepare() at the end
of this function will disable it again, causing the clock enable count to
drop below zero.

[Severity: High]
This isn't a bug introduced by this patch, but does the
pm_runtime_get_sync() failure path in bam_dma_irq() leak the PM usage
counter?

If pm_runtime_get_sync() returns a negative error:

drivers/dma/qcom/bam_dma.c:bam_dma_irq() {
	...
	ret = pm_runtime_get_sync(bdev->dev);
	if (ret < 0)
		return IRQ_NONE;
	...
}

Returning IRQ_NONE immediately without calling pm_runtime_put_noidle()
permanently leaks the PM reference count.

Additionally, returning IRQ_NONE without clearing the hardware interrupt
status leaves the IRQ asserted, potentially causing an IRQ storm that leads
to a CPU soft-lockup.

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