Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1428178 > unrolled thread
| Started by | Lyude <cpaul@redhat.com> |
|---|---|
| First post | 2016-06-21 23:20 +0200 |
| Last post | 2016-06-21 23:30 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v6 0/4] Fixes for HPD Lyude <cpaul@redhat.com> - 2016-06-21 23:20 +0200
[PATCH v6 3/4] drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug() Lyude <cpaul@redhat.com> - 2016-06-21 23:20 +0200
[PATCH v6 2/4] drm/i915/vlv: Reset the ADPA in vlv_display_power_well_init() Lyude <cpaul@redhat.com> - 2016-06-21 23:30 +0200
| From | Lyude <cpaul@redhat.com> |
|---|---|
| Date | 2016-06-21 23:20 +0200 |
| Subject | [PATCH v6 0/4] Fixes for HPD |
| Message-ID | <rMBfr-2Hb-3@gated-at.bofh.it> |
Latest version of: https://lists.freedesktop.org/archives/intel-gfx/2016-June/098787.html The only patch that's changed here is 4/4, the rest are just being sent so that they can be in one thread to make things easier for reviewers Lyude (4): drm/i915/vlv: Make intel_crt_reset() per-encoder drm/i915/vlv: Reset the ADPA in vlv_display_power_well_init() drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug() drm/i915: Enable polling when we don't have hpd drivers/gpu/drm/i915/i915_drv.c | 3 + drivers/gpu/drm/i915/i915_drv.h | 5 ++ drivers/gpu/drm/i915/intel_crt.c | 28 ++++++-- drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_hotplug.c | 117 ++++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_runtime_pm.c | 9 +++ 6 files changed, 148 insertions(+), 18 deletions(-) -- 2.5.5
[toc] | [next] | [standalone]
| From | Lyude <cpaul@redhat.com> |
|---|---|
| Date | 2016-06-21 23:20 +0200 |
| Subject | [PATCH v6 3/4] drm/i915/vlv: Disable HPD in valleyview_crt_detect_hotplug() |
| Message-ID | <rMBfs-2Hb-35@gated-at.bofh.it> |
| In reply to | #1428178 |
One of the things preventing us from using polling is the fact that
calling valleyview_crt_detect_hotplug() when there's a VGA cable
connected results in sending another hotplug. With polling enabled when
HPD is disabled, this results in a scenario like this:
- We enable power wells and reset the ADPA
- output_poll_exec does force probe on VGA, triggering a hpd
- HPD handler waits for poll to unlock dev->mode_config.mutex
- output_poll_exec shuts off the ADPA, unlocks dev->mode_config.mutex
- HPD handler runs, resets ADPA and brings us back to the start
This results in an endless irq storm getting sent from the ADPA
whenever a VGA connector gets detected in the middle of polling.
Somewhat based off of the "drm/i915: Disable CRT HPD around force
trigger" patch Ville Syrjälä sent a while back
Cc: stable@vger.kernel.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Lyude <cpaul@redhat.com>
---
drivers/gpu/drm/i915/i915_drv.h | 2 ++
drivers/gpu/drm/i915/intel_crt.c | 18 ++++++++++++++++++
drivers/gpu/drm/i915/intel_hotplug.c | 27 +++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a988a95..239a3ec 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2933,6 +2933,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv);
void intel_hpd_init_work(struct drm_i915_private *dev_priv);
void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port);
+bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
+void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin);
/* i915_irq.c */
void i915_queue_hangcheck(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 220be7a..a626793 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -327,10 +327,25 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(connector);
struct drm_i915_private *dev_priv = dev->dev_private;
+ bool reenable_hpd;
u32 adpa;
bool ret;
u32 save_adpa;
+ /*
+ * Doing a force trigger causes a hpd interrupt to get sent, which can
+ * get us stuck in a loop if we're polling:
+ * - We enable power wells and reset the ADPA
+ * - output_poll_exec does force probe on VGA, triggering a hpd
+ * - HPD handler waits for poll to unlock dev->mode_config.mutex
+ * - output_poll_exec shuts off the ADPA, unlocks
+ * dev->mode_config.mutex
+ * - HPD handler runs, resets ADPA and brings us back to the start
+ *
+ * Just disable HPD interrupts here to prevent this
+ */
+ reenable_hpd = intel_hpd_disable(dev_priv, crt->base.hpd_pin);
+
save_adpa = adpa = I915_READ(crt->adpa_reg);
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
@@ -353,6 +368,9 @@ static bool valleyview_crt_detect_hotplug(struct drm_connector *connector)
DRM_DEBUG_KMS("valleyview hotplug adpa=0x%x, result %d\n", adpa, ret);
+ if (reenable_hpd)
+ intel_hpd_enable(dev_priv, crt->base.hpd_pin);
+
return ret;
}
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 38eeca7..ec3285f 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -510,3 +510,30 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
cancel_work_sync(&dev_priv->hotplug.hotplug_work);
cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work);
}
+
+bool intel_hpd_disable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
+{
+ bool ret = false;
+
+ if (pin == HPD_NONE)
+ return false;
+
+ spin_lock_irq(&dev_priv->irq_lock);
+ if (dev_priv->hotplug.stats[pin].state == HPD_ENABLED) {
+ dev_priv->hotplug.stats[pin].state = HPD_DISABLED;
+ ret = true;
+ }
+ spin_unlock_irq(&dev_priv->irq_lock);
+
+ return ret;
+}
+
+void intel_hpd_enable(struct drm_i915_private *dev_priv, enum hpd_pin pin)
+{
+ if (pin == HPD_NONE)
+ return;
+
+ spin_lock_irq(&dev_priv->irq_lock);
+ dev_priv->hotplug.stats[pin].state = HPD_ENABLED;
+ spin_unlock_irq(&dev_priv->irq_lock);
+}
--
2.5.5
[toc] | [prev] | [next] | [standalone]
| From | Lyude <cpaul@redhat.com> |
|---|---|
| Date | 2016-06-21 23:30 +0200 |
| Subject | [PATCH v6 2/4] drm/i915/vlv: Reset the ADPA in vlv_display_power_well_init() |
| Message-ID | <rMBp8-2Kp-25@gated-at.bofh.it> |
| In reply to | #1428178 |
While VGA hotplugging worked(ish) before, it looks like that was mainly
because we'd unintentionally enable it in
valleyview_crt_detect_hotplug() when we did a force trigger. This
doesn't work reliably enough because whenever the display powerwell on
vlv gets disabled, the values set in VLV_ADPA get cleared and
consequently VGA hotplugging gets disabled. This causes bugs such as one
we found on an Intel NUC, where doing the following sequence of
hotplugs:
- Disconnect all monitors
- Connect VGA
- Disconnect VGA
- Connect HDMI
Would result in VGA hotplugging becoming disabled, due to the powerwells
getting toggled in the process of connecting HDMI.
Changes since v3:
- Expose intel_crt_reset() through intel_drv.h and call that in
vlv_display_power_well_init() instead of
encoder->base.funcs->reset(&encoder->base);
Changes since v2:
- Use intel_encoder structs instead of drm_encoder structs
Changes since v1:
- Instead of handling the register writes ourself, we just reuse
intel_crt_detect()
- Instead of resetting the ADPA during display IRQ installation, we now
reset them in vlv_display_power_well_init()
Cc: stable@vger.kernel.org
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Lyude <cpaul@redhat.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_crt.c | 2 +-
drivers/gpu/drm/i915/intel_drv.h | 2 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 7 +++++++
3 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index dfcd718..220be7a 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -713,7 +713,7 @@ static int intel_crt_set_property(struct drm_connector *connector,
return 0;
}
-static void intel_crt_reset(struct drm_encoder *encoder)
+void intel_crt_reset(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 496c962..dcbfdde 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1075,7 +1075,7 @@ void gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
/* intel_crt.c */
void intel_crt_init(struct drm_device *dev);
-
+void intel_crt_reset(struct drm_encoder *encoder);
/* intel_ddi.c */
void intel_ddi_clk_select(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index e856d49..f88ef76 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -1065,6 +1065,7 @@ static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv)
static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
{
+ struct intel_encoder *encoder;
enum pipe pipe;
/*
@@ -1100,6 +1101,12 @@ static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
intel_hpd_init(dev_priv);
+ /* Re-enable the ADPA, if we have one */
+ for_each_intel_encoder(dev_priv->dev, encoder) {
+ if (encoder->type == INTEL_OUTPUT_ANALOG)
+ intel_crt_reset(&encoder->base);
+ }
+
i915_redisable_vga_power_on(dev_priv->dev);
}
--
2.5.5
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web