drm/vc4: dsi: Release workaround buffer and DMA
authorDave Stevenson <dave.stevenson@raspberrypi.com>
Mon, 13 Jun 2022 14:47:38 +0000 (16:47 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:23:25 +0000 (14:23 +0200)
[ Upstream commit 89c4bbe2a01ea401c2b0fabc104720809084b77f ]

On Pi0-3 the driver allocates a buffer and requests a DMA channel
because the ARM can't write to DSI1's registers directly.

However, we never release that buffer or channel. Let's add a
device-managed action to release each.

Fixes: 4078f5757144 ("drm/vc4: Add DSI driver")
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Link: https://lore.kernel.org/r/20220613144800.326124-12-maxime@cerno.tech
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/vc4/vc4_dsi.c

index 98308a1..e82ee94 100644 (file)
@@ -1487,13 +1487,29 @@ vc4_dsi_init_phy_clocks(struct vc4_dsi *dsi)
                                      dsi->clk_onecell);
 }
 
+static void vc4_dsi_dma_mem_release(void *ptr)
+{
+       struct vc4_dsi *dsi = ptr;
+       struct device *dev = &dsi->pdev->dev;
+
+       dma_free_coherent(dev, 4, dsi->reg_dma_mem, dsi->reg_dma_paddr);
+       dsi->reg_dma_mem = NULL;
+}
+
+static void vc4_dsi_dma_chan_release(void *ptr)
+{
+       struct vc4_dsi *dsi = ptr;
+
+       dma_release_channel(dsi->reg_dma_chan);
+       dsi->reg_dma_chan = NULL;
+}
+
 static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dsi *dsi = dev_get_drvdata(dev);
        struct vc4_dsi_encoder *vc4_dsi_encoder;
-       dma_cap_mask_t dma_mask;
        int ret;
 
        dsi->variant = of_device_get_match_data(dev);
@@ -1527,6 +1543,8 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
         * so set up a channel for talking to it.
         */
        if (dsi->variant->broken_axi_workaround) {
+               dma_cap_mask_t dma_mask;
+
                dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
                                                      &dsi->reg_dma_paddr,
                                                      GFP_KERNEL);
@@ -1535,8 +1553,13 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
                        return -ENOMEM;
                }
 
+               ret = devm_add_action_or_reset(dev, vc4_dsi_dma_mem_release, dsi);
+               if (ret)
+                       return ret;
+
                dma_cap_zero(dma_mask);
                dma_cap_set(DMA_MEMCPY, dma_mask);
+
                dsi->reg_dma_chan = dma_request_chan_by_mask(&dma_mask);
                if (IS_ERR(dsi->reg_dma_chan)) {
                        ret = PTR_ERR(dsi->reg_dma_chan);
@@ -1546,6 +1569,10 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
                        return ret;
                }
 
+               ret = devm_add_action_or_reset(dev, vc4_dsi_dma_chan_release, dsi);
+               if (ret)
+                       return ret;
+
                /* Get the physical address of the device's registers.  The
                 * struct resource for the regs gives us the bus address
                 * instead.