Re: [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH
[email protected] Mon, 27 Jul 2026 20:56:54 +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] This problem wasn't introduced by this patch, but an initialization race condition exists: `request_irq()` is called before hardware clocks are enabled and DMA channels are initialized, which can cause a kernel panic or infinite loop. - [High] This problem wasn't introduced by this patch, but there is a resource leak and Use-After-Free due to a bypassed cleanup loop in `at_xdmac_remove()`. - [High] This problem wasn't introduced by this patch, but the teardown order is flawed: Hardware clocks and PM runtime are disabled before freeing the IRQ and stopping BH workers. - [High] This problem wasn't introduced by this patch, but out-of-bounds memory accesses and list corruption occur due to an unchecked `list_first_entry()` in the BH worker. - [High] This problem wasn't introduced by this patch, but there is a sleeping in atomic bug: The error handler calls `pm_runtime_resume_and_get()` while holding an IRQ-disabled spinlock. -- --- Patch [4]: [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH --- commit 91d37fd9a6c41425b793e9ed1792794d52b35014 Author: Allen Pais <[email protected]> dmaengine: at_xdmac: move irq bottom half to dma_chan BH Replace the per-channel tasklet with the shared dma_chan BH helper. The handler continues to run in softirq context while dmaengine owns the common scheduling and teardown mechanism. > diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c > index 901971e8bae69..aa918043e37ec 100644 > --- a/drivers/dma/at_xdmac.c > +++ b/drivers/dma/at_xdmac.c [ ... ] > @@ -1759,9 +1758,9 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan) > /* Then continue with usual descriptor management */ > } > > -static void at_xdmac_tasklet(struct tasklet_struct *t) > +static void at_xdmac_tasklet(struct dma_chan *chan) > { > - struct at_xdmac_chan *atchan = from_tasklet(atchan, t, tasklet); > + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); > struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device); > struct at_xdmac_desc *desc; [Severity: High] This is a pre-existing issue, but does this function lack a list empty check? Later in at_xdmac_tasklet(), the code does: desc = list_first_entry(&atchan->xfers_list, struct at_xdmac_desc, xfer_node); if (!desc->active_xfer) { ... } If at_xdmac_device_terminate_all() runs concurrently and empties xfers_list, resuming the BH worker might resolve an invalid pointer for the empty list, read out-of-bounds for desc->active_xfer, and corrupt the list. [Severity: High] This is also a pre-existing issue, but can this path sleep while atomic? In at_xdmac_tasklet(), an IRQ-disabled spinlock is acquired: spin_lock_irq(&atchan->lock); ... if (atchan->irq_status & error_mask) at_xdmac_handle_error(atchan); Inside at_xdmac_handle_error(), it calls pm_runtime_resume_and_get(), which can sleep since the device isn't marked as pm_runtime_irq_safe(). Could this lead to a scheduling while atomic bug if the device's runtime status is not RPM_ACTIVE? [ ... ] > @@ -2317,7 +2316,7 @@ static int at_xdmac_probe(struct platform_device *pdev) > return PTR_ERR(atxdmac->clk); > } > > - /* Do not use dev res to prevent races with tasklet */ > + /* Do not use devm resources to prevent races with the BH worker */ > ret = request_irq(atxdmac->irq, at_xdmac_interrupt, 0, "at_xdmac", atxdmac); [Severity: High] This isn't a bug introduced by this patch, but an initialization race condition appears to exist here. Is it safe to call request_irq() before the hardware clocks are enabled via clk_prepare_enable() and before dma_async_device_register() initializes the channel count? If an early or pending interrupt fires immediately after request_irq(), the handler at_xdmac_interrupt() will execute while the controller's clock is gated, which could trigger a bus fault. Even if clocks were enabled, atxdmac->dma.chancnt is still 0 at this point. The handler would skip the channel check loop, fail to clear the interrupt, and spin infinitely in its do-while(pending) loop. [ ... ] > @@ -2458,7 +2457,7 @@ static void at_xdmac_remove(struct platform_device *pdev) > for (i = 0; i < atxdmac->dma.chancnt; i++) { > struct at_xdmac_chan *atchan = &atxdmac->chan[i]; > > - tasklet_kill(&atchan->tasklet); > + dma_chan_kill_bh(&atchan->chan); > at_xdmac_free_chan_resources(&atchan->chan); > } > } [Severity: High] This is a pre-existing issue, but does the teardown order in at_xdmac_remove() and the probe error path risk a bus fault? In at_xdmac_remove(), clk_disable_unprepare() and pm_runtime_disable() are called before free_irq(). If a pending interrupt fires before free_irq() completes, the interrupt handler will attempt to read from the clock-gated device registers, which could trigger a synchronous external abort. [Severity: High] This is another pre-existing issue, but will this cleanup loop ever execute? Earlier in at_xdmac_remove(), dma_async_device_unregister() is called, which iterates over all registered channels and decrements device->chancnt to 0. When this loop attempts to use atxdmac->dma.chancnt as its limit, it is completely bypassed, meaning dma_chan_kill_bh() and at_xdmac_free_chan_resources() are never called, potentially causing a resource leak and use-after-free for pending BH workers. -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=4