Commit b478e336 authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Dave Airlie

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: default avatarDarren Etheridge <detheridge@ti.com>
Tested-by: default avatarJohannes Pointner <johannes.pointner@br-automation.com>
Signed-off-by: default avatarEzequiel Garcia <ezequiel@vanguardiasur.com.ar>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 40d201af
...@@ -84,6 +84,7 @@ static int modeset_init(struct drm_device *dev) ...@@ -84,6 +84,7 @@ static int modeset_init(struct drm_device *dev)
if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
/* oh nos! */ /* oh nos! */
dev_err(dev->dev, "no encoders/connectors found\n"); dev_err(dev->dev, "no encoders/connectors found\n");
drm_mode_config_cleanup(dev);
return -ENXIO; return -ENXIO;
} }
...@@ -172,33 +173,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ...@@ -172,33 +173,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = priv; dev->dev_private = priv;
priv->wq = alloc_ordered_workqueue("tilcdc", 0); priv->wq = alloc_ordered_workqueue("tilcdc", 0);
if (!priv->wq) {
ret = -ENOMEM;
goto fail_free_priv;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
dev_err(dev->dev, "failed to get memory resource\n"); dev_err(dev->dev, "failed to get memory resource\n");
ret = -EINVAL; ret = -EINVAL;
goto fail; goto fail_free_wq;
} }
priv->mmio = ioremap_nocache(res->start, resource_size(res)); priv->mmio = ioremap_nocache(res->start, resource_size(res));
if (!priv->mmio) { if (!priv->mmio) {
dev_err(dev->dev, "failed to ioremap\n"); dev_err(dev->dev, "failed to ioremap\n");
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail_free_wq;
} }
priv->clk = clk_get(dev->dev, "fck"); priv->clk = clk_get(dev->dev, "fck");
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(dev->dev, "failed to get functional clock\n"); dev_err(dev->dev, "failed to get functional clock\n");
ret = -ENODEV; ret = -ENODEV;
goto fail; goto fail_iounmap;
} }
priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck");
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(dev->dev, "failed to get display clock\n"); dev_err(dev->dev, "failed to get display clock\n");
ret = -ENODEV; ret = -ENODEV;
goto fail; goto fail_put_clk;
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
...@@ -208,7 +213,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ...@@ -208,7 +213,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
if (ret) { if (ret) {
dev_err(dev->dev, "failed to register cpufreq notifier\n"); dev_err(dev->dev, "failed to register cpufreq notifier\n");
goto fail; goto fail_put_disp_clk;
} }
#endif #endif
...@@ -253,13 +258,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ...@@ -253,13 +258,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
ret = modeset_init(dev); ret = modeset_init(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to initialize mode setting\n"); dev_err(dev->dev, "failed to initialize mode setting\n");
goto fail; goto fail_cpufreq_unregister;
} }
ret = drm_vblank_init(dev, 1); ret = drm_vblank_init(dev, 1);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n"); dev_err(dev->dev, "failed to initialize vblank\n");
goto fail; goto fail_mode_config_cleanup;
} }
pm_runtime_get_sync(dev->dev); pm_runtime_get_sync(dev->dev);
...@@ -267,7 +272,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ...@@ -267,7 +272,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
pm_runtime_put_sync(dev->dev); pm_runtime_put_sync(dev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to install IRQ handler\n"); dev_err(dev->dev, "failed to install IRQ handler\n");
goto fail; goto fail_vblank_cleanup;
} }
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
...@@ -283,13 +288,48 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) ...@@ -283,13 +288,48 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
priv->fbdev = drm_fbdev_cma_init(dev, bpp, priv->fbdev = drm_fbdev_cma_init(dev, bpp,
dev->mode_config.num_crtc, dev->mode_config.num_crtc,
dev->mode_config.num_connector); dev->mode_config.num_connector);
if (IS_ERR(priv->fbdev)) {
ret = PTR_ERR(priv->fbdev);
goto fail_irq_uninstall;
}
drm_kms_helper_poll_init(dev); drm_kms_helper_poll_init(dev);
return 0; return 0;
fail: fail_irq_uninstall:
tilcdc_unload(dev); pm_runtime_get_sync(dev->dev);
drm_irq_uninstall(dev);
pm_runtime_put_sync(dev->dev);
fail_vblank_cleanup:
drm_vblank_cleanup(dev);
fail_mode_config_cleanup:
drm_mode_config_cleanup(dev);
fail_cpufreq_unregister:
pm_runtime_disable(dev->dev);
#ifdef CONFIG_CPU_FREQ
cpufreq_unregister_notifier(&priv->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
fail_put_disp_clk:
clk_put(priv->disp_clk);
#endif
fail_put_clk:
clk_put(priv->clk);
fail_iounmap:
iounmap(priv->mmio);
fail_free_wq:
flush_workqueue(priv->wq);
destroy_workqueue(priv->wq);
fail_free_priv:
dev->dev_private = NULL;
kfree(priv);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment