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>
This commit is contained in:
parent
d5090b9625
commit
4fb066ab9e
|
@ -536,8 +536,9 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&dev_priv->rps_lock, flags);
|
spin_lock_irqsave(&dev_priv->rps_lock, flags);
|
||||||
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
|
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
|
||||||
I915_WRITE(GEN6_PMIMR, pm_iir);
|
|
||||||
dev_priv->pm_iir |= pm_iir;
|
dev_priv->pm_iir |= pm_iir;
|
||||||
|
I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
|
||||||
|
POSTING_READ(GEN6_PMIMR);
|
||||||
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
|
||||||
queue_work(dev_priv->wq, &dev_priv->rps_work);
|
queue_work(dev_priv->wq, &dev_priv->rps_work);
|
||||||
}
|
}
|
||||||
|
@ -649,8 +650,9 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&dev_priv->rps_lock, flags);
|
spin_lock_irqsave(&dev_priv->rps_lock, flags);
|
||||||
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
|
WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
|
||||||
I915_WRITE(GEN6_PMIMR, pm_iir);
|
|
||||||
dev_priv->pm_iir |= pm_iir;
|
dev_priv->pm_iir |= pm_iir;
|
||||||
|
I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
|
||||||
|
POSTING_READ(GEN6_PMIMR);
|
||||||
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
|
spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
|
||||||
queue_work(dev_priv->wq, &dev_priv->rps_work);
|
queue_work(dev_priv->wq, &dev_priv->rps_work);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue