mirror of https://gitee.com/openkylin/linux.git
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)) {
|
||||
/* oh nos! */
|
||||
dev_err(dev->dev, "no encoders/connectors found\n");
|
||||
drm_mode_config_cleanup(dev);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
|
@ -172,33 +173,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
|
|||
dev->dev_private = priv;
|
||||
|
||||
priv->wq = alloc_ordered_workqueue("tilcdc", 0);
|
||||
if (!priv->wq) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_free_priv;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev->dev, "failed to get memory resource\n");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
goto fail_free_wq;
|
||||
}
|
||||
|
||||
priv->mmio = ioremap_nocache(res->start, resource_size(res));
|
||||
if (!priv->mmio) {
|
||||
dev_err(dev->dev, "failed to ioremap\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
goto fail_free_wq;
|
||||
}
|
||||
|
||||
priv->clk = clk_get(dev->dev, "fck");
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(dev->dev, "failed to get functional clock\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
goto fail_iounmap;
|
||||
}
|
||||
|
||||
priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck");
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(dev->dev, "failed to get display clock\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
goto fail_put_clk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
@ -208,7 +213,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
|
|||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to register cpufreq notifier\n");
|
||||
goto fail;
|
||||
goto fail_put_disp_clk;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -253,13 +258,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
|
|||
ret = modeset_init(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "failed to initialize mode setting\n");
|
||||
goto fail;
|
||||
goto fail_cpufreq_unregister;
|
||||
}
|
||||
|
||||
ret = drm_vblank_init(dev, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "failed to initialize vblank\n");
|
||||
goto fail;
|
||||
goto fail_mode_config_cleanup;
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "failed to install IRQ handler\n");
|
||||
goto fail;
|
||||
goto fail_vblank_cleanup;
|
||||
}
|
||||
|
||||
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,
|
||||
dev->mode_config.num_crtc,
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
tilcdc_unload(dev);
|
||||
fail_irq_uninstall:
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue