aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2015-02-24 04:14:30 -0500
committerJani Nikula <jani.nikula@intel.com>2015-02-24 08:47:17 -0500
commit2dd2a883aad7c852400027c2261bcab69d9e238e (patch)
tree9d65586f28c069b23a3893f79a500dfd9b0681ff /drivers/gpu
parent6c31a614c43ae274546f736b2a33363e149c3dc2 (diff)
drm/i915: avoid processing spurious/shared interrupts in low-power states
Atm, it's possible that the interrupt handler is called when the device is in D3 or some other low-power state. It can be due to another device that is still in D0 state and shares the interrupt line with i915, or on some platforms there could be spurious interrupts even without sharing the interrupt line. The latter case was reported by Klaus Ethgen using a Lenovo x61p machine (gen 4). He noticed this issue via a system suspend/resume hang and bisected it to the following commit: commit e11aa362308f5de467ce355a2a2471321b15a35c Author: Jesse Barnes <jbarnes@virtuousgeek.org> Date: Wed Jun 18 09:52:55 2014 -0700 drm/i915: use runtime irq suspend/resume in freeze/thaw This is a problem, since in low-power states IIR will always read 0xffffffff resulting in an endless IRQ servicing loop. Fix this by handling interrupts only when the driver explicitly enables them and so it's guaranteed that the interrupt registers return a valid value. Note that this issue existed even before the above commit, since during runtime suspend/resume we never unregistered the handler. v2: - clarify the purpose of smp_mb() vs. synchronize_irq() in the code comment (Chris) v3: - no need for an explicit smp_mb(), we can assume that synchronize_irq() and the mmio read/writes in the install hooks provide for this (Daniel) - remove code comment as the remaining synchronize_irq() is self explanatory (Daniel) v4: - drm_irq_uninstall() implies synchronize_irq(), so no need to call it explicitly (Daniel) Reference: https://lkml.org/lkml/2015/2/11/205 Reported-and-bisected-by: Klaus Ethgen <Klaus@Ethgen.ch> Cc: stable@vger.kernel.org Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 4145d95902f5..ede5bbbd8a08 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1892,6 +1892,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
1892 u32 iir, gt_iir, pm_iir; 1892 u32 iir, gt_iir, pm_iir;
1893 irqreturn_t ret = IRQ_NONE; 1893 irqreturn_t ret = IRQ_NONE;
1894 1894
1895 if (!intel_irqs_enabled(dev_priv))
1896 return IRQ_NONE;
1897
1895 while (true) { 1898 while (true) {
1896 /* Find, clear, then process each source of interrupt */ 1899 /* Find, clear, then process each source of interrupt */
1897 1900
@@ -1936,6 +1939,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
1936 u32 master_ctl, iir; 1939 u32 master_ctl, iir;
1937 irqreturn_t ret = IRQ_NONE; 1940 irqreturn_t ret = IRQ_NONE;
1938 1941
1942 if (!intel_irqs_enabled(dev_priv))
1943 return IRQ_NONE;
1944
1939 for (;;) { 1945 for (;;) {
1940 master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL; 1946 master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
1941 iir = I915_READ(VLV_IIR); 1947 iir = I915_READ(VLV_IIR);
@@ -2208,6 +2214,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
2208 u32 de_iir, gt_iir, de_ier, sde_ier = 0; 2214 u32 de_iir, gt_iir, de_ier, sde_ier = 0;
2209 irqreturn_t ret = IRQ_NONE; 2215 irqreturn_t ret = IRQ_NONE;
2210 2216
2217 if (!intel_irqs_enabled(dev_priv))
2218 return IRQ_NONE;
2219
2211 /* We get interrupts on unclaimed registers, so check for this before we 2220 /* We get interrupts on unclaimed registers, so check for this before we
2212 * do any I915_{READ,WRITE}. */ 2221 * do any I915_{READ,WRITE}. */
2213 intel_uncore_check_errors(dev); 2222 intel_uncore_check_errors(dev);
@@ -2279,6 +2288,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
2279 enum pipe pipe; 2288 enum pipe pipe;
2280 u32 aux_mask = GEN8_AUX_CHANNEL_A; 2289 u32 aux_mask = GEN8_AUX_CHANNEL_A;
2281 2290
2291 if (!intel_irqs_enabled(dev_priv))
2292 return IRQ_NONE;
2293
2282 if (IS_GEN9(dev)) 2294 if (IS_GEN9(dev))
2283 aux_mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C | 2295 aux_mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
2284 GEN9_AUX_CHANNEL_D; 2296 GEN9_AUX_CHANNEL_D;
@@ -3771,6 +3783,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
3771 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 3783 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
3772 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3784 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
3773 3785
3786 if (!intel_irqs_enabled(dev_priv))
3787 return IRQ_NONE;
3788
3774 iir = I915_READ16(IIR); 3789 iir = I915_READ16(IIR);
3775 if (iir == 0) 3790 if (iir == 0)
3776 return IRQ_NONE; 3791 return IRQ_NONE;
@@ -3951,6 +3966,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
3951 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 3966 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
3952 int pipe, ret = IRQ_NONE; 3967 int pipe, ret = IRQ_NONE;
3953 3968
3969 if (!intel_irqs_enabled(dev_priv))
3970 return IRQ_NONE;
3971
3954 iir = I915_READ(IIR); 3972 iir = I915_READ(IIR);
3955 do { 3973 do {
3956 bool irq_received = (iir & ~flip_mask) != 0; 3974 bool irq_received = (iir & ~flip_mask) != 0;
@@ -4171,6 +4189,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
4171 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | 4189 I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
4172 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; 4190 I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
4173 4191
4192 if (!intel_irqs_enabled(dev_priv))
4193 return IRQ_NONE;
4194
4174 iir = I915_READ(IIR); 4195 iir = I915_READ(IIR);
4175 4196
4176 for (;;) { 4197 for (;;) {
@@ -4520,6 +4541,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
4520{ 4541{
4521 dev_priv->dev->driver->irq_uninstall(dev_priv->dev); 4542 dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
4522 dev_priv->pm.irqs_enabled = false; 4543 dev_priv->pm.irqs_enabled = false;
4544 synchronize_irq(dev_priv->dev->irq);
4523} 4545}
4524 4546
4525/** 4547/**