Skip to content

Commit

Permalink
drm: vc4_dsi: Fix DMA channel and memory leak in vc4 (#3012)
Browse files Browse the repository at this point in the history
Signed-off-by: Chris G Miller <chris@creative-electronics.net>
  • Loading branch information
Chris Miller authored and popcornmix committed Jun 26, 2020
1 parent eea7d23 commit f127760
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions drivers/gpu/drm/vc4/vc4_dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
/* 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) {
Expand All @@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
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.
Expand All @@ -1532,31 +1536,31 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
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");
if (IS_ERR(dsi->escape_clock)) {
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");
if (IS_ERR(dsi->pll_phy_clock)) {
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");
if (IS_ERR(dsi->pixel_clock)) {
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,
Expand All @@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
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;
Expand All @@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
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
Expand All @@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
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,
Expand All @@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master,

vc4_dsi_encoder_destroy(dsi->encoder);

dma_release_channel(dsi->reg_dma_chan);

if (dsi->port == 1)
vc4->dsi1 = NULL;
}
Expand Down

0 comments on commit f127760

Please sign in to comment.