mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes
@ 2026-06-01  0:35 Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 1/5] dmaengine: ti: omap-dma: fix missing return in probe error path Rosen Penev
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

This series fixes four bugs in the TI OMAP DMA driver:

 - Patch 1: add missing return statement in the probe error path
 - Patch 2: fix a notifier leak in remove
 - Patch 3: fix dma_pool_destroy being called before omap_dma_free
 - Patch 4: fix interrupt handling in the remove path
 - Patch 5: use dmam for dmaengine registration and remove devm_free_irq

v2: fix sashiko comments and add extra patch

Rosen Penev (5):
  dmaengine: ti: omap-dma: fix missing return in probe error path
  dmaengine: ti: omap-dma: fix notifier leak in remove
  dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in
    error paths
  dmaengine: ti: omap-dma: fix interrupt handling in remove
  dmaengine: ti: omap-dma: use devm for dmaengine registration

 drivers/dma/ti/omap-dma.c | 50 ++++++++++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 17 deletions(-)

--
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/5] dmaengine: ti: omap-dma: fix missing return in probe error path
  2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
@ 2026-06-01  0:35 ` Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 2/5] dmaengine: ti: omap-dma: fix notifier leak in remove Rosen Penev
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

If of_dma_controller_register() fails, the error path omits the return
statement, causing probe to continue (and eventually succeed) despite
the DMA controller not being registered. Add the missing return rc;.

Fixes: 2e1136acf8a8 ("dmaengine: omap-dma: fix dma_pool resource leak in error paths")
Cc: stable@vger.kernel.org
Assisted-by: Opencode:BigPickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/dma/ti/omap-dma.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 55ece7fd0d99..0f6dd6b0a301 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1828,6 +1828,7 @@ static int omap_dma_probe(struct platform_device *pdev)
 			if (od->ll123_supported)
 				dma_pool_destroy(od->desc_pool);
 			omap_dma_free(od);
+			return rc;
 		}
 	}
 
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 2/5] dmaengine: ti: omap-dma: fix notifier leak in remove
  2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 1/5] dmaengine: ti: omap-dma: fix missing return in probe error path Rosen Penev
@ 2026-06-01  0:35 ` Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 3/5] dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in error paths Rosen Penev
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

The notifier may be registered for needs_busy_check (omap2420) rather than
may_lose_context (omap3). The remove path only checks may_lose_context,
leaving the notifier registered during driver removal. Check both flags.

Fixes: 2e1136acf8a8 ("dmaengine: omap-dma: fix dma_pool resource leak in error paths")
Cc: stable@vger.kernel.org
Assisted-by: Opencode:BigPickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/dma/ti/omap-dma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 0f6dd6b0a301..839e04f53fc2 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1853,7 +1853,7 @@ static void omap_dma_remove(struct platform_device *pdev)
 	struct omap_dmadev *od = platform_get_drvdata(pdev);
 	int irq;
 
-	if (od->cfg->may_lose_context)
+	if (od->cfg->needs_busy_check || od->cfg->may_lose_context)
 		cpu_pm_unregister_notifier(&od->nb);
 
 	if (pdev->dev.of_node)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 3/5] dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in error paths
  2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 1/5] dmaengine: ti: omap-dma: fix missing return in probe error path Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 2/5] dmaengine: ti: omap-dma: fix notifier leak in remove Rosen Penev
@ 2026-06-01  0:35 ` Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 4/5] dmaengine: ti: omap-dma: fix interrupt handling in remove Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 5/5] dmaengine: ti: omap-dma: use devm for dmaengine registration Rosen Penev
  4 siblings, 0 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

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@vger.kernel.org
Assisted-by: Opencode:BigPickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 4/5] dmaengine: ti: omap-dma: fix interrupt handling in remove
  2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
                   ` (2 preceding siblings ...)
  2026-06-01  0:35 ` [PATCH v2 3/5] dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in error paths Rosen Penev
@ 2026-06-01  0:35 ` Rosen Penev
  2026-06-01  0:35 ` [PATCH v2 5/5] dmaengine: ti: omap-dma: use devm for dmaengine registration Rosen Penev
  4 siblings, 0 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

The remove path had several pre-existing bugs:

1. Interrupts are enabled via IRQENABLE_L1 in probe and alloc_chan_resources,
   but the remove path writes to IRQENABLE_L0, which has no effect on the L1
   interrupt line. The DMA engine can continue asserting its IRQ during
   removal. Write to IRQENABLE_L1 instead.

2. devm_free_irq() was called before disabling hardware interrupts. With
   IRQF_SHARED, the hardware may still assert the IRQ line after the handler
   is freed, causing unhandled interrupts that can lead to the kernel
   permanently disabling the shared IRQ line. Disable interrupts first.

3. platform_get_irq() return value was not checked before devm_free_irq().
   If it returns an error code (<= 0), passing it to devm_free_irq() is
   incorrect. Add a guard.

4. Clearing od->irq_enable_mask and writing to IRQENABLE_L1 raced with the
   interrupt handler, which reads irq_enable_mask under the spinlock.
   Hold irq_lock around the disable.

5. The posted write to IRQENABLE_L1 used _relaxed accessors with no
   readback to drain the write buffer. Add a readback flush before
   devm_free_irq() to ensure the hardware has actually disabled the
   interrupt line.

6. omap_dma_free() unconditionally freed all channel memory without
   checking whether clients still held references. A sysfs unbind of the
   DMA controller does not synchronously unbind consumers, so active
   clients could access freed channel memory. Skip freeing channels
   that still have active clients.

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

diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index dde270646bb9..8c32b7ab50f6 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1516,13 +1516,21 @@ static int omap_dma_chan_init(struct omap_dmadev *od)
 
 static void omap_dma_free(struct omap_dmadev *od)
 {
+	struct omap_chan *c;
+
 	while (!list_empty(&od->ddev.channels)) {
-		struct omap_chan *c = list_first_entry(&od->ddev.channels,
-			struct omap_chan, vc.chan.device_node);
+		c = list_first_entry(&od->ddev.channels,
+				     struct omap_chan, vc.chan.device_node);
 
 		list_del(&c->vc.chan.device_node);
 		tasklet_kill(&c->vc.task);
 		vchan_free_chan_resources(&c->vc);
+		if (c->vc.chan.client_count) {
+			dev_warn(od->ddev.dev,
+				 "chan%d freed with %u client(s)\n",
+				 c->dma_ch, c->vc.chan.client_count);
+			continue;
+		}
 		kfree(c);
 	}
 }
@@ -1870,16 +1878,20 @@ static void omap_dma_remove(struct platform_device *pdev)
 	if (pdev->dev.of_node)
 		of_dma_controller_free(pdev->dev.of_node);
 
-	irq = platform_get_irq(pdev, 1);
-	devm_free_irq(&pdev->dev, irq, od);
-
 	dma_async_device_unregister(&od->ddev);
 
 	if (!omap_dma_legacy(od)) {
-		/* Disable all interrupts */
-		omap_dma_glbl_write(od, IRQENABLE_L0, 0);
+		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);
 	}
 
+	irq = platform_get_irq(pdev, 1);
+	if (irq > 0)
+		devm_free_irq(&pdev->dev, irq, od);
+
 	omap_dma_free(od);
 
 	if (od->ll123_supported)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 5/5] dmaengine: ti: omap-dma: use devm for dmaengine registration
  2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
                   ` (3 preceding siblings ...)
  2026-06-01  0:35 ` [PATCH v2 4/5] dmaengine: ti: omap-dma: fix interrupt handling in remove Rosen Penev
@ 2026-06-01  0:35 ` Rosen Penev
  4 siblings, 0 replies; 6+ messages in thread
