]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
drm/i915/sdvo: clean up connectors on intel_sdvo_init() failures
authorJani Nikula <jani.nikula@intel.com>
Mon, 12 Nov 2012 16:31:35 +0000 (18:31 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 26 Nov 2012 20:14:17 +0000 (12:14 -0800)
commit d0ddfbd3d1346c1f481ec2289eef350cdba64b42 upstream.

Any failures in intel_sdvo_init() after the intel_sdvo_setup_output() call
left behind ghost connectors, attached (with a dangling pointer) to the
sdvo that has been cleaned up and freed. Properly destroy any connectors
attached to the encoder.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=46381
CC: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Tested-by: bjo@nord-west.org
[danvet: added a comment to explain why we need to clean up connectors
even when sdvo_output_setup fails.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/i915/intel_sdvo.c

index 20cb52dfcb5a066225c4461428a0c4fa60f58dc2..d554f647613763605e59cb7b3c6431acc3e9e105 100644 (file)
@@ -2287,6 +2287,18 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
        return true;
 }
 
+static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
+{
+       struct drm_device *dev = intel_sdvo->base.base.dev;
+       struct drm_connector *connector, *tmp;
+
+       list_for_each_entry_safe(connector, tmp,
+                                &dev->mode_config.connector_list, head) {
+               if (intel_attached_encoder(connector) == &intel_sdvo->base)
+                       intel_sdvo_destroy(connector);
+       }
+}
+
 static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
                                          struct intel_sdvo_connector *intel_sdvo_connector,
                                          int type)
@@ -2606,7 +2618,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
                                    intel_sdvo->caps.output_flags) != true) {
                DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
                              SDVO_NAME(intel_sdvo));
-               goto err;
+               /* Output_setup can leave behind connectors! */
+               goto err_output;
        }
 
        /* Only enable the hotplug irq if we need it, to work around noisy
@@ -2619,12 +2632,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 
        /* Set the input timing to the screen. Assume always input 0. */
        if (!intel_sdvo_set_target_input(intel_sdvo))
-               goto err;
+               goto err_output;
 
        if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
                                                    &intel_sdvo->pixel_clock_min,
                                                    &intel_sdvo->pixel_clock_max))
-               goto err;
+               goto err_output;
 
        DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
                        "clock range %dMHz - %dMHz, "
@@ -2644,6 +2657,9 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
                        (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
        return true;
 
+err_output:
+       intel_sdvo_output_cleanup(intel_sdvo);
+
 err:
        drm_encoder_cleanup(&intel_encoder->base);
        i2c_del_adapter(&intel_sdvo->ddc);