drm/i915: Fix hpd handling for pins with two encoders
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_hotplug.c
index 648a13c6043c0071ddd495424691d795b39b96a1..9a801813023728e2e0a05bb5feba1f8415eb3269 100644 (file)
@@ -228,7 +228,9 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
                drm_for_each_connector_iter(connector, &conn_iter) {
                        struct intel_connector *intel_connector = to_intel_connector(connector);
 
-                       if (intel_connector->encoder->hpd_pin == pin) {
+                       /* Don't check MST ports, they don't have pins */
+                       if (!intel_connector->mst_port &&
+                           intel_connector->encoder->hpd_pin == pin) {
                                if (connector->polled != intel_connector->polled)
                                        DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n",
                                                         connector->name);
@@ -395,37 +397,54 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
        struct intel_encoder *encoder;
        bool storm_detected = false;
        bool queue_dig = false, queue_hp = false;
+       u32 long_hpd_pulse_mask = 0;
+       u32 short_hpd_pulse_mask = 0;
+       enum hpd_pin pin;
 
        if (!pin_mask)
                return;
 
        spin_lock(&dev_priv->irq_lock);
+
+       /*
+        * Determine whether ->hpd_pulse() exists for each pin, and
+        * whether we have a short or a long pulse. This is needed
+        * as each pin may have up to two encoders (HDMI and DP) and
+        * only the one of them (DP) will have ->hpd_pulse().
+        */
        for_each_intel_encoder(&dev_priv->drm, encoder) {
-               enum hpd_pin pin = encoder->hpd_pin;
                bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder);
+               enum port port = encoder->port;
+               bool long_hpd;
 
+               pin = encoder->hpd_pin;
                if (!(BIT(pin) & pin_mask))
                        continue;
 
-               if (has_hpd_pulse) {
-                       bool long_hpd = long_mask & BIT(pin);
-                       enum port port = encoder->port;
+               if (!has_hpd_pulse)
+                       continue;
 
-                       DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port),
-                                        long_hpd ? "long" : "short");
-                       /*
-                        * For long HPD pulses we want to have the digital queue happen,
-                        * but we still want HPD storm detection to function.
-                        */
-                       queue_dig = true;
-                       if (long_hpd) {
-                               dev_priv->hotplug.long_port_mask |= (1 << port);
-                       } else {
-                               /* for short HPD just trigger the digital queue */
-                               dev_priv->hotplug.short_port_mask |= (1 << port);
-                               continue;
-                       }
+               long_hpd = long_mask & BIT(pin);
+
+               DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port),
+                                long_hpd ? "long" : "short");
+               queue_dig = true;
+
+               if (long_hpd) {
+                       long_hpd_pulse_mask |= BIT(pin);
+                       dev_priv->hotplug.long_port_mask |= BIT(port);
+               } else {
+                       short_hpd_pulse_mask |= BIT(pin);
+                       dev_priv->hotplug.short_port_mask |= BIT(port);
                }
+       }
+
+       /* Now process each pin just once */
+       for_each_hpd_pin(pin) {
+               bool long_hpd;
+
+               if (!(BIT(pin) & pin_mask))
+                       continue;
 
                if (dev_priv->hotplug.stats[pin].state == HPD_DISABLED) {
                        /*
@@ -442,11 +461,22 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv,
                if (dev_priv->hotplug.stats[pin].state != HPD_ENABLED)
                        continue;
 
-               if (!has_hpd_pulse) {
+               /*
+                * Delegate to ->hpd_pulse() if one of the encoders for this
+                * pin has it, otherwise let the hotplug_work deal with this
+                * pin directly.
+                */
+               if (((short_hpd_pulse_mask | long_hpd_pulse_mask) & BIT(pin))) {
+                       long_hpd = long_hpd_pulse_mask & BIT(pin);
+               } else {
                        dev_priv->hotplug.event_bits |= BIT(pin);
+                       long_hpd = true;
                        queue_hp = true;
                }
 
+               if (!long_hpd)
+                       continue;
+
                if (intel_hpd_irq_storm_detect(dev_priv, pin)) {
                        dev_priv->hotplug.event_bits &= ~BIT(pin);
                        storm_detected = true;