diff options
author | Lukas Wunner <lukas@wunner.de> | 2015-11-18 07:43:20 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-11-19 11:00:24 -0500 |
commit | 54632abe8ca3db8621673b186c7cc0e869c0032f (patch) | |
tree | b48e3fe26a194df46e96d51272b3de98363039d0 | |
parent | ce7f172856396d92e82cb0eae420f4ce41c92851 (diff) |
drm/i915: Fix oops caused by fbdev initialization failure
intelfb_create() is called once on driver initialization. If it fails,
ifbdev->helper.fbdev, ifbdev->fb or ifbdev->fb->obj may be NULL.
Further up in the call stack, intel_fbdev_initial_config() calls
intel_fbdev_fini() to tear down the ifbdev on failure. This calls
intel_fbdev_destroy() which dereferences ifbdev->fb. Fix the ensuing
oops.
Also check in these functions if ifbdev is not NULL to avoid oops:
i915_gem_framebuffer_info() is called on access to debugfs file
"i915_gem_framebuffer" and dereferences ifbdev, ifbdev->helper.fb
and ifbdev->helper.fb->obj.
intel_connector_add_to_fbdev() / intel_connector_remove_from_fbdev()
are called when registering / unregistering an mst connector and
dereference ifbdev.
v3: Drop additional null pointer checks in intel_fbdev_set_suspend(),
intel_fbdev_output_poll_changed() and intel_fbdev_restore_mode()
since they already check if ifbdev is not NULL, which is sufficient
now that intel_fbdev_fini() is called on initialization failure.
(Requested by Daniel Vetter <daniel.vetter@ffwll.ch>)
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Link: http://patchwork.freedesktop.org/patch/msgid/d05f0edf121264a9d0adb8ca713fd8cc4ae068bf.1447938059.git.lukas@wunner.de
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp_mst.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 6 |
3 files changed, 25 insertions, 15 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a9af884dadd5..08eb40292933 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c | |||
@@ -1878,17 +1878,19 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) | |||
1878 | struct drm_i915_private *dev_priv = dev->dev_private; | 1878 | struct drm_i915_private *dev_priv = dev->dev_private; |
1879 | 1879 | ||
1880 | ifbdev = dev_priv->fbdev; | 1880 | ifbdev = dev_priv->fbdev; |
1881 | fb = to_intel_framebuffer(ifbdev->helper.fb); | 1881 | if (ifbdev) { |
1882 | 1882 | fb = to_intel_framebuffer(ifbdev->helper.fb); | |
1883 | seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", | 1883 | |
1884 | fb->base.width, | 1884 | seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", |
1885 | fb->base.height, | 1885 | fb->base.width, |
1886 | fb->base.depth, | 1886 | fb->base.height, |
1887 | fb->base.bits_per_pixel, | 1887 | fb->base.depth, |
1888 | fb->base.modifier[0], | 1888 | fb->base.bits_per_pixel, |
1889 | atomic_read(&fb->base.refcount.refcount)); | 1889 | fb->base.modifier[0], |
1890 | describe_obj(m, fb->obj); | 1890 | atomic_read(&fb->base.refcount.refcount)); |
1891 | seq_putc(m, '\n'); | 1891 | describe_obj(m, fb->obj); |
1892 | seq_putc(m, '\n'); | ||
1893 | } | ||
1892 | #endif | 1894 | #endif |
1893 | 1895 | ||
1894 | mutex_lock(&dev->mode_config.fb_lock); | 1896 | mutex_lock(&dev->mode_config.fb_lock); |
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 8a604ac797aa..a12d1c7ee0e7 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -408,7 +408,10 @@ static void intel_connector_add_to_fbdev(struct intel_connector *connector) | |||
408 | { | 408 | { |
409 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 409 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
410 | struct drm_i915_private *dev_priv = to_i915(connector->base.dev); | 410 | struct drm_i915_private *dev_priv = to_i915(connector->base.dev); |
411 | drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base); | 411 | |
412 | if (dev_priv->fbdev) | ||
413 | drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, | ||
414 | &connector->base); | ||
412 | #endif | 415 | #endif |
413 | } | 416 | } |
414 | 417 | ||
@@ -416,7 +419,10 @@ static void intel_connector_remove_from_fbdev(struct intel_connector *connector) | |||
416 | { | 419 | { |
417 | #ifdef CONFIG_DRM_FBDEV_EMULATION | 420 | #ifdef CONFIG_DRM_FBDEV_EMULATION |
418 | struct drm_i915_private *dev_priv = to_i915(connector->base.dev); | 421 | struct drm_i915_private *dev_priv = to_i915(connector->base.dev); |
419 | drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base); | 422 | |
423 | if (dev_priv->fbdev) | ||
424 | drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, | ||
425 | &connector->base); | ||
420 | #endif | 426 | #endif |
421 | } | 427 | } |
422 | 428 | ||
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 98772d37b09f..cdbef32897f0 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -529,8 +529,10 @@ static void intel_fbdev_destroy(struct drm_device *dev, | |||
529 | 529 | ||
530 | drm_fb_helper_fini(&ifbdev->helper); | 530 | drm_fb_helper_fini(&ifbdev->helper); |
531 | 531 | ||
532 | drm_framebuffer_unregister_private(&ifbdev->fb->base); | 532 | if (ifbdev->fb) { |
533 | drm_framebuffer_remove(&ifbdev->fb->base); | 533 | drm_framebuffer_unregister_private(&ifbdev->fb->base); |
534 | drm_framebuffer_remove(&ifbdev->fb->base); | ||
535 | } | ||
534 | } | 536 | } |
535 | 537 | ||
536 | /* | 538 | /* |