9fd796850f389fa607b454a175cfa79f695cca09
[oweals/openwrt.git] /
1 From cbda8e6de54f8a0f194e990f53e1cfad642af1be Mon Sep 17 00:00:00 2001
2 From: Chris Miller <chris@mesl2.co.uk>
3 Date: Wed, 26 Jun 2019 10:40:30 +0100
4 Subject: [PATCH] drm: vc4_dsi: Fix DMA channel and memory leak in vc4
5  (#3012)
6
7 Signed-off-by: Chris G Miller <chris@creative-electronics.net>
8 ---
9  drivers/gpu/drm/vc4/vc4_dsi.c | 35 ++++++++++++++++++++++++-----------
10  1 file changed, 24 insertions(+), 11 deletions(-)
11
12 --- a/drivers/gpu/drm/vc4/vc4_dsi.c
13 +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
14 @@ -1485,9 +1485,11 @@ static int vc4_dsi_bind(struct device *d
15         /* DSI1 has a broken AXI slave that doesn't respond to writes
16          * from the ARM.  It does handle writes from the DMA engine,
17          * so set up a channel for talking to it.
18 +        * Where possible managed resource providers are used, but the DMA channel
19 +        * must - if acquired - be explicitly released prior to taking an error exit path.
20          */
21         if (dsi->port == 1) {
22 -               dsi->reg_dma_mem = dma_alloc_coherent(dev, 4,
23 +               dsi->reg_dma_mem = dmam_alloc_coherent(dev, 4,
24                                                       &dsi->reg_dma_paddr,
25                                                       GFP_KERNEL);
26                 if (!dsi->reg_dma_mem) {
27 @@ -1506,6 +1508,8 @@ static int vc4_dsi_bind(struct device *d
28                         return ret;
29                 }
30  
31 +               /* From here on, any error exits must release the dma channel */
32 +
33                 /* Get the physical address of the device's registers.  The
34                  * struct resource for the regs gives us the bus address
35                  * instead.
36 @@ -1532,7 +1536,7 @@ static int vc4_dsi_bind(struct device *d
37         if (ret) {
38                 if (ret != -EPROBE_DEFER)
39                         dev_err(dev, "Failed to get interrupt: %d\n", ret);
40 -               return ret;
41 +               goto rel_dma_exit;
42         }
43  
44         dsi->escape_clock = devm_clk_get(dev, "escape");
45 @@ -1540,7 +1544,7 @@ static int vc4_dsi_bind(struct device *d
46                 ret = PTR_ERR(dsi->escape_clock);
47                 if (ret != -EPROBE_DEFER)
48                         dev_err(dev, "Failed to get escape clock: %d\n", ret);
49 -               return ret;
50 +               goto rel_dma_exit;
51         }
52  
53         dsi->pll_phy_clock = devm_clk_get(dev, "phy");
54 @@ -1548,7 +1552,7 @@ static int vc4_dsi_bind(struct device *d
55                 ret = PTR_ERR(dsi->pll_phy_clock);
56                 if (ret != -EPROBE_DEFER)
57                         dev_err(dev, "Failed to get phy clock: %d\n", ret);
58 -               return ret;
59 +               goto rel_dma_exit;
60         }
61  
62         dsi->pixel_clock = devm_clk_get(dev, "pixel");
63 @@ -1556,7 +1560,7 @@ static int vc4_dsi_bind(struct device *d
64                 ret = PTR_ERR(dsi->pixel_clock);
65                 if (ret != -EPROBE_DEFER)
66                         dev_err(dev, "Failed to get pixel clock: %d\n", ret);
67 -               return ret;
68 +               goto rel_dma_exit;
69         }
70  
71         ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
72 @@ -1571,26 +1575,28 @@ static int vc4_dsi_bind(struct device *d
73                 if (ret == -ENODEV)
74                         return 0;
75  
76 -               return ret;
77 +               goto rel_dma_exit;
78         }
79  
80         if (panel) {
81                 dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
82                                                         DRM_MODE_CONNECTOR_DSI);
83 -               if (IS_ERR(dsi->bridge))
84 -                       return PTR_ERR(dsi->bridge);
85 +               if (IS_ERR(dsi->bridge)){
86 +                       ret = PTR_ERR(dsi->bridge);
87 +                       goto rel_dma_exit;
88 +               }
89         }
90  
91         /* The esc clock rate is supposed to always be 100Mhz. */
92         ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
93         if (ret) {
94                 dev_err(dev, "Failed to set esc clock: %d\n", ret);
95 -               return ret;
96 +               goto rel_dma_exit;
97         }
98  
99         ret = vc4_dsi_init_phy_clocks(dsi);
100         if (ret)
101 -               return ret;
102 +               goto rel_dma_exit;
103  
104         if (dsi->port == 1)
105                 vc4->dsi1 = dsi;
106 @@ -1602,7 +1608,7 @@ static int vc4_dsi_bind(struct device *d
107         ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
108         if (ret) {
109                 dev_err(dev, "bridge attach failed: %d\n", ret);
110 -               return ret;
111 +               goto rel_dma_exit;
112         }
113         /* Disable the atomic helper calls into the bridge.  We
114          * manually call the bridge pre_enable / enable / etc. calls
115 @@ -1619,6 +1625,11 @@ static int vc4_dsi_bind(struct device *d
116         pm_runtime_enable(dev);
117  
118         return 0;
119 +
120 +rel_dma_exit:
121 +       dma_release_channel(dsi->reg_dma_chan);
122 +
123 +       return ret;
124  }
125  
126  static void vc4_dsi_unbind(struct device *dev, struct device *master,
127 @@ -1633,6 +1644,8 @@ static void vc4_dsi_unbind(struct device
128  
129         vc4_dsi_encoder_destroy(dsi->encoder);
130  
131 +       dma_release_channel(dsi->reg_dma_chan);
132 +
133         if (dsi->port == 1)
134                 vc4->dsi1 = NULL;
135  }