diff mbox

drm: Avoid forcing a detection cycle following a hotplug event

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

Commit Message

Chris Wilson June 5, 2013, 3:50 p.m. UTC
The typical procedure after a hotplug event is then to enumerate all the
new modes. In the existing code, this is achieved by performing a forced
detection cycle over all connectors. Ideally, we should just be able to
use the current detection status and only enumerate the modes on the
connectors that changed. This is a step in that direction by teaching
the hotplug path to only use the known detection status rather than
performing a second *forced* detection on every connector. As it
currently stands, the first thing userspace does upon receipt of a
hotplug uevent is call DRM_IOCTL_MODE_GETCONNECTOR on each connector,
which of course, performs another full detection cycle.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: dri-devel@lists.freedesktop.org
Cc: Jakob Bornecrantz <jakob@vmware.com>
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Adam Jackson <ajax@redhat.com>
---
 drivers/gpu/drm/drm_crtc.c                    |    3 ++-
 drivers/gpu/drm/drm_crtc_helper.c             |    8 ++++++--
 drivers/gpu/drm/drm_fb_helper.c               |   14 ++++++++------
 drivers/gpu/drm/exynos/exynos_drm_connector.c |    7 ++++---
 drivers/gpu/drm/i2c/ch7006_drv.c              |    2 +-
 drivers/gpu/drm/nouveau/dispnv04/tvnv17.c     |    2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c           |    3 ++-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h           |    3 ++-
 include/drm/drm_crtc.h                        |    2 +-
 include/drm/drm_crtc_helper.h                 |    2 +-
 10 files changed, 28 insertions(+), 18 deletions(-)

Comments

Laurent Pinchart June 8, 2013, 7:28 a.m. UTC | #1
Hi Chris,

Thanks for the patch.

On Wednesday 05 June 2013 16:50:14 Chris Wilson wrote:
> The typical procedure after a hotplug event is then to enumerate all the
> new modes. In the existing code, this is achieved by performing a forced
> detection cycle over all connectors. Ideally, we should just be able to
> use the current detection status and only enumerate the modes on the
> connectors that changed. This is a step in that direction by teaching
> the hotplug path to only use the known detection status rather than
> performing a second *forced* detection on every connector. As it
> currently stands, the first thing userspace does upon receipt of a
> hotplug uevent is call DRM_IOCTL_MODE_GETCONNECTOR on each connector,
> which of course, performs another full detection cycle.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: dri-devel@lists.freedesktop.org
> Cc: Jakob Bornecrantz <jakob@vmware.com>
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Adam Jackson <ajax@redhat.com>
> ---
>  drivers/gpu/drm/drm_crtc.c                    |    3 ++-
>  drivers/gpu/drm/drm_crtc_helper.c             |    8 ++++++--
>  drivers/gpu/drm/drm_fb_helper.c               |   14 ++++++++------
>  drivers/gpu/drm/exynos/exynos_drm_connector.c |    7 ++++---
>  drivers/gpu/drm/i2c/ch7006_drv.c              |    2 +-
>  drivers/gpu/drm/nouveau/dispnv04/tvnv17.c     |    2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c           |    3 ++-
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.h           |    3 ++-
>  include/drm/drm_crtc.h                        |    2 +-
>  include/drm/drm_crtc_helper.h                 |    2 +-

Could you please also update Documentation/DocBook/drm.tmpl ?

