[PATCH v2 3/5] dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in error paths

From: Rosen Penev

Date: Sun May 31 2026 - 20:39:29 EST


The probe error paths and remove path called omap_dma_free() after
dma_pool_destroy(), leaving the desc_pool dangling while freeing
channel descriptors that may reference it. Reorder so omap_dma_free()
comes first.

While here, fix two additional pre-existing issues:

- The probe error paths that run after the IRQ handler is registered
did not disable hardware interrupts before freeing channels. If an
IRQ fires concurrently, the handler could access freed channel
memory via lch_map[]. Disable IRQENABLE_L1 and clear
irq_enable_mask under the spinlock, then readback the register to
flush the posted write, before calling omap_dma_free().

- omap_dma_free() did not drain the virt-dma descriptor lists
(desc_allocated, desc_submitted, desc_issued, desc_completed) before
kfree() of the channel. This leaked pending descriptors when the
error or remove path tore down channels without going through
omap_dma_free_chan_resources(). Call vchan_free_chan_resources()
before freeing the channel structure.

Fixes: 2e1136acf8a8 ("dmaengine: omap-dma: fix dma_pool resource leak in error paths")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Opencode:BigPickle
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
drivers/dma/ti/omap-dma.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 839e04f53fc2..dde270646bb9 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1522,6 +1522,7 @@ static void omap_dma_free(struct omap_dmadev *od)

list_del(&c->vc.chan.device_node);
tasklet_kill(&c->vc.task);
+ vchan_free_chan_resources(&c->vc);
kfree(c);
}
}
@@ -1808,9 +1809,14 @@ static int omap_dma_probe(struct platform_device *pdev)
if (rc) {
pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n",
rc);
+ spin_lock_irq(&od->irq_lock);
+ od->irq_enable_mask = 0;
+ omap_dma_glbl_write(od, IRQENABLE_L1, 0);
+ spin_unlock_irq(&od->irq_lock);
+ omap_dma_glbl_read(od, IRQENABLE_L1);
+ omap_dma_free(od);
if (od->ll123_supported)
dma_pool_destroy(od->desc_pool);
- omap_dma_free(od);
return rc;
}

@@ -1825,9 +1831,14 @@ static int omap_dma_probe(struct platform_device *pdev)
if (rc) {
pr_warn("OMAP-DMA: failed to register DMA controller\n");
dma_async_device_unregister(&od->ddev);
+ spin_lock_irq(&od->irq_lock);
+ od->irq_enable_mask = 0;
+ omap_dma_glbl_write(od, IRQENABLE_L1, 0);
+ spin_unlock_irq(&od->irq_lock);
+ omap_dma_glbl_read(od, IRQENABLE_L1);
+ omap_dma_free(od);
if (od->ll123_supported)
dma_pool_destroy(od->desc_pool);
- omap_dma_free(od);
return rc;
}
}
@@ -1869,10 +1880,10 @@ static void omap_dma_remove(struct platform_device *pdev)
omap_dma_glbl_write(od, IRQENABLE_L0, 0);
}

+ omap_dma_free(od);
+
if (od->ll123_supported)
dma_pool_destroy(od->desc_pool);
-
- omap_dma_free(od);
}

static const struct omap_dma_config omap2420_data = {
--
2.54.0