<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001
From: Chris Miller &lt;chris@mesl2.co.uk&gt;
Date: Wed, 26 Jun 2019 10:40:30 +0100
Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
 (#3012)

Signed-off-by: Chris G Miller &lt;chris@creative-electronics.net&gt;
---
 drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1483,9 +1483,11 @@ static int vc4_dsi_bind(struct device *d
 	/* DSI1 has a broken AXI slave that doesn't respond to writes
 	 * from the ARM.  It does handle writes from the DMA engine,
 	 * so set up a channel for talking to it.
+	 * Where possible managed resource providers are used, but the DMA channel
+	 * must - if acquired - be explicitly released prior to taking an error exit path.
 	 */
 	if (dsi-&gt;port == 1) {
-		dsi-&gt;reg_dma_mem = dma_alloc_coherent(dev, 4,
+		dsi-&gt;reg_dma_mem = dmam_alloc_coherent(dev, 4,
 						      &amp;dsi-&gt;reg_dma_paddr,
 						      GFP_KERNEL);
 		if (!dsi-&gt;reg_dma_mem) {
@@ -1504,6 +1506,8 @@ static int vc4_dsi_bind(struct device *d
 			return ret;
 		}
 
+		/* From here on, any error exits must release the dma channel */
+
 		/* Get the physical address of the device's registers.  The
 		 * struct resource for the regs gives us the bus address
 		 * instead.
@@ -1530,7 +1534,7 @@ static int vc4_dsi_bind(struct device *d
 	if (ret) {
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get interrupt: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	dsi-&gt;escape_clock = devm_clk_get(dev, "escape");
@@ -1538,7 +1542,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi-&gt;escape_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get escape clock: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	dsi-&gt;pll_phy_clock = devm_clk_get(dev, "phy");
@@ -1546,7 +1550,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi-&gt;pll_phy_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get phy clock: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	dsi-&gt;pixel_clock = devm_clk_get(dev, "pixel");
@@ -1554,7 +1558,7 @@ static int vc4_dsi_bind(struct device *d
 		ret = PTR_ERR(dsi-&gt;pixel_clock);
 		if (ret != -EPROBE_DEFER)
 			dev_err(dev, "Failed to get pixel clock: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	ret = drm_of_find_panel_or_bridge(dev-&gt;of_node, 0, 0,
@@ -1569,26 +1573,28 @@ static int vc4_dsi_bind(struct device *d
 		if (ret == -ENODEV)
 			return 0;
 
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	if (panel) {
 		dsi-&gt;bridge = devm_drm_panel_bridge_add(dev, panel,
 							DRM_MODE_CONNECTOR_DSI);
-		if (IS_ERR(dsi-&gt;bridge))
-			return PTR_ERR(dsi-&gt;bridge);
+		if (IS_ERR(dsi-&gt;bridge)){
+			ret = PTR_ERR(dsi-&gt;bridge);
+			goto rel_dma_exit;
+		}
 	}
 
 	/* The esc clock rate is supposed to always be 100Mhz. */
 	ret = clk_set_rate(dsi-&gt;escape_clock, 100 * 1000000);
 	if (ret) {
 		dev_err(dev, "Failed to set esc clock: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 
 	ret = vc4_dsi_init_phy_clocks(dsi);
 	if (ret)
-		return ret;
+		goto rel_dma_exit;
 
 	if (dsi-&gt;port == 1)
 		vc4-&gt;dsi1 = dsi;
@@ -1600,7 +1606,7 @@ static int vc4_dsi_bind(struct device *d
 	ret = drm_bridge_attach(dsi-&gt;encoder, dsi-&gt;bridge, NULL);
 	if (ret) {
 		dev_err(dev, "bridge attach failed: %d\n", ret);
-		return ret;
+		goto rel_dma_exit;
 	}
 	/* Disable the atomic helper calls into the bridge.  We
 	 * manually call the bridge pre_enable / enable / etc. calls
@@ -1617,6 +1623,11 @@ static int vc4_dsi_bind(struct device *d
 	pm_runtime_enable(dev);
 
 	return 0;
+
+rel_dma_exit:
+	dma_release_channel(dsi-&gt;reg_dma_chan);
+
+	return ret;
 }
 
 static void vc4_dsi_unbind(struct device *dev, struct device *master,
@@ -1631,6 +1642,8 @@ static void vc4_dsi_unbind(struct device
 
 	vc4_dsi_encoder_destroy(dsi-&gt;encoder);
 
+	dma_release_channel(dsi-&gt;reg_dma_chan);
+
 	if (dsi-&gt;port == 1)
 		vc4-&gt;dsi1 = NULL;
 }
</pre></body></html>