diff options
author | 2019-05-10 11:43:46 -0700 | |
---|---|---|
committer | 2019-05-10 11:43:46 -0700 | |
commit | 2a267e7c41aa88215de2b542de797d03d16ecdfd (patch) | |
tree | b949270835e304c8b60a40cde1b2c2e19c13b33a /drivers/gpu/drm/i915/intel_hotplug.c | |
parent | Input: libps2 - mark expected switch fall-through (diff) | |
parent | Linux 5.1 (diff) | |
download | linux-dev-2a267e7c41aa88215de2b542de797d03d16ecdfd.tar.xz linux-dev-2a267e7c41aa88215de2b542de797d03d16ecdfd.zip |
Merge tag 'v5.1' into next
Sync up with mainline to bring in the latest APIs.
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hotplug.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_hotplug.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 9a8018130237..b8937c788f03 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -23,7 +23,6 @@ #include <linux/kernel.h> -#include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -114,51 +113,68 @@ enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv, #define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) /** - * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin + * intel_hpd_irq_storm_detect - gather stats and detect HPD IRQ storm on a pin * @dev_priv: private driver data pointer * @pin: the pin to gather stats on + * @long_hpd: whether the HPD IRQ was long or short * - * Gather stats about HPD irqs from the specified @pin, and detect irq + * Gather stats about HPD IRQs from the specified @pin, and detect IRQ * storms. Only the pin specific stats and state are changed, the caller is * responsible for further action. * - * The number of irqs that are allowed within @HPD_STORM_DETECT_PERIOD is + * The number of IRQs that are allowed within @HPD_STORM_DETECT_PERIOD is * stored in @dev_priv->hotplug.hpd_storm_threshold which defaults to - * @HPD_STORM_DEFAULT_THRESHOLD. If this threshold is exceeded, it's - * considered an irq storm and the irq state is set to @HPD_MARK_DISABLED. + * @HPD_STORM_DEFAULT_THRESHOLD. Long IRQs count as +10 to this threshold, and + * short IRQs count as +1. If this threshold is exceeded, it's considered an + * IRQ storm and the IRQ state is set to @HPD_MARK_DISABLED. + * + * By default, most systems will only count long IRQs towards + * &dev_priv->hotplug.hpd_storm_threshold. However, some older systems also + * suffer from short IRQ storms and must also track these. Because short IRQ + * storms are naturally caused by sideband interactions with DP MST devices, + * short IRQ detection is only enabled for systems without DP MST support. + * Systems which are new enough to support DP MST are far less likely to + * suffer from IRQ storms at all, so this is fine. * * The HPD threshold can be controlled through i915_hpd_storm_ctl in debugfs, * and should only be adjusted for automated hotplug testing. * - * Return true if an irq storm was detected on @pin. + * Return true if an IRQ storm was detected on @pin. */ static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, - enum hpd_pin pin) + enum hpd_pin pin, bool long_hpd) { - unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; + struct i915_hotplug *hpd = &dev_priv->hotplug; + unsigned long start = hpd->stats[pin].last_jiffies; unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); - const int threshold = dev_priv->hotplug.hpd_storm_threshold; + const int increment = long_hpd ? 10 : 1; + const int threshold = hpd->hpd_storm_threshold; bool storm = false; + if (!threshold || + (!long_hpd && !dev_priv->hotplug.hpd_short_storm_enabled)) + return false; + if (!time_in_range(jiffies, start, end)) { - dev_priv->hotplug.stats[pin].last_jiffies = jiffies; - dev_priv->hotplug.stats[pin].count = 0; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); - } else if (dev_priv->hotplug.stats[pin].count > threshold && - threshold) { - dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; + hpd->stats[pin].last_jiffies = jiffies; + hpd->stats[pin].count = 0; + } + + hpd->stats[pin].count += increment; + if (hpd->stats[pin].count > threshold) { + hpd->stats[pin].state = HPD_MARK_DISABLED; DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); storm = true; } else { - dev_priv->hotplug.stats[pin].count++; DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, - dev_priv->hotplug.stats[pin].count); + hpd->stats[pin].count); } return storm; } -static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) +static void +intel_hpd_irq_storm_switch_to_polling(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; struct intel_connector *intel_connector; @@ -210,9 +226,10 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) container_of(work, typeof(*dev_priv), hotplug.reenable_work.work); struct drm_device *dev = &dev_priv->drm; + intel_wakeref_t wakeref; enum hpd_pin pin; - intel_runtime_pm_get(dev_priv); + wakeref = intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->irq_lock); for_each_hpd_pin(pin) { @@ -245,7 +262,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); - intel_runtime_pm_put(dev_priv); + intel_runtime_pm_put(dev_priv, wakeref); } bool intel_encoder_hotplug(struct intel_encoder *encoder, @@ -348,8 +365,8 @@ static void i915_hotplug_work_func(struct work_struct *work) hpd_event_bits = dev_priv->hotplug.event_bits; dev_priv->hotplug.event_bits = 0; - /* Disable hotplug on connectors that hit an irq storm. */ - intel_hpd_irq_storm_disable(dev_priv); + /* Enable polling for connectors which had HPD IRQ storms */ + intel_hpd_irq_storm_switch_to_polling(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); @@ -453,7 +470,7 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, * hotplug bits itself. So only WARN about unexpected * interrupts on saner platforms. */ - WARN_ONCE(!HAS_GMCH_DISPLAY(dev_priv), + WARN_ONCE(!HAS_GMCH(dev_priv), "Received HPD interrupt on pin %d although disabled\n", pin); continue; } @@ -474,15 +491,17 @@ void intel_hpd_irq_handler(struct drm_i915_private *dev_priv, queue_hp = true; } - if (!long_hpd) - continue; - - if (intel_hpd_irq_storm_detect(dev_priv, pin)) { + if (intel_hpd_irq_storm_detect(dev_priv, pin, long_hpd)) { dev_priv->hotplug.event_bits &= ~BIT(pin); storm_detected = true; + queue_hp = true; } } + /* + * Disable any IRQs that storms were detected on. Polling enablement + * happens later in our hotplug work. + */ if (storm_detected && dev_priv->display_irqs_enabled) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock(&dev_priv->irq_lock); |