aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c108
1 files changed, 61 insertions, 47 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ca3ed1833908..654d42fabec8 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -168,69 +168,83 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
168{ 168{
169 struct drm_device *dev = (struct drm_device *) arg; 169 struct drm_device *dev = (struct drm_device *) arg;
170 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 170 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
171 u32 iir; 171 u32 iir, new_iir;
172 u32 pipea_stats = 0, pipeb_stats = 0; 172 u32 pipea_stats, pipeb_stats;
173 int vblank = 0; 173 int vblank = 0;
174 unsigned long irqflags; 174 unsigned long irqflags;
175 175
176 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
177 atomic_inc(&dev_priv->irq_received); 176 atomic_inc(&dev_priv->irq_received);
178 177
179 if (dev->pdev->msi_enabled)
180 I915_WRITE(IMR, ~0);
181 iir = I915_READ(IIR); 178 iir = I915_READ(IIR);
182 179
183 if (iir == 0) { 180 if (iir == 0)
184 if (dev->pdev->msi_enabled) {
185 I915_WRITE(IMR, dev_priv->irq_mask_reg);
186 (void) I915_READ(IMR);
187 }
188 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
189 return IRQ_NONE; 181 return IRQ_NONE;
190 }
191
192 /*
193 * Clear the PIPE(A|B)STAT regs before the IIR
194 */
195 if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
196 pipea_stats = I915_READ(PIPEASTAT);
197 I915_WRITE(PIPEASTAT, pipea_stats);
198 }
199 182
200 if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { 183 do {
201 pipeb_stats = I915_READ(PIPEBSTAT); 184 pipea_stats = 0;
202 I915_WRITE(PIPEBSTAT, pipeb_stats); 185 pipeb_stats = 0;
203 } 186 /*
187 * Clear the PIPE(A|B)STAT regs before the IIR
188 */
189 if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
190 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
191 pipea_stats = I915_READ(PIPEASTAT);
192 I915_WRITE(PIPEASTAT, pipea_stats);
193 spin_unlock_irqrestore(&dev_priv->user_irq_lock,
194 irqflags);
195 }
204 196
205 I915_WRITE(IIR, iir); 197 if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
206 if (dev->pdev->msi_enabled) 198 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
207 I915_WRITE(IMR, dev_priv->irq_mask_reg); 199 pipeb_stats = I915_READ(PIPEBSTAT);
208 (void) I915_READ(IIR); /* Flush posted writes */ 200 I915_WRITE(PIPEBSTAT, pipeb_stats);
201 spin_unlock_irqrestore(&dev_priv->user_irq_lock,
202 irqflags);
203 }
209 204
210 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 205 I915_WRITE(IIR, iir);
206 new_iir = I915_READ(IIR); /* Flush posted writes */
211 207
212 if (dev_priv->sarea_priv) 208 if (dev_priv->sarea_priv)
213 dev_priv->sarea_priv->last_dispatch = 209 dev_priv->sarea_priv->last_dispatch =
214 READ_BREADCRUMB(dev_priv); 210 READ_BREADCRUMB(dev_priv);
215 211
216 if (iir & I915_USER_INTERRUPT) { 212 if (iir & I915_USER_INTERRUPT) {
217 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 213 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
218 DRM_WAKEUP(&dev_priv->irq_queue); 214 DRM_WAKEUP(&dev_priv->irq_queue);
219 } 215 }
220 216
221 if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) { 217 if (pipea_stats & I915_VBLANK_INTERRUPT_STATUS) {
222 vblank++; 218 vblank++;
223 drm_handle_vblank(dev, 0); 219 drm_handle_vblank(dev, 0);
224 } 220 }
225 221
226 if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) { 222 if (pipeb_stats & I915_VBLANK_INTERRUPT_STATUS) {
227 vblank++; 223 vblank++;
228 drm_handle_vblank(dev, 1); 224 drm_handle_vblank(dev, 1);
229 } 225 }
230 226
231 if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || 227 if ((pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) ||
232 (iir & I915_ASLE_INTERRUPT)) 228 (iir & I915_ASLE_INTERRUPT))
233 opregion_asle_intr(dev); 229 opregion_asle_intr(dev);
230
231 /* With MSI, interrupts are only generated when iir
232 * transitions from zero to nonzero. If another bit got
233 * set while we were handling the existing iir bits, then
234 * we would never get another interrupt.
235 *
236 * This is fine on non-MSI as well, as if we hit this path
237 * we avoid exiting the interrupt handler only to generate
238 * another one.
239 *
240 * Note that for MSI this could cause a stray interrupt report
241 * if an interrupt landed in the time between writing IIR and
242 * the posting read. This should be rare enough to never
243 * trigger the 99% of 100,000 interrupts test for disabling
244 * stray interrupts.
245 */
246 iir = new_iir;
247 } while (iir != 0);
234 248
235 return IRQ_HANDLED; 249 return IRQ_HANDLED;
236} 250}