drm/i915: don't set modes for 2 connectors on the same encoder
authorPaulo Zanoni <paulo.r.zanoni@intel.com>
Tue, 7 Jan 2014 16:55:53 +0000 (14:55 -0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 10 Jan 2014 16:56:39 +0000 (17:56 +0100)
In some cases we have more than 1 connector associated to an encoder
(e.g., SDVO, Haswell DP/HDMI) and we can only set a mode for one of
these connectors. If we only allowed modesets for connected connectors
we would never need this patch, but since we do allow modeset for
disconnected connectors we may see user space trying to set modes on
the two connectors attached to the same encoder, so we need to forbid
that.

This problem can be reproduced by running the following
intel-gpu-tools test case:
  ./kms_setmode --run-subtest clone-exclusive-crtc

Thanks to Daniel Vetter for providing a version of this patch on
pastebin.

Credits-to: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_display.c

index c4d3f439168625bfe634f521f9b133c7ff9392a9..507fb19c75911041f08ff57227be10dee81bb800 100644 (file)
@@ -9923,17 +9923,21 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        /* Check for any encoders that needs to be disabled. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                            base.head) {
+               int num_connectors = 0;
                list_for_each_entry(connector,
                                    &dev->mode_config.connector_list,
                                    base.head) {
                        if (connector->new_encoder == encoder) {
                                WARN_ON(!connector->new_encoder->new_crtc);
-
-                               goto next_encoder;
+                               num_connectors++;
                        }
                }
-               encoder->new_crtc = NULL;
-next_encoder:
+
+               if (num_connectors == 0)
+                       encoder->new_crtc = NULL;
+               else if (num_connectors > 1)
+                       return -EINVAL;
+
                /* Only now check for crtc changes so we don't miss encoders
                 * that will be disabled. */
                if (&encoder->new_crtc->base != encoder->base.crtc) {