aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tilcdc
diff options
context:
space:
mode:
authorEzequiel Garcia <ezequiel@vanguardiasur.com.ar>2014-09-02 08:51:15 -0400
committerDave Airlie <airlied@redhat.com>2014-09-16 20:54:33 -0400
commitb478e336b3e75505707a11e78ef8b964ef0a03af (patch)
tree59ad1d8e4434f4c42ff4dc96184a6762012afb60 /drivers/gpu/drm/tilcdc
parent40d201af0b9e6196a210b97d3b2493b1156564f6 (diff)
drm/tilcdc: Fix the error path in tilcdc_load()
The current error path calls tilcdc_unload() in case of an error to release the resources. However, this is wrong because not all resources have been allocated by the time an error occurs in tilcdc_load(). To fix it, this commit adds proper labels to bail out at the different stages in the load function, and release only the resources actually allocated. Tested-by: Darren Etheridge <detheridge@ti.com> Tested-by: Johannes Pointner <johannes.pointner@br-automation.com> Signed-off-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/tilcdc')
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index aea4b7663934..79a34cbd29f5 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -84,6 +84,7 @@ static int modeset_init(struct drm_device *dev)
84 if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { 84 if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
85 /* oh nos! */ 85 /* oh nos! */
86 dev_err(dev->dev, "no encoders/connectors found\n"); 86 dev_err(dev->dev, "no encoders/connectors found\n");
87 drm_mode_config_cleanup(dev);
87 return -ENXIO; 88 return -ENXIO;
88 } 89 }
89 90
@@ -172,33 +173,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
172 dev->dev_private = priv; 173 dev->dev_private = priv;
173 174
174 priv->wq = alloc_ordered_workqueue("tilcdc", 0); 175 priv->wq = alloc_ordered_workqueue("tilcdc", 0);
176 if (!priv->wq) {
177 ret = -ENOMEM;
178 goto fail_free_priv;
179 }
175 180
176 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 181 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
177 if (!res) { 182 if (!res) {
178 dev_err(dev->dev, "failed to get memory resource\n"); 183 dev_err(dev->dev, "failed to get memory resource\n");
179 ret = -EINVAL; 184 ret = -EINVAL;
180 goto fail; 185 goto fail_free_wq;
181 } 186 }
182 187
183 priv->mmio = ioremap_nocache(res->start, resource_size(res)); 188 priv->mmio = ioremap_nocache(res->start, resource_size(res));
184 if (!priv->mmio) { 189 if (!priv->mmio) {
185 dev_err(dev->dev, "failed to ioremap\n"); 190 dev_err(dev->dev, "failed to ioremap\n");
186 ret = -ENOMEM; 191 ret = -ENOMEM;
187 goto fail; 192 goto fail_free_wq;
188 } 193 }
189 194
190 priv->clk = clk_get(dev->dev, "fck"); 195 priv->clk = clk_get(dev->dev, "fck");
191 if (IS_ERR(priv->clk)) { 196 if (IS_ERR(priv->clk)) {
192 dev_err(dev->dev, "failed to get functional clock\n"); 197 dev_err(dev->dev, "failed to get functional clock\n");
193 ret = -ENODEV; 198 ret = -ENODEV;
194 goto fail; 199 goto fail_iounmap;
195 } 200 }
196 201
197 priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); 202 priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck");
198 if (IS_ERR(priv->clk)) { 203 if (IS_ERR(priv->clk)) {
199 dev_err(dev->dev, "failed to get display clock\n"); 204 dev_err(dev->dev, "failed to get display clock\n");
200 ret = -ENODEV; 205 ret = -ENODEV;
201 goto fail; 206 goto fail_put_clk;
202 } 207 }
203 208
204#ifdef CONFIG_CPU_FREQ 209#ifdef CONFIG_CPU_FREQ
@@ -208,7 +213,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
208 CPUFREQ_TRANSITION_NOTIFIER); 213 CPUFREQ_TRANSITION_NOTIFIER);
209 if (ret) { 214 if (ret) {
210 dev_err(dev->dev, "failed to register cpufreq notifier\n"); 215 dev_err(dev->dev, "failed to register cpufreq notifier\n");
211 goto fail; 216 goto fail_put_disp_clk;
212 } 217 }
213#endif 218#endif
214 219
@@ -253,13 +258,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
253 ret = modeset_init(dev); 258 ret = modeset_init(dev);
254 if (ret < 0) { 259 if (ret < 0) {
255 dev_err(dev->dev, "failed to initialize mode setting\n"); 260 dev_err(dev->dev, "failed to initialize mode setting\n");
256 goto fail; 261 goto fail_cpufreq_unregister;
257 } 262 }
258 263
259 ret = drm_vblank_init(dev, 1); 264 ret = drm_vblank_init(dev, 1);
260 if (ret < 0) { 265 if (ret < 0) {
261 dev_err(dev->dev, "failed to initialize vblank\n"); 266 dev_err(dev->dev, "failed to initialize vblank\n");
262 goto fail; 267 goto fail_mode_config_cleanup;
263 } 268 }
264 269
265 pm_runtime_get_sync(dev->dev); 270 pm_runtime_get_sync(dev->dev);
@@ -267,7 +272,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
267 pm_runtime_put_sync(dev->dev); 272 pm_runtime_put_sync(dev->dev);
268 if (ret < 0) { 273 if (ret < 0) {
269 dev_err(dev->dev, "failed to install IRQ handler\n"); 274 dev_err(dev->dev, "failed to install IRQ handler\n");
270 goto fail; 275 goto fail_vblank_cleanup;
271 } 276 }
272 277
273 platform_set_drvdata(pdev, dev); 278 platform_set_drvdata(pdev, dev);
@@ -283,13 +288,48 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
283 priv->fbdev = drm_fbdev_cma_init(dev, bpp, 288 priv->fbdev = drm_fbdev_cma_init(dev, bpp,
284 dev->mode_config.num_crtc, 289 dev->mode_config.num_crtc,
285 dev->mode_config.num_connector); 290 dev->mode_config.num_connector);
291 if (IS_ERR(priv->fbdev)) {
292 ret = PTR_ERR(priv->fbdev);
293 goto fail_irq_uninstall;
294 }
286 295
287 drm_kms_helper_poll_init(dev); 296 drm_kms_helper_poll_init(dev);
288 297
289 return 0; 298 return 0;
290 299
291fail: 300fail_irq_uninstall:
292 tilcdc_unload(dev); 301 pm_runtime_get_sync(dev->dev);
302 drm_irq_uninstall(dev);
303 pm_runtime_put_sync(dev->dev);
304
305fail_vblank_cleanup:
306 drm_vblank_cleanup(dev);
307
308fail_mode_config_cleanup:
309 drm_mode_config_cleanup(dev);
310
311fail_cpufreq_unregister:
312 pm_runtime_disable(dev->dev);
313#ifdef CONFIG_CPU_FREQ
314 cpufreq_unregister_notifier(&priv->freq_transition,
315 CPUFREQ_TRANSITION_NOTIFIER);
316fail_put_disp_clk:
317 clk_put(priv->disp_clk);
318#endif
319
320fail_put_clk:
321 clk_put(priv->clk);
322
323fail_iounmap:
324 iounmap(priv->mmio);
325
326fail_free_wq:
327 flush_workqueue(priv->wq);
328 destroy_workqueue(priv->wq);
329
330fail_free_priv:
331 dev->dev_private = NULL;
332 kfree(priv);
293 return ret; 333 return ret;
294} 334}
295 335