diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hotplug.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_hotplug.c | 131 |
1 files changed, 90 insertions, 41 deletions
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 648a13c6043c..e24174d08fed 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c | |||
@@ -114,51 +114,68 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, | |||
114 | #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) | 114 | #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) |
115 | 115 | ||
116 | /** | 116 | /** |
117 | * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin | 117 | * intel_hpd_irq_storm_detect - gather stats and detect HPD IRQ storm on a pin |
118 | * @dev_priv: private driver data pointer | 118 | * @dev_priv: private driver data pointer |
119 | * @pin: the pin to gather stats on | 119 | * @pin: the pin to gather stats on |
120 | * @long_hpd: whether the HPD IRQ was long or short | ||
120 | * | 121 | * |
121 | * Gather stats about HPD irqs from the specified @pin, and detect irq | 122 | * Gather stats about HPD IRQs from the specified @pin, and detect IRQ |
122 | * storms. Only the pin specific stats and state are changed, the caller is | 123 | * storms. Only the pin specific stats and state are changed, the caller is |
123 | * responsible for further action. | 124 | * responsible for further action. |
124 | * | 125 | * |
125 | * The number of irqs that are allowed within @HPD_STORM_DETECT_PERIOD is | 126 | * The number of IRQs that are allowed within @HPD_STORM_DETECT_PERIOD is |
126 | * stored in @dev_priv->hotplug.hpd_storm_threshold which defaults to | 127 | * stored in @dev_priv->hotplug.hpd_storm_threshold which defaults to |
127 | * @HPD_STORM_DEFAULT_THRESHOLD. If this threshold is exceeded, it's | 128 | * @HPD_STORM_DEFAULT_THRESHOLD. Long IRQs count as +10 to this threshold, and |
128 | * considered an irq storm and the irq state is set to @HPD_MARK_DISABLED. | 129 | * short IRQs count as +1. If this threshold is exceeded, it's considered an |
130 | * IRQ storm and the IRQ state is set to @HPD_MARK_DISABLED. | ||
131 | * | ||
132 | * By default, most systems will only count long IRQs towards | ||
133 | * &dev_priv->hotplug.hpd_storm_threshold. However, some older systems also | ||
134 | * suffer from short IRQ storms and must also track these. Because short IRQ | ||
135 | * storms are naturally caused by sideband interactions with DP MST devices, | ||
136 | * short IRQ detection is only enabled for systems without DP MST support. | ||
137 | * Systems which are new enough to support DP MST are far less likely to | ||
138 | * suffer from IRQ storms at all, so this is fine. | ||
129 | * | 139 | * |
130 | * The HPD threshold can be controlled through i915_hpd_storm_ctl in debugfs, | 140 | * The HPD threshold can be controlled through i915_hpd_storm_ctl in debugfs, |
131 | * and should only be adjusted for automated hotplug testing. | 141 | * and should only be adjusted for automated hotplug testing. |
132 | * | 142 | * |
133 | * Return true if an irq storm was detected on @pin. | 143 | * Return true if an IRQ storm was detected on @pin. |
134 | */ | 144 | */ |
135 | static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, | 145 | static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, |
136 | enum hpd_pin pin) | 146 | enum hpd_pin pin, bool long_hpd) |
137 | { | 147 | { |
138 | unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; | 148 | struct i915_hotplug *hpd = &dev_priv->hotplug; |
149 | unsigned long start = hpd->stats[pin].last_jiffies; | ||
139 | unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); | 150 | unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); |
140 | const int threshold = dev_priv->hotplug.hpd_storm_threshold; | 151 | const int increment = long_hpd ? 10 : 1; |
152 | const int threshold = hpd->hpd_storm_threshold; | ||
141 | bool storm = false; | 153 | bool storm = false; |
142 | 154 | ||
155 | if (!threshold || | ||
156 | (!long_hpd && !dev_priv->hotplug.hpd_short_storm_enabled)) | ||
157 | return false; | ||
158 | |||
143 | if (!time_in_range(jiffies, start, end)) { | 159 | if (!time_in_range(jiffies, start, end)) { |
144 | dev_priv->hotplug.stats[pin].last_jiffies = jiffies; | 160 | hpd->stats[pin].last_jiffies = jiffies; |
145 | dev_priv->hotplug.stats[pin].count = 0; | 161 | hpd->stats[pin].count = 0; |
146 | DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); | 162 | } |
147 | } else if (dev_priv->hotplug.stats[pin].count > threshold && | 163 | |
148 | threshold) { | 164 | hpd->stats[pin].count += increment; |
149 | dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; | 165 | if (hpd->stats[pin].count > threshold) { |
166 | hpd->stats[pin].state = HPD_MARK_DISABLED; | ||
150 | DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); | 167 | DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); |
151 | storm = true; | 168 | storm = true; |
152 | } else { | 169 | } else { |
153 | dev_priv->hotplug.stats[pin].count++; | ||
154 | DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, | 170 | DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, |
155 | dev_priv->hotplug.stats[pin].count); | 171 | hpd->stats[pin].count); |
156 | } | 172 | } |
157 | 173 | ||
158 | return storm; | 174 | return storm; |
159 | } | 175 | } |
160 | 176 | ||
161 | static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) | 177 | static void |
178 | intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) | ||
162 | { | 179 | { |
163 | struct drm_device *dev = &dev_priv->drm; | 180 | struct drm_device *dev = &dev_priv->drm; |
164 | struct intel_connector *intel_connector; | 181 | struct intel_connector *intel_connector; |
@@ -228,7 +245,9 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) | |||
228 | drm_for_each_connector_iter(connector, &conn_iter) { | 245 | drm_for_each_connector_iter(connector, &conn_iter) { |
229 | struct intel_connector *intel_connector = to_intel_connector(connector); | 246 | struct intel_connector *intel_connector = to_intel_connector(connector); |
230 | 247 | ||
231 | if (intel_connector->encoder->hpd_pin == pin) { | 248 | /* Don't check MST ports, they don't have pins */ |
249 | if (!intel_connector->mst_port && | ||
250 | intel_connector->encoder->hpd_pin == pin) { | ||
232 | if (connector->polled != intel_connector->polled) | 251 | if (connector->polled != intel_connector->polled) |
233 | DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", | 252 | DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", |
234 | connector->name); | 253 | connector->name); |
@@ -346,8 +365,8 @@ static void i915_hotplug_work_func(struct work_struct *work) | |||
346 | hpd_event_bits = dev_priv->hotplug.event_bits; | 365 | hpd_event_bits = dev_priv->hotplug.event_bits; |
347 | dev_priv->hotplug.event_bits = 0; | 366 | dev_priv->hotplug.event_bits = 0; |
348 | 367 | ||
349 | /* Disable hotplug on connectors that hit an irq storm. */ | 368 | /* Enable polling for connectors which had HPD IRQ storms */ |
350 | intel_hpd_irq_storm_disable(dev_priv); | 369 | intel_hpd_irq_storm_switch_to_polling(dev_priv); |
351 | 370 | ||
352 | spin_unlock_irq(&dev_priv->irq_lock); | 371 | spin_unlock_irq(&dev_priv->irq_lock); |
353 | 372 | ||
@@ -395,37 +414,54 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, | |||
395 | struct intel_encoder *encoder; | 414 | struct intel_encoder *encoder; |
396 | bool storm_detected = false; | 415 | bool storm_detected = false; |
397 | bool queue_dig = false, queue_hp = false; | 416 | bool queue_dig = false, queue_hp = false; |
417 | u32 long_hpd_pulse_mask = 0; | ||
418 | u32 short_hpd_pulse_mask = 0; | ||
419 | enum hpd_pin pin; | ||
398 | 420 | ||
399 | if (!pin_mask) | 421 | if (!pin_mask) |
400 | return; | 422 | return; |
401 | 423 | ||
402 | spin_lock(&dev_priv->irq_lock); | 424 | spin_lock(&dev_priv->irq_lock); |
425 | |||
426 | /* | ||
427 | * Determine whether ->hpd_pulse() exists for each pin, and | ||
428 | * whether we have a short or a long pulse. This is needed | ||
429 | * as each pin may have up to two encoders (HDMI and DP) and | ||
430 | * only the one of them (DP) will have ->hpd_pulse(). | ||
431 | */ | ||
403 | for_each_intel_encoder(&dev_priv->drm, encoder) { | 432 | for_each_intel_encoder(&dev_priv->drm, encoder) { |
404 | enum hpd_pin pin = encoder->hpd_pin; | ||
405 | bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder); | 433 | bool has_hpd_pulse = intel_encoder_has_hpd_pulse(encoder); |
434 | enum port port = encoder->port; | ||
435 | bool long_hpd; | ||
406 | 436 | ||
437 | pin = encoder->hpd_pin; | ||
407 | if (!(BIT(pin) & pin_mask)) | 438 | if (!(BIT(pin) & pin_mask)) |
408 | continue; | 439 | continue; |
409 | 440 | ||
410 | if (has_hpd_pulse) { | 441 | if (!has_hpd_pulse) |
411 | bool long_hpd = long_mask & BIT(pin); | 442 | continue; |
412 | enum port port = encoder->port; | ||
413 | 443 | ||
414 | DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), | 444 | long_hpd = long_mask & BIT(pin); |
415 | long_hpd ? "long" : "short"); | 445 | |
416 | /* | 446 | DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), |
417 | * For long HPD pulses we want to have the digital queue happen, | 447 | long_hpd ? "long" : "short"); |
418 | * but we still want HPD storm detection to function. | 448 | queue_dig = true; |
419 | */ | 449 | |
420 | queue_dig = true; | 450 | if (long_hpd) { |
421 | if (long_hpd) { | 451 | long_hpd_pulse_mask |= BIT(pin); |
422 | dev_priv->hotplug.long_port_mask |= (1 << port); | 452 | dev_priv->hotplug.long_port_mask |= BIT(port); |
423 | } else { | 453 | } else { |
424 | /* for short HPD just trigger the digital queue */ | 454 | short_hpd_pulse_mask |= BIT(pin); |
425 | dev_priv->hotplug.short_port_mask |= (1 << port); | 455 | dev_priv->hotplug.short_port_mask |= BIT(port); |
426 | continue; | ||
427 | } | ||
428 | } | 456 | } |
457 | } | ||
458 | |||
459 | /* Now process each pin just once */ | ||
460 | for_each_hpd_pin(pin) { | ||
461 | bool long_hpd; | ||
462 | |||
463 | if (!(BIT(pin) & pin_mask)) | ||
464 | continue; | ||
429 | 465 | ||
430 | if (dev_priv->hotplug.stats[pin].state == HPD_DISABLED) { | 466 | if (dev_priv->hotplug.stats[pin].state == HPD_DISABLED) { |
431 | /* | 467 | /* |
@@ -442,17 +478,30 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, | |||
442 | if (dev_priv->hotplug.stats[pin].state != HPD_ENABLED) | 478 | if (dev_priv->hotplug.stats[pin].state != HPD_ENABLED) |
443 | continue; | 479 | continue; |
444 | 480 | ||
445 | if (!has_hpd_pulse) { | 481 | /* |
482 | * Delegate to ->hpd_pulse() if one of the encoders for this | ||
483 | * pin has it, otherwise let the hotplug_work deal with this | ||
484 | * pin directly. | ||
485 | */ | ||
486 | if (((short_hpd_pulse_mask | long_hpd_pulse_mask) & BIT(pin))) { | ||
487 | long_hpd = long_hpd_pulse_mask & BIT(pin); | ||
488 | } else { | ||
446 | dev_priv->hotplug.event_bits |= BIT(pin); | 489 | dev_priv->hotplug.event_bits |= BIT(pin); |
490 | long_hpd = true; | ||
447 | queue_hp = true; | 491 | queue_hp = true; |
448 | } | 492 | } |
449 | 493 | ||
450 | if (intel_hpd_irq_storm_detect(dev_priv, pin)) { | 494 | if (intel_hpd_irq_storm_detect(dev_priv, pin, long_hpd)) { |
451 | dev_priv->hotplug.event_bits &= ~BIT(pin); | 495 | dev_priv->hotplug.event_bits &= ~BIT(pin); |
452 | storm_detected = true; | 496 | storm_detected = true; |
497 | queue_hp = true; | ||
453 | } | 498 | } |
454 | } | 499 | } |
455 | 500 | ||
501 | /* | ||
502 | * Disable any IRQs that storms were detected on. Polling enablement | ||
503 | * happens later in our hotplug work. | ||
504 | */ | ||
456 | if (storm_detected && dev_priv->display_irqs_enabled) | 505 | if (storm_detected && dev_priv->display_irqs_enabled) |
457 | dev_priv->display.hpd_irq_setup(dev_priv); | 506 | dev_priv->display.hpd_irq_setup(dev_priv); |
458 | spin_unlock(&dev_priv->irq_lock); | 507 | spin_unlock(&dev_priv->irq_lock); |