summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/fb.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-11-06 14:12:08 +0100
committerThierry Reding <treding@nvidia.com>2014-11-13 16:14:48 +0100
commit1d1e6fe9b5cd9e51c0b064b60f673a973cac38ba (patch)
tree404e5b43d88a459e749d0a749ff41b6eebf5b9fc /drivers/gpu/drm/tegra/fb.c
parent53ea72132df8dd62bb77b28df7b05074dcea96fe (diff)
drm/tegra: Fix error handling cleanup
The DRM driver's ->load() implementation didn't do a good job (no job at all really) cleaning up on failure. Fix that by undoing any prior setup when an error occurs. This requires a bit of rework to make it possible to clean up fbdev midway. This was tested by injecting errors at various points during the initialization sequence and verifying that error cleanup didn't crash and no memory leaked (using kmemleak). Reported-by: Stéphane Marchesin <marcheu@chromium.org> Reported-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/drm/tegra/fb.c')
-rw-r--r--drivers/gpu/drm/tegra/fb.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 3513d12d5aa1..0474241ac2a4 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -289,6 +289,11 @@ static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm)
return fbdev;
}
+static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
+{
+ kfree(fbdev);
+}
+
static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
unsigned int preferred_bpp,
unsigned int num_crtc,
@@ -322,7 +327,7 @@ fini:
return err;
}
-static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
+static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
{
struct fb_info *info = fbdev->base.fbdev;
@@ -345,7 +350,7 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
}
drm_fb_helper_fini(&fbdev->base);
- kfree(fbdev);
+ tegra_fbdev_free(fbdev);
}
void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
@@ -393,6 +398,15 @@ int tegra_drm_fb_prepare(struct drm_device *drm)
return 0;
}
+void tegra_drm_fb_free(struct drm_device *drm)
+{
+#ifdef CONFIG_DRM_TEGRA_FBDEV
+ struct tegra_drm *tegra = drm->dev_private;
+
+ tegra_fbdev_free(tegra->fbdev);
+#endif
+}
+
int tegra_drm_fb_init(struct drm_device *drm)
{
#ifdef CONFIG_DRM_TEGRA_FBDEV
@@ -413,6 +427,6 @@ void tegra_drm_fb_exit(struct drm_device *drm)
#ifdef CONFIG_DRM_TEGRA_FBDEV
struct tegra_drm *tegra = drm->dev_private;
- tegra_fbdev_free(tegra->fbdev);
+ tegra_fbdev_exit(tegra->fbdev);
#endif
}