>  10 files changed, 28 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index e7e9242..635276c 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1537,7 +1537,8 @@ int drm_mode_getconnector(struct drm_device *dev, void
> *data, if (out_resp->count_modes == 0) {
>  		connector->funcs->fill_modes(connector,
>  					     dev->mode_config.max_width,
> -					     dev->mode_config.max_height);
> +					     dev->mode_config.max_height,
> +					     true);
>  	}
> 
>  	/* delayed so we get modes regardless of pre-fill_modes state */
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c
> b/drivers/gpu/drm/drm_crtc_helper.c index ed1334e..7f2128c 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -96,6 +96,9 @@ static void drm_mode_validate_flag(struct drm_connector
> *connector, * @connector: connector to probe
>   * @maxX: max width for modes
>   * @maxY: max height for modes
> + * @force: whether to use the cached connector status or to force a
> + *         fresh detection cycle, for instance after a hotplug event, we
> + *         want to simply use the known status.
>   *
>   * LOCKING:
>   * Caller must hold mode config lock.
> @@ -113,7 +116,8 @@ static void drm_mode_validate_flag(struct drm_connector
> *connector, * Number of modes found on @connector.
>   */
>  int drm_helper_probe_single_connector_modes(struct drm_connector
> *connector, -					    uint32_t maxX, uint32_t maxY)
> +					    uint32_t maxX, uint32_t maxY,
> +					    bool force)
>  {
>  	struct drm_device *dev = connector->dev;
>  	struct drm_display_mode *mode;
> @@ -136,7 +140,7 @@ int drm_helper_probe_single_connector_modes(struct
> drm_connector *connector, connector->status =
> connector_status_disconnected;
>  		if (connector->funcs->force)
>  			connector->funcs->force(connector);
> -	} else {
> +	} else if (force) {
>  		connector->status = connector->funcs->detect(connector, true);
>  	}
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c
> b/drivers/gpu/drm/drm_fb_helper.c index b78cbe7..3e0802d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -1087,8 +1087,8 @@ void drm_fb_helper_fill_var(struct fb_info *info,
> struct drm_fb_helper *fb_helpe EXPORT_SYMBOL(drm_fb_helper_fill_var);
> 
>  static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper
> *fb_helper, -					       uint32_t maxX,
> -					       uint32_t maxY)
> +					       uint32_t maxX, uint32_t maxY,
> +					       bool force)
>  {
>  	struct drm_connector *connector;
>  	int count = 0;
> @@ -1096,7 +1096,7 @@ static int drm_fb_helper_probe_connector_modes(struct
> drm_fb_helper *fb_helper,
> 
>  	for (i = 0; i < fb_helper->connector_count; i++) {
>  		connector = fb_helper->connector_info[i]->connector;
> -		count += connector->funcs->fill_modes(connector, maxX, maxY);
> +		count += connector->funcs->fill_modes(connector, maxX, maxY, force);
>  	}
> 
>  	return count;
> @@ -1510,7 +1510,8 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper
> *fb_helper, int bpp_sel)
> 
>  	count = drm_fb_helper_probe_connector_modes(fb_helper,
>  						    dev->mode_config.max_width,
> -						    dev->mode_config.max_height);
> +						    dev->mode_config.max_height,
> +						    true);
>  	/*
>  	 * we shouldn't end up with no modes here.
>  	 */
> @@ -1563,8 +1564,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper
> *fb_helper) max_height = fb_helper->fb->height;
>  	bpp_sel = fb_helper->fb->bits_per_pixel;
> 
> -	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
> -						    max_height);
> +	count = drm_fb_helper_probe_connector_modes(fb_helper,
> +						    max_width, max_height,
> +						    false);
>  	mutex_unlock(&fb_helper->dev->mode_config.mutex);
> 
>  	drm_modeset_lock_all(dev);
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c
> b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 8bcc13a..48ef16f
> 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
> @@ -249,7 +249,8 @@ static void exynos_drm_connector_dpms(struct
> drm_connector *connector, }
> 
>  static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
> -				unsigned int max_width, unsigned int max_height)
> +				unsigned int max_width, unsigned int max_height,
> +				bool force)
>  {
>  	struct exynos_drm_connector *exynos_connector =
>  					to_exynos_connector(connector);
> @@ -267,8 +268,8 @@ static int exynos_drm_connector_fill_modes(struct
> drm_connector *connector, if (ops && ops->get_max_resol)
>  		ops->get_max_resol(manager->dev, &width, &height);
> 
> -	return drm_helper_probe_single_connector_modes(connector, width,
> -							height);
> +	return drm_helper_probe_single_connector_modes(connector,
> +						       width, height, force);
>  }
> 
>  /* get detection status of display device. */
> diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c
> b/drivers/gpu/drm/i2c/ch7006_drv.c index 51fa323..d18237d 100644
> --- a/drivers/gpu/drm/i2c/ch7006_drv.c
> +++ b/drivers/gpu/drm/i2c/ch7006_drv.c
> @@ -355,7 +355,7 @@ static int ch7006_encoder_set_property(struct
> drm_encoder *encoder, }
> 
>  	if (modes_changed) {
> -		drm_helper_probe_single_connector_modes(connector, 0, 0);
> +		drm_helper_probe_single_connector_modes(connector, 0, 0, false);
> 
>  		/* Disable the crtc to ensure a full modeset is
>  		 * performed whenever it's turned on again. */
> diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
> b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index acef48f..535dd14 100644
> --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
> +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
> @@ -759,7 +759,7 @@ static int nv17_tv_set_property(struct drm_encoder
> *encoder, }
> 
>  	if (modes_changed) {
> -		drm_helper_probe_single_connector_modes(connector, 0, 0);
> +		drm_helper_probe_single_connector_modes(connector, 0, 0, false);
> 
>  		/* Disable the crtc to ensure a full modeset is
>  		 * performed whenever it's turned on again. */
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 3e3c7ab..d9a0768 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
> @@ -1924,7 +1924,8 @@ static void vmw_guess_mode_timing(struct
> drm_display_mode *mode)
> 
> 
>  int vmw_du_connector_fill_modes(struct drm_connector *connector,
> -				uint32_t max_width, uint32_t max_height)
> +				uint32_t max_width, uint32_t max_height,
> +				bool force)
>  {
>  	struct vmw_display_unit *du = vmw_connector_to_du(connector);
>  	struct drm_device *dev = connector->dev;
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 6fa89c9..19fc306 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
> @@ -138,7 +138,8 @@ void vmw_du_connector_restore(struct drm_connector
> *connector); enum drm_connector_status
>  vmw_du_connector_detect(struct drm_connector *connector, bool force);
>  int vmw_du_connector_fill_modes(struct drm_connector *connector,
> -				uint32_t max_width, uint32_t max_height);
> +				uint32_t max_width, uint32_t max_height,
> +				bool force);
>  int vmw_du_connector_set_property(struct drm_connector *connector,
>  				  struct drm_property *property,
>  				  uint64_t val);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index adb3f9b..373e774 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -468,7 +468,7 @@ struct drm_connector_funcs {
>  	 */
>  	enum drm_connector_status (*detect)(struct drm_connector *connector,
>  					    bool force);
> -	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width,
> uint32_t max_height); +	int (*fill_modes)(struct drm_connector *connector,
> uint32_t max_width, uint32_t max_height, bool force); int
> (*set_property)(struct drm_connector *connector, struct drm_property
> *property, uint64_t val);
>  	void (*destroy)(struct drm_connector *connector);
> diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
> index f43d556..cce7221 100644
> --- a/include/drm/drm_crtc_helper.h
> +++ b/include/drm/drm_crtc_helper.h
> @@ -125,7 +125,7 @@ struct drm_connector_helper_funcs {
>  	struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
>  };
> 
> -extern int drm_helper_probe_single_connector_modes(struct drm_connector
> *connector, uint32_t maxX, uint32_t maxY); +extern int
> drm_helper_probe_single_connector_modes(struct drm_connector *connector,
> uint32_t maxX, uint32_t maxY, bool force); extern void
> drm_helper_disable_unused_functions(struct drm_device *dev); extern int
> drm_crtc_helper_set_config(struct drm_mode_set *set);
>  extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
Chris Wilson June 8, 2013, 7:53 a.m. UTC | #2
On Sat, Jun 08, 2013 at 09:28:17AM +0200, Laurent Pinchart wrote:
> Could you please also update Documentation/DocBook/drm.tmpl ?

It looks out of context there, as nothing explains the hotplug ->
fill_modes -> probe -> detect loop...

How about:

  <title>Modes</title>
  <synopsis>int (*fill_modes)(struct drm_connector *connector, uint32_t max_width,
	      uint32_t max_height, bool force);</synopsis>
  <para>
    Fill the mode list with all supported modes for the connector. If the
    <parameter>max_width</parameter> and <parameter>max_height</parameter>
    arguments are non-zero, the implementation must ignore all modes wider
    than <parameter>max_width</parameter> or higher than
    <parameter>max_height</parameter>. The driver may use the existing
    connector status, unless <parameter>force</parameter> is passed. During a
    hotplug event, the driver may already have updated its knowledge of the
    output and so may simply refresh the modes list from the information it
    acquired whilst handling the event. However, the caller may explicitly
    request that any cached information be dropped, and for the output to be
    queried for its current status and modes - under such circumstances
    <parameter>force</parameter> is true.
  </para>
-Chris
Daniel Vetter June 8, 2013, 1:30 p.m. UTC | #3
On Wed, Jun 5, 2013 at 5:50 PM, Chris Wilson <chris@chris-wilson.co.uk> wrote:
> The typical procedure after a hotplug event is then to enumerate all the
> new modes. In the existing code, this is achieved by performing a forced
> detection cycle over all connectors. Ideally, we should just be able to
> use the current detection status and only enumerate the modes on the
> connectors that changed. This is a step in that direction by teaching
> the hotplug path to only use the known detection status rather than
> performing a second *forced* detection on every connector. As it
> currently stands, the first thing userspace does upon receipt of a
> hotplug uevent is call DRM_IOCTL_MODE_GETCONNECTOR on each connector,
> which of course, performs another full detection cycle.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: dri-devel@lists.freedesktop.org
> Cc: Jakob Bornecrantz <jakob@vmware.com>
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Adam Jackson <ajax@redhat.com>

I've dumped a bit a longer blabla text onto the i915 patch in this
series (and cc'ed dri-devel on it), so just the gist: I'm a bit
unhappy that we add a force parameter here essentially just for the
fbdev helper. Imo userspace and legacy fbdev should use the same api,
if that's not good enough the interface is probably not fully
suitable. The end result is a pretty convoluted sequence:
- hpd/poll work calls ->detect
- fbdev calls into ->fill_modes, but avoids ->detect with the
force=false parameter, so this is the part which calls ->get_modes
- userspace avoids calling ->fill_modes with a special trick

I prefer things more explicit ;-)

Cheers, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
Laurent Pinchart June 18, 2013, 10:37 p.m. UTC | #4
Hi Chris,

On Saturday 08 June 2013 08:53:30 Chris Wilson wrote:
> On Sat, Jun 08, 2013 at 09:28:17AM +0200, Laurent Pinchart wrote:
> > Could you please also update Documentation/DocBook/drm.tmpl ?
> 
> It looks out of context there, as nothing explains the hotplug ->
> fill_modes -> probe -> detect loop...

Sorry, I should have been more precise. You patches changes the prototype of 
the fill_modes() operation and the drm_helper_probe_single_connector_modes() 
function, documented in drm.tmpl. I'd like to keep the documentation in sync.

> 
> How about:
> 
>   <title>Modes</title>
>   <synopsis>int (*fill_modes)(struct drm_connector *connector, uint32_t
> max_width, uint32_t max_height, bool force);</synopsis>
>   <para>
>     Fill the mode list with all supported modes for the connector. If the
>     <parameter>max_width</parameter> and <parameter>max_height</parameter>
>     arguments are non-zero, the implementation must ignore all modes wider
>     than <parameter>max_width</parameter> or higher than
>     <parameter>max_height</parameter>. The driver may use the existing
>     connector status, unless <parameter>force</parameter> is passed. During
> a hotplug event, the driver may already have updated its knowledge of the
> output and so may simply refresh the modes list from the information it
> acquired whilst handling the event. However, the caller may explicitly
> request that any cached information be dropped, and for the output to be
> queried for its current status and modes - under such circumstances
> <parameter>force</parameter> is true.
>   </para>

That looks good to me (I would split this in two paragraphs, but that's just 
nitpicking).

Could you please also update the drm_helper_probe_single_connector_modes() 
description in drm.tmpl ?
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e7e9242..635276c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1537,7 +1537,8 @@  int drm_mode_getconnector(struct drm_device *dev, void *data,
 	if (out_resp->count_modes == 0) {
 		connector->funcs->fill_modes(connector,
 					     dev->mode_config.max_width,
-					     dev->mode_config.max_height);
+					     dev->mode_config.max_height,
+					     true);
 	}
 
 	/* delayed so we get modes regardless of pre-fill_modes state */
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ed1334e..7f2128c 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -96,6 +96,9 @@  static void drm_mode_validate_flag(struct drm_connector *connector,
  * @connector: connector to probe
  * @maxX: max width for modes
  * @maxY: max height for modes
+ * @force: whether to use the cached connector status or to force a
+ *         fresh detection cycle, for instance after a hotplug event, we
+ *         want to simply use the known status.
  *
  * LOCKING:
  * Caller must hold mode config lock.
@@ -113,7 +116,8 @@  static void drm_mode_validate_flag(struct drm_connector *connector,
  * Number of modes found on @connector.
  */
 int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
-					    uint32_t maxX, uint32_t maxY)
+					    uint32_t maxX, uint32_t maxY,
+					    bool force)
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_display_mode *mode;
@@ -136,7 +140,7 @@  int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
 			connector->status = connector_status_disconnected;
 		if (connector->funcs->force)
 			connector->funcs->force(connector);
-	} else {
+	} else if (force) {
 		connector->status = connector->funcs->detect(connector, true);
 	}
 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b78cbe7..3e0802d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1087,8 +1087,8 @@  void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 EXPORT_SYMBOL(drm_fb_helper_fill_var);
 
 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-					       uint32_t maxX,
-					       uint32_t maxY)
+					       uint32_t maxX, uint32_t maxY,
+					       bool force)
 {
 	struct drm_connector *connector;
 	int count = 0;
@@ -1096,7 +1096,7 @@  static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
 
 	for (i = 0; i < fb_helper->connector_count; i++) {
 		connector = fb_helper->connector_info[i]->connector;
-		count += connector->funcs->fill_modes(connector, maxX, maxY);
+		count += connector->funcs->fill_modes(connector, maxX, maxY, force);
 	}
 
 	return count;
@@ -1510,7 +1510,8 @@  bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 
 	count = drm_fb_helper_probe_connector_modes(fb_helper,
 						    dev->mode_config.max_width,
-						    dev->mode_config.max_height);
+						    dev->mode_config.max_height,
+						    true);
 	/*
 	 * we shouldn't end up with no modes here.
 	 */
