aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2011-09-08 08:00:20 -0400
committerKeith Packard <keithp@keithp.com>2011-10-20 17:11:16 -0400
commit4fb066ab9ef3111c86d9fb8f13f1178885cf7f1c (patch)
tree28e9224114cdaf240c5302d53ea3ca11a98a71a4
parentd5090b96256b9bc479514d54cb55dcaba3144a8d (diff)
drm/i915: close PM interrupt masking races in the irq handler
Quoting Chris Wilson's more concise description: "Ah I think I see the problem. As you point out we only mask the current interrupt received, so that if we have a task pending (and so IMR != 0) we actually unmask the pending interrupt and so could receive it again before the tasklet is finally kicked off by the grumpy scheduler." We need the hw to issue PM interrupts A, B, A while the scheduler is hating us and refuses to run the rps work item. On receiving PM interrupt A we hit the WARN because dev_priv->pm_iir == PM_A | PM_B Also add a posting read as suggested by Chris to ensure proper ordering of the writes to PMIMR and PMIIR. Just in case somebody weakens write ordering. Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 944d712b752b..98eedddc7440 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -536,8 +536,9 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
536 unsigned long flags; 536 unsigned long flags;
537 spin_lock_irqsave(&dev_priv->rps_lock, flags); 537 spin_lock_irqsave(&dev_priv->rps_lock, flags);
538 WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); 538 WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
539 I915_WRITE(GEN6_PMIMR, pm_iir);
540 dev_priv->pm_iir |= pm_iir; 539 dev_priv->pm_iir |= pm_iir;
540 I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
541 POSTING_READ(GEN6_PMIMR);
541 spin_unlock_irqrestore(&dev_priv->rps_lock, flags); 542 spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
542 queue_work(dev_priv->wq, &dev_priv->rps_work); 543 queue_work(dev_priv->wq, &dev_priv->rps_work);
543 } 544 }
@@ -649,8 +650,9 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
649 unsigned long flags; 650 unsigned long flags;
650 spin_lock_irqsave(&dev_priv->rps_lock, flags); 651 spin_lock_irqsave(&dev_priv->rps_lock, flags);
651 WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); 652 WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
652 I915_WRITE(GEN6_PMIMR, pm_iir);
653 dev_priv->pm_iir |= pm_iir; 653 dev_priv->pm_iir |= pm_iir;
654 I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
655 POSTING_READ(GEN6_PMIMR);
654 spin_unlock_irqrestore(&dev_priv->rps_lock, flags); 656 spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
655 queue_work(dev_priv->wq, &dev_priv->rps_work); 657 queue_work(dev_priv->wq, &dev_priv->rps_work);
656 } 658 }