diff mbox

drm/i915: Allow DBLSCAN user modes with eDP/LVDS/DSI

Message ID 20180524125403.23445-1-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ville Syrjälä May 24, 2018, 12:54 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

When encountering a connector with the scaling mode property both
intel and modesetting ddxs sometimes add tons of DBLSCAN modes
to the output's mode list. The idea presumably being that since the
output will be going through the panel fitter anyway we can pretend
to use any kind of mode.

Sadly that means we can't reject user modes with the DBLSCAN flag
until we know whether we're going to be using the panel's native
mode or the user mode directly. Doing otherwise means X clients using
xf86vidmode/xrandr will get a protocol error (and often self
terminate as a result) when the kernel refuses to use the requested
mode with the DBLSCAN flag.

To undo the regression we'll move the DBLSCAN checks into the
connector->mode_valid() and encoder->compute_config() hooks.

Cc: Vito Caputo <vcaputo@pengaru.com>
Reported-by: Vito Caputo <vcaputo@pengaru.com>
Fixes: e995ca0b8139 ("drm/i915: Provide a device level .mode_valid() hook")
References: https://lkml.org/lkml/2018/5/21/715
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_crt.c     | 20 ++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++---
 drivers/gpu/drm/i915/intel_dp.c      |  6 ++++++
 drivers/gpu/drm/i915/intel_dp_mst.c  |  6 ++++++
 drivers/gpu/drm/i915/intel_dsi.c     |  6 ++++++
 drivers/gpu/drm/i915/intel_dvo.c     |  6 ++++++
 drivers/gpu/drm/i915/intel_hdmi.c    |  6 ++++++
 drivers/gpu/drm/i915/intel_lvds.c    |  5 +++++
 drivers/gpu/drm/i915/intel_sdvo.c    |  6 ++++++
 drivers/gpu/drm/i915/intel_tv.c      | 12 ++++++++++--
 10 files changed, 84 insertions(+), 5 deletions(-)

Comments

Maarten Lankhorst June 13, 2018, 2:48 p.m. UTC | #1
Op 24-05-18 om 14:54 schreef Ville Syrjala:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> When encountering a connector with the scaling mode property both
> intel and modesetting ddxs sometimes add tons of DBLSCAN modes
> to the output's mode list. The idea presumably being that since the
> output will be going through the panel fitter anyway we can pretend
> to use any kind of mode.
>
> Sadly that means we can't reject user modes with the DBLSCAN flag
> until we know whether we're going to be using the panel's native
> mode or the user mode directly. Doing otherwise means X clients using
> xf86vidmode/xrandr will get a protocol error (and often self
> terminate as a result) when the kernel refuses to use the requested
> mode with the DBLSCAN flag.
>
> To undo the regression we'll move the DBLSCAN checks into the
> connector->mode_valid() and encoder->compute_config() hooks.
>
> Cc: Vito Caputo <vcaputo@pengaru.com>
> Reported-by: Vito Caputo <vcaputo@pengaru.com>
> Fixes: e995ca0b8139 ("drm/i915: Provide a device level .mode_valid() hook")
> References: https://lkml.org/lkml/2018/5/21/715
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_crt.c     | 20 ++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++---
>  drivers/gpu/drm/i915/intel_dp.c      |  6 ++++++
>  drivers/gpu/drm/i915/intel_dp_mst.c  |  6 ++++++
>  drivers/gpu/drm/i915/intel_dsi.c     |  6 ++++++
>  drivers/gpu/drm/i915/intel_dvo.c     |  6 ++++++
>  drivers/gpu/drm/i915/intel_hdmi.c    |  6 ++++++
>  drivers/gpu/drm/i915/intel_lvds.c    |  5 +++++
>  drivers/gpu/drm/i915/intel_sdvo.c    |  6 ++++++
>  drivers/gpu/drm/i915/intel_tv.c      | 12 ++++++++++--
>  10 files changed, 84 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
> index 211d601cd1b1..95aa29cf2d9c 100644
> --- a/drivers/gpu/drm/i915/intel_crt.c
> +++ b/drivers/gpu/drm/i915/intel_crt.c
> @@ -304,6 +304,9 @@ intel_crt_mode_valid(struct drm_connector *connector,
>  	int max_dotclk = dev_priv->max_dotclk_freq;
>  	int max_clock;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	if (mode->clock < 25000)
>  		return MODE_CLOCK_LOW;
>  
> @@ -337,6 +340,12 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
>  				     struct intel_crtc_state *pipe_config,
>  				     struct drm_connector_state *conn_state)
>  {
> +	struct drm_display_mode *adjusted_mode =
> +		&pipe_config->base.adjusted_mode;
> +
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	return true;
>  }
>  
> @@ -344,6 +353,12 @@ static bool pch_crt_compute_config(struct intel_encoder *encoder,
>  				   struct intel_crtc_state *pipe_config,
>  				   struct drm_connector_state *conn_state)
>  {
> +	struct drm_display_mode *adjusted_mode =
> +		&pipe_config->base.adjusted_mode;
> +
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	pipe_config->has_pch_encoder = true;
>  
>  	return true;
> @@ -354,6 +369,11 @@ static bool hsw_crt_compute_config(struct intel_encoder *encoder,
>  				   struct drm_connector_state *conn_state)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct drm_display_mode *adjusted_mode =
> +		&pipe_config->base.adjusted_mode;
> +
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
>  
>  	pipe_config->has_pch_encoder = true;
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 8b385176ce3c..02651298a99b 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -14443,12 +14443,22 @@ static enum drm_mode_status
>  intel_mode_valid(struct drm_device *dev,
>  		 const struct drm_display_mode *mode)
>  {
> +	/*
> +	 * Can't reject DBLSCAN here because Xorg ddxen can add piles
> +	 * of DBLSCAN modes to the output's mode list when they detect
> +	 * the scaling mode property on the connector. And they don't
> +	 * ask the kernel to validate those modes in any way until
> +	 * modeset time at which point the client gets a protocol error.
> +	 * So in order to not upset those clients we silently ignore the
> +	 * DBLSCAN flag on such connectors. For other connectors we will
> +	 * reject modes with the DBLSCAN flag in encoder->compute_config().
> +	 * And we always reject DBLSCAN modes in connector->mode_valid()
> +	 * as we never want such modes on the connector's mode list.
> +	 */
> +
>  	if (mode->vscan > 1)
>  		return MODE_NO_VSCAN;
>  
> -	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> -		return MODE_NO_DBLESCAN;
> -
>  	if (mode->flags & DRM_MODE_FLAG_HSKEW)
>  		return MODE_H_ILLEGAL;
>  
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index ce07bd794aed..91885f2500af 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -420,6 +420,9 @@ intel_dp_mode_valid(struct drm_connector *connector,
>  	int max_rate, mode_rate, max_lanes, max_link_clock;
>  	int max_dotclk;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
>  
>  	if (intel_dp_is_edp(intel_dp) && fixed_mode) {
> @@ -1862,6 +1865,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  						conn_state->scaling_mode);
>  	}
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
>  	    adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
>  		return false;
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 9e6956c08688..5890500a3a8b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -48,6 +48,9 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  	bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
>  					   DP_DPCD_QUIRK_LIMITED_M_N);
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	pipe_config->has_pch_encoder = false;
>  	bpp = 24;
>  	if (intel_dp->compliance.test_data.bpc) {
> @@ -366,6 +369,9 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
>  	if (!intel_dp)
>  		return MODE_ERROR;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	max_link_clock = intel_dp_max_link_rate(intel_dp);
>  	max_lanes = intel_dp_max_lane_count(intel_dp);
>  
> diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
> index cf39ca90d887..f349b3920199 100644
> --- a/drivers/gpu/drm/i915/intel_dsi.c
> +++ b/drivers/gpu/drm/i915/intel_dsi.c
> @@ -326,6 +326,9 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
>  						conn_state->scaling_mode);
>  	}
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	/* DSI uses short packets for sync events, so clear mode flags for DSI */
>  	adjusted_mode->flags = 0;
>  
> @@ -1266,6 +1269,9 @@ intel_dsi_mode_valid(struct drm_connector *connector,
>  
>  	DRM_DEBUG_KMS("\n");
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	if (fixed_mode) {
>  		if (mode->hdisplay > fixed_mode->hdisplay)
>  			return MODE_PANEL;
> diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
> index 7b942b6c1700..27f16db8953a 100644
> --- a/drivers/gpu/drm/i915/intel_dvo.c
> +++ b/drivers/gpu/drm/i915/intel_dvo.c
> @@ -215,6 +215,9 @@ intel_dvo_mode_valid(struct drm_connector *connector,
>  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
>  	int target_clock = mode->clock;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	/* XXX: Validate clock range */
>  
>  	if (fixed_mode) {
> @@ -250,6 +253,9 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
>  	if (fixed_mode)
>  		intel_fixed_panel_mode(fixed_mode, adjusted_mode);
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	return true;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 0ca4cc877520..47e6cca3e208 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -1544,6 +1544,9 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
>  	bool force_dvi =
>  		READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	clock = mode->clock;
>  
>  	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
> @@ -1664,6 +1667,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
>  	int desired_bpp;
>  	bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
>  
>  	if (pipe_config->has_hdmi_sink)
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
> index bacad88ad7ae..5b4a35299531 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -378,6 +378,8 @@ intel_lvds_mode_valid(struct drm_connector *connector,
>  	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
>  	int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
>  	if (mode->hdisplay > fixed_mode->hdisplay)
>  		return MODE_PANEL;
>  	if (mode->vdisplay > fixed_mode->vdisplay)
> @@ -427,6 +429,9 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
>  	intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
>  			       adjusted_mode);
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	if (HAS_PCH_SPLIT(dev_priv)) {
>  		pipe_config->has_pch_encoder = true;
>  
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index a02e4d73c7a4..e6a64b3ecd91 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -1160,6 +1160,9 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
>  							   adjusted_mode);
>  	}
>  
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
>  	/*
>  	 * Make the CRTC code factor in the SDVO pixel multiplier.  The
>  	 * SDVO device will factor out the multiplier during mode_set.
> @@ -1631,6 +1634,9 @@ intel_sdvo_mode_valid(struct drm_connector *connector,
>  	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
>  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	if (intel_sdvo->pixel_clock_min > mode->clock)
>  		return MODE_CLOCK_LOW;
>  
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 99bc2368dda0..24dc368fdaa1 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -846,6 +846,9 @@ intel_tv_mode_valid(struct drm_connector *connector,
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
>  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
>  
> +	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return MODE_NO_DBLESCAN;
> +
>  	if (mode->clock > max_dotclk)
>  		return MODE_CLOCK_HIGH;
>  
> @@ -873,16 +876,21 @@ intel_tv_compute_config(struct intel_encoder *encoder,
>  			struct drm_connector_state *conn_state)
>  {
>  	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
> +	struct drm_display_mode *adjusted_mode =
> +		&pipe_config->base.adjusted_mode;
>  
>  	if (!tv_mode)
>  		return false;
>  
> -	pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
> +	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
> +		return false;
> +
> +	adjusted_mode->crtc_clock = tv_mode->clock;
>  	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
>  	pipe_config->pipe_bpp = 8*3;
>  
>  	/* TV has it's own notion of sync and other mode flags, so clear them. */
> -	pipe_config->base.adjusted_mode.flags = 0;
> +	adjusted_mode->flags = 0;
>  
>  	/*
>  	 * FIXME: We don't check whether the input mode is actually what we want


Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Ville Syrjälä June 13, 2018, 5:56 p.m. UTC | #2
On Thu, May 24, 2018 at 04:30:10PM -0000, Patchwork wrote:
> == Series Details ==
> 
> Series: drm/i915: Allow DBLSCAN user modes with eDP/LVDS/DSI
> URL   : https://patchwork.freedesktop.org/series/43698/
> State : failure
> 
> == Summary ==
> 
> = CI Bug Log - changes from CI_DRM_4230_full -> Patchwork_9104_full =
> 
> == Summary - FAILURE ==
> 
>   Serious unknown changes coming with Patchwork_9104_full absolutely need to be
>   verified manually.
>   
>   If you think the reported changes have nothing to do with the changes
>   introduced in Patchwork_9104_full, please notify your bug team to allow them
>   to document this new failure mode, which will reduce false positives in CI.
> 
>   External URL: https://patchwork.freedesktop.org/api/1.0/series/43698/revisions/1/mbox/
> 
> == Possible new issues ==
> 
>   Here are the unknown changes that may have been introduced in Patchwork_9104_full:
> 
>   === IGT changes ===
> 
>     ==== Possible regressions ====
> 
>     igt@drv_selftest@live_gtt:
>       shard-kbl:          PASS -> FAIL

Selftest blew up for some reason:
<4>[  177.975101] RIP: 0010:i915_vma_destroy+0x1fd/0x410 [i915]
...
<4>[  177.975202]  __igt_write_huge+0xf7/0x2d0 [i915]

> 
>     
>     ==== Warnings ====
> 
>     igt@gem_exec_schedule@deep-bsd1:
>       shard-kbl:          SKIP -> PASS
> 
>     igt@pm_rc6_residency@rc6-accuracy:
>       shard-snb:          PASS -> SKIP

Test requirement not met in function __real_main198, file
../tests/pm_rc6_residency.c:217:
Test requirement: wait_for_rc6()
Subtest rc6-accuracy: SKIP

meh

> 
>     
> == Known issues ==
> 
>   Here are the changes found in Patchwork_9104_full that come from known issues:
> 
>   === IGT changes ===
> 
>     ==== Issues hit ====
> 
>     igt@drv_selftest@live_hugepages:
>       shard-kbl:          PASS -> INCOMPLETE (fdo#103665)
> 
>     igt@kms_atomic_transition@1x-modeset-transitions-nonblocking-fencing:
>       shard-glk:          PASS -> FAIL (fdo#105703)
> 
>     igt@kms_flip@2x-dpms-vs-vblank-race-interruptible:
>       shard-hsw:          PASS -> FAIL (fdo#103060)
> 
>     igt@kms_flip@plain-flip-fb-recreate:
>       shard-glk:          PASS -> FAIL (fdo#100368)
> 
>     igt@kms_setmode@basic:
>       shard-apl:          PASS -> FAIL (fdo#99912)
> 
>     igt@perf_pmu@busy-double-start-vcs0:
>       shard-snb:          PASS -> FAIL (fdo#105106)
> 
>     
>     ==== Possible fixes ====
> 
>     igt@drv_selftest@live_gtt:
>       shard-glk:          INCOMPLETE (fdo#103359, k.org#198133) -> PASS
> 
>     igt@drv_selftest@live_hangcheck:
>       shard-apl:          DMESG-FAIL (fdo#106560) -> PASS
> 
>     igt@gem_ppgtt@blt-vs-render-ctx0:
>       shard-kbl:          INCOMPLETE (fdo#106023, fdo#103665) -> PASS
> 
>     igt@kms_atomic_transition@1x-modeset-transitions-nonblocking:
>       shard-glk:          FAIL (fdo#105703) -> PASS
> 
>     igt@kms_flip@2x-flip-vs-expired-vblank:
>       shard-hsw:          FAIL (fdo#102887) -> PASS
> 
>     igt@kms_flip@2x-plain-flip-fb-recreate:
>       shard-glk:          FAIL (fdo#100368) -> PASS
> 
>     igt@kms_flip@flip-vs-expired-vblank-interruptible:
>       shard-glk:          FAIL (fdo#102887, fdo#105363) -> PASS
> 
>     igt@kms_flip@modeset-vs-vblank-race-interruptible:
>       shard-hsw:          FAIL (fdo#103060) -> PASS
> 
>     igt@kms_flip_tiling@flip-x-tiled:
>       shard-glk:          FAIL (fdo#104724) -> PASS
> 
>     igt@pm_rpm@modeset-non-lpsp-stress:
>       shard-hsw:          DMESG-WARN (fdo#102614) -> PASS
> 
>     
>   fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
>   fdo#102614 https://bugs.freedesktop.org/show_bug.cgi?id=102614
>   fdo#102887 https://bugs.freedesktop.org/show_bug.cgi?id=102887
>   fdo#103060 https://bugs.freedesktop.org/show_bug.cgi?id=103060
>   fdo#103359 https://bugs.freedesktop.org/show_bug.cgi?id=103359
>   fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
>   fdo#104724 https://bugs.freedesktop.org/show_bug.cgi?id=104724
>   fdo#105106 https://bugs.freedesktop.org/show_bug.cgi?id=105106
>   fdo#105363 https://bugs.freedesktop.org/show_bug.cgi?id=105363
>   fdo#105703 https://bugs.freedesktop.org/show_bug.cgi?id=105703
>   fdo#106023 https://bugs.freedesktop.org/show_bug.cgi?id=106023
>   fdo#106560 https://bugs.freedesktop.org/show_bug.cgi?id=106560
>   fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912
>   k.org#198133 https://bugzilla.kernel.org/show_bug.cgi?id=198133
> 
> 
> == Participating hosts (5 -> 5) ==
> 
>   No changes in participating hosts
> 
> 
> == Build changes ==
> 
>     * Linux: CI_DRM_4230 -> Patchwork_9104
> 
>   CI_DRM_4230: 097c5e2d7cf300d1f9855a550bfdd5150410ffc4 @ git://anongit.freedesktop.org/gfx-ci/linux
>   IGT_4498: f9ecb79ad8b02278cfdb5b82495df47061c04f8f @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
>   Patchwork_9104: 82368323f7e2a1fbe3822bd2da4e1860f8ca418d @ git://anongit.freedesktop.org/gfx-ci/linux
> 
> == Logs ==
> 
> For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_9104/shards.html
Ville Syrjälä June 13, 2018, 6:11 p.m. UTC | #3
On Wed, Jun 13, 2018 at 04:48:29PM +0200, Maarten Lankhorst wrote:
> Op 24-05-18 om 14:54 schreef Ville Syrjala:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > When encountering a connector with the scaling mode property both
> > intel and modesetting ddxs sometimes add tons of DBLSCAN modes
> > to the output's mode list. The idea presumably being that since the
> > output will be going through the panel fitter anyway we can pretend
> > to use any kind of mode.
> >
> > Sadly that means we can't reject user modes with the DBLSCAN flag
> > until we know whether we're going to be using the panel's native
> > mode or the user mode directly. Doing otherwise means X clients using
> > xf86vidmode/xrandr will get a protocol error (and often self
> > terminate as a result) when the kernel refuses to use the requested
> > mode with the DBLSCAN flag.
> >
> > To undo the regression we'll move the DBLSCAN checks into the
> > connector->mode_valid() and encoder->compute_config() hooks.
> >
> > Cc: Vito Caputo <vcaputo@pengaru.com>
> > Reported-by: Vito Caputo <vcaputo@pengaru.com>
> > Fixes: e995ca0b8139 ("drm/i915: Provide a device level .mode_valid() hook")
> > References: https://lkml.org/lkml/2018/5/21/715
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
<snip> 
> 
> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>

Thanks. Pushed to dinq with
Cc: stable@vger.kernel.org
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106804
Tested-by: Arkadiusz Miskiewicz <arekm@maven.pl>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 211d601cd1b1..95aa29cf2d9c 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -304,6 +304,9 @@  intel_crt_mode_valid(struct drm_connector *connector,
 	int max_dotclk = dev_priv->max_dotclk_freq;
 	int max_clock;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	if (mode->clock < 25000)
 		return MODE_CLOCK_LOW;
 
@@ -337,6 +340,12 @@  static bool intel_crt_compute_config(struct intel_encoder *encoder,
 				     struct intel_crtc_state *pipe_config,
 				     struct drm_connector_state *conn_state)
 {
+	struct drm_display_mode *adjusted_mode =
+		&pipe_config->base.adjusted_mode;
+
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	return true;
 }
 
@@ -344,6 +353,12 @@  static bool pch_crt_compute_config(struct intel_encoder *encoder,
 				   struct intel_crtc_state *pipe_config,
 				   struct drm_connector_state *conn_state)
 {
+	struct drm_display_mode *adjusted_mode =
+		&pipe_config->base.adjusted_mode;
+
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	pipe_config->has_pch_encoder = true;
 
 	return true;
@@ -354,6 +369,11 @@  static bool hsw_crt_compute_config(struct intel_encoder *encoder,
 				   struct drm_connector_state *conn_state)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct drm_display_mode *adjusted_mode =
+		&pipe_config->base.adjusted_mode;
+
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
 
 	pipe_config->has_pch_encoder = true;
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8b385176ce3c..02651298a99b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14443,12 +14443,22 @@  static enum drm_mode_status
 intel_mode_valid(struct drm_device *dev,
 		 const struct drm_display_mode *mode)
 {
+	/*
+	 * Can't reject DBLSCAN here because Xorg ddxen can add piles
+	 * of DBLSCAN modes to the output's mode list when they detect
+	 * the scaling mode property on the connector. And they don't
+	 * ask the kernel to validate those modes in any way until
+	 * modeset time at which point the client gets a protocol error.
+	 * So in order to not upset those clients we silently ignore the
+	 * DBLSCAN flag on such connectors. For other connectors we will
+	 * reject modes with the DBLSCAN flag in encoder->compute_config().
+	 * And we always reject DBLSCAN modes in connector->mode_valid()
+	 * as we never want such modes on the connector's mode list.
+	 */
+
 	if (mode->vscan > 1)
 		return MODE_NO_VSCAN;
 
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		return MODE_NO_DBLESCAN;
-
 	if (mode->flags & DRM_MODE_FLAG_HSKEW)
 		return MODE_H_ILLEGAL;
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index ce07bd794aed..91885f2500af 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -420,6 +420,9 @@  intel_dp_mode_valid(struct drm_connector *connector,
 	int max_rate, mode_rate, max_lanes, max_link_clock;
 	int max_dotclk;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
 
 	if (intel_dp_is_edp(intel_dp) && fixed_mode) {
@@ -1862,6 +1865,9 @@  intel_dp_compute_config(struct intel_encoder *encoder,
 						conn_state->scaling_mode);
 	}
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
 	    adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
 		return false;
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 9e6956c08688..5890500a3a8b 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -48,6 +48,9 @@  static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 	bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
 					   DP_DPCD_QUIRK_LIMITED_M_N);
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	pipe_config->has_pch_encoder = false;
 	bpp = 24;
 	if (intel_dp->compliance.test_data.bpc) {
@@ -366,6 +369,9 @@  intel_dp_mst_mode_valid(struct drm_connector *connector,
 	if (!intel_dp)
 		return MODE_ERROR;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index cf39ca90d887..f349b3920199 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -326,6 +326,9 @@  static bool intel_dsi_compute_config(struct intel_encoder *encoder,
 						conn_state->scaling_mode);
 	}
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	/* DSI uses short packets for sync events, so clear mode flags for DSI */
 	adjusted_mode->flags = 0;
 
@@ -1266,6 +1269,9 @@  intel_dsi_mode_valid(struct drm_connector *connector,
 
 	DRM_DEBUG_KMS("\n");
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	if (fixed_mode) {
 		if (mode->hdisplay > fixed_mode->hdisplay)
 			return MODE_PANEL;
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 7b942b6c1700..27f16db8953a 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -215,6 +215,9 @@  intel_dvo_mode_valid(struct drm_connector *connector,
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 	int target_clock = mode->clock;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	/* XXX: Validate clock range */
 
 	if (fixed_mode) {
@@ -250,6 +253,9 @@  static bool intel_dvo_compute_config(struct intel_encoder *encoder,
 	if (fixed_mode)
 		intel_fixed_panel_mode(fixed_mode, adjusted_mode);
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 0ca4cc877520..47e6cca3e208 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1544,6 +1544,9 @@  intel_hdmi_mode_valid(struct drm_connector *connector,
 	bool force_dvi =
 		READ_ONCE(to_intel_digital_connector_state(connector->state)->force_audio) == HDMI_AUDIO_OFF_DVI;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	clock = mode->clock;
 
 	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
@@ -1664,6 +1667,9 @@  bool intel_hdmi_compute_config(struct intel_encoder *encoder,
 	int desired_bpp;
 	bool force_dvi = intel_conn_state->force_audio == HDMI_AUDIO_OFF_DVI;
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	pipe_config->has_hdmi_sink = !force_dvi && intel_hdmi->has_hdmi_sink;
 
 	if (pipe_config->has_hdmi_sink)
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index bacad88ad7ae..5b4a35299531 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -378,6 +378,8 @@  intel_lvds_mode_valid(struct drm_connector *connector,
 	struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
 	int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
 	if (mode->hdisplay > fixed_mode->hdisplay)
 		return MODE_PANEL;
 	if (mode->vdisplay > fixed_mode->vdisplay)
@@ -427,6 +429,9 @@  static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
 	intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
 			       adjusted_mode);
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	if (HAS_PCH_SPLIT(dev_priv)) {
 		pipe_config->has_pch_encoder = true;
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index a02e4d73c7a4..e6a64b3ecd91 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1160,6 +1160,9 @@  static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 							   adjusted_mode);
 	}
 
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
 	/*
 	 * Make the CRTC code factor in the SDVO pixel multiplier.  The
 	 * SDVO device will factor out the multiplier during mode_set.
@@ -1631,6 +1634,9 @@  intel_sdvo_mode_valid(struct drm_connector *connector,
 	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	if (intel_sdvo->pixel_clock_min > mode->clock)
 		return MODE_CLOCK_LOW;
 
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 99bc2368dda0..24dc368fdaa1 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -846,6 +846,9 @@  intel_tv_mode_valid(struct drm_connector *connector,
 	const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
 
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
 	if (mode->clock > max_dotclk)
 		return MODE_CLOCK_HIGH;
 
@@ -873,16 +876,21 @@  intel_tv_compute_config(struct intel_encoder *encoder,
 			struct drm_connector_state *conn_state)
 {
 	const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
+	struct drm_display_mode *adjusted_mode =
+		&pipe_config->base.adjusted_mode;
 
 	if (!tv_mode)
 		return false;
 
-	pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
+	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return false;
+
+	adjusted_mode->crtc_clock = tv_mode->clock;
 	DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
 	pipe_config->pipe_bpp = 8*3;
 
 	/* TV has it's own notion of sync and other mode flags, so clear them. */
-	pipe_config->base.adjusted_mode.flags = 0;
+	adjusted_mode->flags = 0;
 
 	/*
 	 * FIXME: We don't check whether the input mode is actually what we want