@@ -1563,8 +1564,9 @@  int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	max_height = fb_helper->fb->height;
 	bpp_sel = fb_helper->fb->bits_per_pixel;
 
-	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
-						    max_height);
+	count = drm_fb_helper_probe_connector_modes(fb_helper,
+						    max_width, max_height,
+						    false);
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
 	drm_modeset_lock_all(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 8bcc13a..48ef16f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -249,7 +249,8 @@  static void exynos_drm_connector_dpms(struct drm_connector *connector,
 }
 
 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-				unsigned int max_width, unsigned int max_height)
+				unsigned int max_width, unsigned int max_height,
+				bool force)
 {
 	struct exynos_drm_connector *exynos_connector =
 					to_exynos_connector(connector);
@@ -267,8 +268,8 @@  static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 	if (ops && ops->get_max_resol)
 		ops->get_max_resol(manager->dev, &width, &height);
 
-	return drm_helper_probe_single_connector_modes(connector, width,
-							height);
+	return drm_helper_probe_single_connector_modes(connector,
+						       width, height, force);
 }
 
 /* get detection status of display device. */
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 51fa323..d18237d 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -355,7 +355,7 @@  static int ch7006_encoder_set_property(struct drm_encoder *encoder,
 	}
 
 	if (modes_changed) {
-		drm_helper_probe_single_connector_modes(connector, 0, 0);
+		drm_helper_probe_single_connector_modes(connector, 0, 0, false);
 
 		/* Disable the crtc to ensure a full modeset is
 		 * performed whenever it's turned on again. */
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index acef48f..535dd14 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -759,7 +759,7 @@  static int nv17_tv_set_property(struct drm_encoder *encoder,
 	}
 
 	if (modes_changed) {
-		drm_helper_probe_single_connector_modes(connector, 0, 0);
+		drm_helper_probe_single_connector_modes(connector, 0, 0, false);
 
 		/* Disable the crtc to ensure a full modeset is
 		 * performed whenever it's turned on again. */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 3e3c7ab..d9a0768 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1924,7 +1924,8 @@  static void vmw_guess_mode_timing(struct drm_display_mode *mode)
 
 
 int vmw_du_connector_fill_modes(struct drm_connector *connector,
-				uint32_t max_width, uint32_t max_height)
+				uint32_t max_width, uint32_t max_height,
+				bool force)
 {
 	struct vmw_display_unit *du = vmw_connector_to_du(connector);
 	struct drm_device *dev = connector->dev;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 6fa89c9..19fc306 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -138,7 +138,8 @@  void vmw_du_connector_restore(struct drm_connector *connector);
 enum drm_connector_status
 vmw_du_connector_detect(struct drm_connector *connector, bool force);
 int vmw_du_connector_fill_modes(struct drm_connector *connector,
-				uint32_t max_width, uint32_t max_height);
+				uint32_t max_width, uint32_t max_height,
+				bool force);
 int vmw_du_connector_set_property(struct drm_connector *connector,
 				  struct drm_property *property,
 				  uint64_t val);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index adb3f9b..373e774 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -468,7 +468,7 @@  struct drm_connector_funcs {
 	 */
 	enum drm_connector_status (*detect)(struct drm_connector *connector,
 					    bool force);
-	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height, bool force);
 	int (*set_property)(struct drm_connector *connector, struct drm_property *property,
 			     uint64_t val);
 	void (*destroy)(struct drm_connector *connector);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index f43d556..cce7221 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -125,7 +125,7 @@  struct drm_connector_helper_funcs {
 	struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
 };
 
-extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
+extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY, bool force);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,