Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+50 −10
Original line number Diff line number Diff line
@@ -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;
}