From: Rosen Penev @ 2026-06-01  0:35 UTC (permalink / raw)
  To: dmaengine; +Cc: Peter Ujfalusi, Vinod Koul, Frank Li, Haotian Zhang, open list

Use dmaenginem_async_device_register() instead of
dma_async_device_register() so that unregistration is handled
automatically by devres on probe failure or driver detach. This
lets us drop:
- The explicit dma_async_device_unregister() in the
  of_dma_controller_register error path (devres unwind runs it
  after omap_dma_free() has emptied the channels list, making the
  iteration a safe no-op).
- The explicit dma_async_device_unregister() and the redundant
  devm_free_irq() call in the remove path (devres handles both in
  the correct order after the remove callback returns).

Assisted-by: Opencode:Big-Pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 drivers/dma/ti/omap-dma.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 8c32b7ab50f6..4bf34569d82b 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1813,7 +1813,7 @@ static int omap_dma_probe(struct platform_device *pdev)
 		}
 	}
 
-	rc = dma_async_device_register(&od->ddev);
+	rc = dmaenginem_async_device_register(&od->ddev);
 	if (rc) {
 		pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n",
 			rc);
@@ -1838,7 +1838,6 @@ static int omap_dma_probe(struct platform_device *pdev)
 				of_dma_simple_xlate, &omap_dma_info);
 		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);
@@ -1870,7 +1869,6 @@ static int omap_dma_probe(struct platform_device *pdev)
 static void omap_dma_remove(struct platform_device *pdev)
 {
 	struct omap_dmadev *od = platform_get_drvdata(pdev);
-	int irq;
 
 	if (od->cfg->needs_busy_check || od->cfg->may_lose_context)
 		cpu_pm_unregister_notifier(&od->nb);
@@ -1878,8 +1876,6 @@ static void omap_dma_remove(struct platform_device *pdev)
 	if (pdev->dev.of_node)
 		of_dma_controller_free(pdev->dev.of_node);
 
-	dma_async_device_unregister(&od->ddev);
-
 	if (!omap_dma_legacy(od)) {
 		spin_lock_irq(&od->irq_lock);
 		od->irq_enable_mask = 0;
@@ -1888,10 +1884,6 @@ static void omap_dma_remove(struct platform_device *pdev)
 		omap_dma_glbl_read(od, IRQENABLE_L1);
 	}
 
-	irq = platform_get_irq(pdev, 1);
-	if (irq > 0)
-		devm_free_irq(&pdev->dev, irq, od);
-
 	omap_dma_free(od);
 
 	if (od->ll123_supported)
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-01  0:36 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-01  0:35 [PATCH v2 0/5] dmaengine: ti: omap-dma: various bug fixes Rosen Penev
2026-06-01  0:35 ` [PATCH v2 1/5] dmaengine: ti: omap-dma: fix missing return in probe error path Rosen Penev
2026-06-01  0:35 ` [PATCH v2 2/5] dmaengine: ti: omap-dma: fix notifier leak in remove Rosen Penev
2026-06-01  0:35 ` [PATCH v2 3/5] dmaengine: ti: omap-dma: fix dma_pool_destroy before omap_dma_free in error paths Rosen Penev
2026-06-01  0:35 ` [PATCH v2 4/5] dmaengine: ti: omap-dma: fix interrupt handling in remove Rosen Penev
2026-06-01  0:35 ` [PATCH v2 5/5] dmaengine: ti: omap-dma: use devm for dmaengine registration Rosen Penev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome