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>
This commit is contained in:
parent
40d201af0b
commit
b478e336b3
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue