mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
bcaabe6d05
Similar version was upstreamed: bcm27xx/patches-5.4/950-0392-tty-amba-pl011-Add-un-throttle-support.patch Manually adapted: ipq806x/patches-5.4/0063-2-tsens-support-configurable-interrupts.patch layerscape/patches-5.4/301-arch-0008-arm-add-new-non-shareable-ioremap.patch Compile-tested: x86/64 Run-tested: x86/64 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
136 lines
4.0 KiB
Diff
136 lines
4.0 KiB
Diff
From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001
|
|
From: Chris Miller <chris@mesl2.co.uk>
|
|
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 <chris@creative-electronics.net>
|
|
---
|
|
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->port == 1) {
|
|
- dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
|
|
+ dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
|
|
&dsi->reg_dma_paddr,
|
|
GFP_KERNEL);
|
|
if (!dsi->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->escape_clock = devm_clk_get(dev, "escape");
|
|
@@ -1538,7 +1542,7 @@ static int vc4_dsi_bind(struct device *d
|
|
ret = PTR_ERR(dsi->escape_clock);
|
|
if (ret != -EPROBE_DEFER)
|
|
dev_err(dev, "Failed to get escape clock: %d\n", ret);
|
|
- return ret;
|
|
+ goto rel_dma_exit;
|
|
}
|
|
|
|
dsi->pll_phy_clock = devm_clk_get(dev, "phy");
|
|
@@ -1546,7 +1550,7 @@ static int vc4_dsi_bind(struct device *d
|
|
ret = PTR_ERR(dsi->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->pixel_clock = devm_clk_get(dev, "pixel");
|
|
@@ -1554,7 +1558,7 @@ static int vc4_dsi_bind(struct device *d
|
|
ret = PTR_ERR(dsi->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->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->bridge = devm_drm_panel_bridge_add(dev, panel,
|
|
DRM_MODE_CONNECTOR_DSI);
|
|
- if (IS_ERR(dsi->bridge))
|
|
- return PTR_ERR(dsi->bridge);
|
|
+ if (IS_ERR(dsi->bridge)){
|
|
+ ret = PTR_ERR(dsi->bridge);
|
|
+ goto rel_dma_exit;
|
|
+ }
|
|
}
|
|
|
|
/* The esc clock rate is supposed to always be 100Mhz. */
|
|
ret = clk_set_rate(dsi->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->port == 1)
|
|
vc4->dsi1 = dsi;
|
|
@@ -1600,7 +1606,7 @@ static int vc4_dsi_bind(struct device *d
|
|
ret = drm_bridge_attach(dsi->encoder, dsi->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->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->encoder);
|
|
|
|
+ dma_release_channel(dsi->reg_dma_chan);
|
|
+
|
|
if (dsi->port == 1)
|
|
vc4->dsi1 = NULL;
|
|
}
|