diff mbox

drm/i915: Protect fbdev across slow or failed initialisation

Message ID 1459360634-25516-1-git-send-email-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson March 30, 2016, 5:57 p.m. UTC
If the initialisation fails, we may be left with a dangling pointer with
an incomplete fbdev structure. Here we want to disable internal calls
into fbdev. Similarly, the initialisation may be slow and we haven't yet
enabled the fbdev (e.g. quick suspend or last-close before the async init
completes).

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93580
Reported-by: "Li, Weinan Z" <weinan.z.li@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_fbdev.c | 48 ++++++++++++++++++++++++--------------
 1 file changed, 30 insertions(+), 18 deletions(-)

Comments

kernel test robot March 30, 2016, 6:10 p.m. UTC | #1
Hi Chris,

[auto build test WARNING on drm-intel/for-linux-next]
[cannot apply to v4.6-rc1 next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Chris-Wilson/drm-i915-Protect-fbdev-across-slow-or-failed-initialisation/20160331-015912
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-randconfig-x015-03310059 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/i915/intel_fbdev.c: In function 'intel_fbdev_get_if_active':
   drivers/gpu/drm/i915/intel_fbdev.c:119:37: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     struct drm_i915_device *dev_priv = to_i915(dev);
                                        ^
   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/async.h:15,
                    from drivers/gpu/drm/i915/intel_fbdev.c:27:
   drivers/gpu/drm/i915/intel_fbdev.c:122:14: error: dereferencing pointer to incomplete type 'struct drm_i915_device'
     if (dev_priv->fbdev == NULL)
                 ^
   include/linux/compiler.h:147:30: note: in definition of macro '__trace_if'
     if (__builtin_constant_p(!!(cond)) ? !!(cond) :   \
                                 ^
>> drivers/gpu/drm/i915/intel_fbdev.c:122:2: note: in expansion of macro 'if'
     if (dev_priv->fbdev == NULL)
     ^
   drivers/gpu/drm/i915/intel_fbdev.c:125:9: error: 'ifbdev' undeclared (first use in this function)
     info = ifbdev->helper.fbdev;
            ^
   drivers/gpu/drm/i915/intel_fbdev.c:125:9: note: each undeclared identifier is reported only once for each function it appears in
   drivers/gpu/drm/i915/intel_fbdev.c:133:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

vim +/if +122 drivers/gpu/drm/i915/intel_fbdev.c

    21	 * DEALINGS IN THE SOFTWARE.
    22	 *
    23	 * Authors:
    24	 *     David Airlie
    25	 */
    26	
  > 27	#include <linux/async.h>
    28	#include <linux/module.h>
    29	#include <linux/kernel.h>
    30	#include <linux/console.h>
    31	#include <linux/errno.h>
    32	#include <linux/string.h>
    33	#include <linux/mm.h>
    34	#include <linux/tty.h>
    35	#include <linux/sysrq.h>
    36	#include <linux/delay.h>
    37	#include <linux/fb.h>
    38	#include <linux/init.h>
    39	#include <linux/vga_switcheroo.h>
    40	
    41	#include <drm/drmP.h>
    42	#include <drm/drm_crtc.h>
    43	#include <drm/drm_fb_helper.h>
    44	#include "intel_drv.h"
    45	#include <drm/i915_drm.h>
    46	#include "i915_drv.h"
    47	
    48	static int intel_fbdev_set_par(struct fb_info *info)
    49	{
    50		struct drm_fb_helper *fb_helper = info->par;
    51		struct intel_fbdev *ifbdev =
    52			container_of(fb_helper, struct intel_fbdev, helper);
    53		int ret;
    54	
    55		ret = drm_fb_helper_set_par(info);
    56	
    57		if (ret == 0) {
    58			mutex_lock(&fb_helper->dev->struct_mutex);
    59			intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
    60			mutex_unlock(&fb_helper->dev->struct_mutex);
    61		}
    62	
    63		return ret;
    64	}
    65	
    66	static int intel_fbdev_blank(int blank, struct fb_info *info)
    67	{
    68		struct drm_fb_helper *fb_helper = info->par;
    69		struct intel_fbdev *ifbdev =
    70			container_of(fb_helper, struct intel_fbdev, helper);
    71		int ret;
    72	
    73		ret = drm_fb_helper_blank(blank, info);
    74	
    75		if (ret == 0) {
    76			mutex_lock(&fb_helper->dev->struct_mutex);
    77			intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
    78			mutex_unlock(&fb_helper->dev->struct_mutex);
    79		}
    80	
    81		return ret;
    82	}
    83	
    84	static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
    85					   struct fb_info *info)
    86	{
    87		struct drm_fb_helper *fb_helper = info->par;
    88		struct intel_fbdev *ifbdev =
    89			container_of(fb_helper, struct intel_fbdev, helper);
    90	
    91		int ret;
    92		ret = drm_fb_helper_pan_display(var, info);
    93	
    94		if (ret == 0) {
    95			mutex_lock(&fb_helper->dev->struct_mutex);
    96			intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
    97			mutex_unlock(&fb_helper->dev->struct_mutex);
    98		}
    99	
   100		return ret;
   101	}
   102	
   103	static struct fb_ops intelfb_ops = {
   104		.owner = THIS_MODULE,
   105		.fb_check_var = drm_fb_helper_check_var,
   106		.fb_set_par = intel_fbdev_set_par,
   107		.fb_fillrect = drm_fb_helper_cfb_fillrect,
   108		.fb_copyarea = drm_fb_helper_cfb_copyarea,
   109		.fb_imageblit = drm_fb_helper_cfb_imageblit,
   110		.fb_pan_display = intel_fbdev_pan_display,
   111		.fb_blank = intel_fbdev_blank,
   112		.fb_setcmap = drm_fb_helper_setcmap,
   113		.fb_debug_enter = drm_fb_helper_debug_enter,
   114		.fb_debug_leave = drm_fb_helper_debug_leave,
   115	};
   116	
   117	static struct intel_fbdev *intel_fbdev_get_if_active(struct drm_device *dev)
   118	{
   119		struct drm_i915_device *dev_priv = to_i915(dev);
   120		struct fb_info *info;
   121	
 > 122		if (dev_priv->fbdev == NULL)
   123			return NULL;
   124	
   125		info = ifbdev->helper.fbdev;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot March 30, 2016, 6:10 p.m. UTC | #2
Hi Chris,

[auto build test ERROR on drm-intel/for-linux-next]
[cannot apply to v4.6-rc1 next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Chris-Wilson/drm-i915-Protect-fbdev-across-slow-or-failed-initialisation/20160331-015912
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-randconfig-x012-03310059 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All error/warnings (new ones prefixed by >>):

   drivers/gpu/drm/i915/intel_fbdev.c: In function 'intel_fbdev_get_if_active':
>> drivers/gpu/drm/i915/intel_fbdev.c:119:37: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     struct drm_i915_device *dev_priv = to_i915(dev);
                                        ^
>> drivers/gpu/drm/i915/intel_fbdev.c:122:14: error: dereferencing pointer to incomplete type 'struct drm_i915_device'
     if (dev_priv->fbdev == NULL)
                 ^
>> drivers/gpu/drm/i915/intel_fbdev.c:125:9: error: 'ifbdev' undeclared (first use in this function)
     info = ifbdev->helper.fbdev;
            ^
   drivers/gpu/drm/i915/intel_fbdev.c:125:9: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/gpu/drm/i915/intel_fbdev.c:133:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

vim +122 drivers/gpu/drm/i915/intel_fbdev.c

   113		.fb_debug_enter = drm_fb_helper_debug_enter,
   114		.fb_debug_leave = drm_fb_helper_debug_leave,
   115	};
   116	
   117	static struct intel_fbdev *intel_fbdev_get_if_active(struct drm_device *dev)
   118	{
 > 119		struct drm_i915_device *dev_priv = to_i915(dev);
   120		struct fb_info *info;
   121	
 > 122		if (dev_priv->fbdev == NULL)
   123			return NULL;
   124	
 > 125		info = ifbdev->helper.fbdev;
   126		if (info->screen_base == NULL)
   127			return NULL;
   128	
   129		if (info->state != FBINFO_STATE_RUNNING)
   130			return NULL;
   131	
   132		return dev_priv->fbdev;
 > 133	}
   134	
   135	static int intelfb_alloc(struct drm_fb_helper *helper,
   136				 struct drm_fb_helper_surface_size *sizes)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot March 30, 2016, 6:26 p.m. UTC | #3
Hi Chris,

[auto build test ERROR on drm-intel/for-linux-next]
[cannot apply to v4.6-rc1 next-20160330]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Chris-Wilson/drm-i915-Protect-fbdev-across-slow-or-failed-initialisation/20160331-015912
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: x86_64-rhel (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/gpu/drm/i915/intel_fbdev.c: In function 'intel_fbdev_get_if_active':
   drivers/gpu/drm/i915/intel_fbdev.c:119:37: warning: initialization from incompatible pointer type
     struct drm_i915_device *dev_priv = to_i915(dev);
                                        ^
>> drivers/gpu/drm/i915/intel_fbdev.c:122:14: error: dereferencing pointer to incomplete type
     if (dev_priv->fbdev == NULL)
                 ^
   drivers/gpu/drm/i915/intel_fbdev.c:125:9: error: 'ifbdev' undeclared (first use in this function)
     info = ifbdev->helper.fbdev;
            ^
   drivers/gpu/drm/i915/intel_fbdev.c:125:9: note: each undeclared identifier is reported only once for each function it appears in
   drivers/gpu/drm/i915/intel_fbdev.c:132:17: error: dereferencing pointer to incomplete type
     return dev_priv->fbdev;
                    ^
   drivers/gpu/drm/i915/intel_fbdev.c:133:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^

vim +122 drivers/gpu/drm/i915/intel_fbdev.c

   113		.fb_debug_enter = drm_fb_helper_debug_enter,
   114		.fb_debug_leave = drm_fb_helper_debug_leave,
   115	};
   116	
   117	static struct intel_fbdev *intel_fbdev_get_if_active(struct drm_device *dev)
   118	{
 > 119		struct drm_i915_device *dev_priv = to_i915(dev);
   120		struct fb_info *info;
   121	
 > 122		if (dev_priv->fbdev == NULL)
   123			return NULL;
   124	
   125		info = ifbdev->helper.fbdev;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Chris Wilson March 30, 2016, 6:30 p.m. UTC | #4
On Wed, Mar 30, 2016 at 06:57:14PM +0100, Chris Wilson wrote:
> If the initialisation fails, we may be left with a dangling pointer with
> an incomplete fbdev structure. Here we want to disable internal calls
> into fbdev. Similarly, the initialisation may be slow and we haven't yet
> enabled the fbdev (e.g. quick suspend or last-close before the async init
> completes).
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93580
> Reported-by: "Li, Weinan Z" <weinan.z.li@intel.com>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/intel_fbdev.c | 48 ++++++++++++++++++++++++--------------
>  1 file changed, 30 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index 51a5e39e52f2..0bae91268a12 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -114,6 +114,24 @@ static struct fb_ops intelfb_ops = {
>  	.fb_debug_leave = drm_fb_helper_debug_leave,
>  };
>  
> +static struct intel_fbdev *intel_fbdev_get_if_active(struct drm_device *dev)
> +{
> +	struct drm_i915_device *dev_priv = to_i915(dev);

As kbuild reported, the danger of retyping a patch from email and
forgetting you compiled on a machine without fbdev.
s/drm_i915_device/drm_i915_private/
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 51a5e39e52f2..0bae91268a12 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -114,6 +114,24 @@  static struct fb_ops intelfb_ops = {
 	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
+static struct intel_fbdev *intel_fbdev_get_if_active(struct drm_device *dev)
+{
+	struct drm_i915_device *dev_priv = to_i915(dev);
+	struct fb_info *info;
+
+	if (dev_priv->fbdev == NULL)
+		return NULL;
+
+	info = ifbdev->helper.fbdev;
+	if (info->screen_base == NULL)
+		return NULL;
+
+	if (info->state != FBINFO_STATE_RUNNING)
+		return NULL;
+
+	return dev_priv->fbdev;
+}
+
 static int intelfb_alloc(struct drm_fb_helper *helper,
 			 struct drm_fb_helper_surface_size *sizes)
 {
@@ -764,6 +782,8 @@  void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
 		return;
 
 	info = ifbdev->helper.fbdev;
+	if (info->screen_base == NULL)
+		return;
 
 	if (synchronous) {
 		/* Flush any pending work to turn the console on, and then
@@ -805,32 +825,24 @@  void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous
 
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev = intel_fbdev_get_if_active(dev);
+
+	if (ifbdev == NULL)
+		return;
 
-	async_synchronize_full();
-	if (dev_priv->fbdev)
-		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+	drm_fb_helper_hotplug_event(&ifbdev->helper);
 }
 
 void intel_fbdev_restore_mode(struct drm_device *dev)
 {
-	int ret;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_fbdev *ifbdev = dev_priv->fbdev;
-	struct drm_fb_helper *fb_helper;
+	struct intel_fbdev *ifbdev = intel_fbdev_get_if_active(dev);
 
-	async_synchronize_full();
-	if (!ifbdev)
+	if (ifbdev == NULL)
 		return;
 
-	fb_helper = &ifbdev->helper;
-
-	ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
-	if (ret) {
-		DRM_DEBUG("failed to restore crtc mode\n");
-	} else {
-		mutex_lock(&fb_helper->dev->struct_mutex);
+	if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0) {
+		mutex_lock(&dev->struct_mutex);
 		intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
-		mutex_unlock(&fb_helper->dev->struct_mutex);
+		mutex_unlock(&dev->struct_mutex);
 	}
 }