Merge remote-tracking branch 'airlied/drm-next' into drm-intel-next
[pandora-kernel.git] / drivers / gpu / drm / i915 / i915_irq.c
index 9fec711..be2713f 100644 (file)
@@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        return true;
 }
 
+static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+       POSTING_READ(reg);
+}
+
 static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
                                                 enum pipe pipe, bool enable)
 {
@@ -375,16 +387,15 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
  *
  * Returns the previous state of underrun reporting.
  */
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
-                                          enum pipe pipe, bool enable)
+bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                            enum pipe pipe, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long flags;
        bool ret;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       assert_spin_locked(&dev_priv->irq_lock);
 
        ret = !intel_crtc->cpu_fifo_underrun_disabled;
 
@@ -393,7 +404,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev))
+       if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
+               i9xx_clear_fifo_underrun(dev, pipe);
+       else if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
@@ -401,10 +414,33 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
+       return ret;
+}
+
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
        return ret;
 }
 
+static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+                                                 enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       return !intel_crtc->cpu_fifo_underrun_disabled;
+}
+
 /**
  * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
  * @dev: drm device
@@ -458,39 +494,103 @@ done:
 }
 
 
-void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
+static void
+__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                      u32 enable_mask, u32 status_mask)
 {
        u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+       u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if ((pipestat & mask) == mask)
+       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
                return;
 
+       if ((pipestat & enable_mask) == enable_mask)
+               return;
+
+       dev_priv->pipestat_irq_mask[pipe] |= status_mask;
+
        /* Enable the interrupt, clear any pending status */
-       pipestat |= mask | (mask >> 16);
+       pipestat |= enable_mask | status_mask;
        I915_WRITE(reg, pipestat);
        POSTING_READ(reg);
 }
 
-void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
+static void
+__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                       u32 enable_mask, u32 status_mask)
 {
        u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+       u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if ((pipestat & mask) == 0)
+       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+               return;
+
+       if ((pipestat & enable_mask) == 0)
                return;
 
-       pipestat &= ~mask;
+       dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
+
+       pipestat &= ~enable_mask;
        I915_WRITE(reg, pipestat);
        POSTING_READ(reg);
 }
 
+static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
+{
+       u32 enable_mask = status_mask << 16;
+
+       /*
+        * On pipe A we don't support the PSR interrupt yet, on pipe B the
+        * same bit MBZ.
+        */
+       if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV))
+               return 0;
+
+       enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
+                        SPRITE0_FLIP_DONE_INT_EN_VLV |
+                        SPRITE1_FLIP_DONE_INT_EN_VLV);
+       if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
+               enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
+       if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
+               enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
+
+       return enable_mask;
+}
+
+void
+i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                    u32 status_mask)
+{
+       u32 enable_mask;
+
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
+                                                          status_mask);
+       else
+               enable_mask = status_mask << 16;
+       __i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask);
+}
+
+void
+i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                     u32 status_mask)
+{
+       u32 enable_mask;
+
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
+                                                          status_mask);
+       else
+               enable_mask = status_mask << 16;
+       __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
+}
+
 /**
  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
  */
@@ -504,10 +604,10 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, PIPE_A,
-                                    PIPE_LEGACY_BLC_EVENT_ENABLE);
+                                    PIPE_LEGACY_BLC_EVENT_STATUS);
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
@@ -915,6 +1015,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
                drm_kms_helper_hotplug_event(dev);
 }
 
+static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
+{
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+}
+
 static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -966,6 +1071,43 @@ static void notify_ring(struct drm_device *dev,
        i915_queue_hangcheck(dev);
 }
 
+void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
+                            u32 pm_iir, int new_delay)
+{
+       if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
+               if (new_delay >= dev_priv->rps.max_delay) {
+                       /* Mask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = true;
+               }
+               if (dev_priv->rps.rp_down_masked) {
+                       /* UnMask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = false;
+               }
+       } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
+               if (new_delay <= dev_priv->rps.min_delay) {
+                       /* Mask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = true;
+               }
+
+               if (dev_priv->rps.rp_up_masked) {
+                       /* UnMask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = false;
+               }
+       }
+}
+
 static void gen6_pm_rps_work(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
@@ -1023,6 +1165,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
         */
        new_delay = clamp_t(int, new_delay,
                            dev_priv->rps.min_delay, dev_priv->rps.max_delay);
+
+       gen6_set_pm_mask(dev_priv, pm_iir, new_delay);
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
 
        if (IS_VALLEYVIEW(dev_priv->dev))
@@ -1164,8 +1308,8 @@ static void snb_gt_irq_handler(struct drm_device *dev,
        if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
                      GT_BSD_CS_ERROR_INTERRUPT |
                      GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) {
-               DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
-               i915_handle_error(dev, false);
+               i915_handle_error(dev, false, "GT error interrupt 0x%08x",
+                                 gt_iir);
        }
 
        if (gt_iir & GT_PARITY_ERROR(dev))
@@ -1236,6 +1380,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
        if (!hotplug_trigger)
                return;
 
+       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+                         hotplug_trigger);
+
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
@@ -1409,23 +1556,89 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
                        notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
 
                if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
-                       DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
-                       i915_handle_error(dev_priv->dev, false);
+                       i915_handle_error(dev_priv->dev, false,
+                                         "VEBOX CS error interrupt 0x%08x",
+                                         pm_iir);
                }
        }
 }
 
+static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pipe_stats[I915_MAX_PIPES] = { };
+       int pipe;
+
+       spin_lock(&dev_priv->irq_lock);
+       for_each_pipe(pipe) {
+               int reg;
+               u32 mask, iir_bit = 0;
+
+               /*
+                * PIPESTAT bits get signalled even when the interrupt is
+                * disabled with the mask bits, and some of the status bits do
+                * not generate interrupts at all (like the underrun bit). Hence
+                * we need to be careful that we only handle what we want to
+                * handle.
+                */
+               mask = 0;
+               if (__cpu_fifo_underrun_reporting_enabled(dev, pipe))
+                       mask |= PIPE_FIFO_UNDERRUN_STATUS;
+
+               switch (pipe) {
+               case PIPE_A:
+                       iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+                       break;
+               case PIPE_B:
+                       iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+                       break;
+               }
+               if (iir & iir_bit)
+                       mask |= dev_priv->pipestat_irq_mask[pipe];
+
+               if (!mask)
+                       continue;
+
+               reg = PIPESTAT(pipe);
+               mask |= PIPESTAT_INT_ENABLE_MASK;
+               pipe_stats[pipe] = I915_READ(reg) & mask;
+
+               /*
+                * Clear the PIPE*STAT regs before the IIR
+                */
+               if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS |
+                                       PIPESTAT_INT_STATUS_MASK))
+                       I915_WRITE(reg, pipe_stats[pipe]);
+       }
+       spin_unlock(&dev_priv->irq_lock);
+
+       for_each_pipe(pipe) {
+               if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
+                       drm_handle_vblank(dev, pipe);
+
+               if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip(dev, pipe);
+               }
+
+               if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                       i9xx_pipe_crc_irq_handler(dev, pipe);
+
+               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                   intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                       DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+       }
+
+       if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
+               gmbus_irq_handler(dev);
+}
+
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 iir, gt_iir, pm_iir;
        irqreturn_t ret = IRQ_NONE;
-       unsigned long irqflags;
-       int pipe;
-       u32 pipe_stats[I915_MAX_PIPES];
-
-       atomic_inc(&dev_priv->irq_received);
 
        while (true) {
                iir = I915_READ(VLV_IIR);
@@ -1439,44 +1652,13 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                snb_gt_irq_handler(dev, dev_priv, gt_iir);
 
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-               for_each_pipe(pipe) {
-                       int reg = PIPESTAT(pipe);
-                       pipe_stats[pipe] = I915_READ(reg);
-
-                       /*
-                        * Clear the PIPE*STAT regs before the IIR
-                        */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
-                               I915_WRITE(reg, pipe_stats[pipe]);
-                       }
-               }
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
-               for_each_pipe(pipe) {
-                       if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
-                               drm_handle_vblank(dev, pipe);
-
-                       if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
-                               intel_prepare_page_flip(dev, pipe);
-                               intel_finish_page_flip(dev, pipe);
-                       }
-
-                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                               i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
+               valleyview_pipestat_irq_handler(dev, iir);
 
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                        hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
@@ -1486,8 +1668,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
-               if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
-                       gmbus_irq_handler(dev);
 
                if (pm_iir)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
@@ -1546,12 +1726,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        if (pch_iir & SDE_TRANSA_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (pch_iir & SDE_TRANSB_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 }
 
 static void ivb_err_int_handler(struct drm_device *dev)
@@ -1567,8 +1747,8 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
@@ -1593,17 +1773,17 @@ static void cpt_serr_int_handler(struct drm_device *dev)
        if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder C FIFO underrun\n");
 
        I915_WRITE(SERR_INT, serr_int);
 }
@@ -1665,8 +1845,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
 
                if (de_iir & DE_PIPE_CRC_DONE(pipe))
                        i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -1698,7 +1878,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum pipe i;
+       enum pipe pipe;
 
        if (de_iir & DE_ERR_INT_IVB)
                ivb_err_int_handler(dev);
@@ -1709,14 +1889,14 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE_IVB)
                intel_opregion_asle_intr(dev);
 
-       for_each_pipe(i) {
-               if (de_iir & (DE_PIPE_VBLANK_IVB(i)))
-                       drm_handle_vblank(dev, i);
+       for_each_pipe(pipe) {
+               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
+                       drm_handle_vblank(dev, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
-               if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) {
-                       intel_prepare_page_flip(dev, i);
-                       intel_finish_page_flip_plane(dev, i);
+               if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
                }
        }
 
@@ -1738,8 +1918,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        /* We get interrupts on unclaimed registers, so check for this before we
         * do any I915_{READ,WRITE}. */
        intel_uncore_check_errors(dev);
@@ -1808,8 +1986,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        uint32_t tmp = 0;
        enum pipe pipe;
 
-       atomic_inc(&dev_priv->irq_received);
-
        master_ctl = I915_READ(GEN8_MASTER_IRQ);
        master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
        if (!master_ctl)
@@ -1871,8 +2047,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
@@ -2114,11 +2290,18 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-void i915_handle_error(struct drm_device *dev, bool wedged)
+void i915_handle_error(struct drm_device *dev, bool wedged,
+                      const char *fmt, ...)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       va_list args;
+       char error_msg[80];
 
-       i915_capture_error_state(dev);
+       va_start(args, fmt);
+       vscnprintf(error_msg, sizeof(error_msg), fmt, args);
+       va_end(args);
+
+       i915_capture_error_state(dev, wedged, error_msg);
        i915_report_and_clear_eir(dev);
 
        if (wedged) {
@@ -2210,13 +2393,13 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
-                                    PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                                    PIPE_START_VBLANK_INTERRUPT_STATUS);
        else
                i915_enable_pipestat(dev_priv, pipe,
-                                    PIPE_VBLANK_INTERRUPT_ENABLE);
+                                    PIPE_VBLANK_INTERRUPT_STATUS);
 
        /* maintain vblank delivery even in deep C-states */
-       if (dev_priv->info->gen == 3)
+       if (INTEL_INFO(dev)->gen == 3)
                I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -2244,20 +2427,13 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       u32 imr;
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       imr = I915_READ(VLV_IMR);
-       if (pipe == PIPE_A)
-               imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       else
-               imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       I915_WRITE(VLV_IMR, imr);
        i915_enable_pipestat(dev_priv, pipe,
-                            PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                            PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -2288,12 +2464,12 @@ static void i915_disable_vblank(struct drm_device *dev, int pipe)
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       if (dev_priv->info->gen == 3)
+       if (INTEL_INFO(dev)->gen == 3)
                I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS));
 
        i915_disable_pipestat(dev_priv, pipe,
-                             PIPE_VBLANK_INTERRUPT_ENABLE |
-                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                             PIPE_VBLANK_INTERRUPT_STATUS |
+                             PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -2313,17 +2489,10 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
-       u32 imr;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_disable_pipestat(dev_priv, pipe,
-                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
-       imr = I915_READ(VLV_IMR);
-       if (pipe == PIPE_A)
-               imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       else
-               imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       I915_WRITE(VLV_IMR, imr);
+                             PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -2435,9 +2604,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
         */
        tmp = I915_READ_CTL(ring);
        if (tmp & RING_WAIT) {
-               DRM_ERROR("Kicking stuck wait on %s\n",
-                         ring->name);
-               i915_handle_error(dev, false);
+               i915_handle_error(dev, false,
+                                 "Kicking stuck wait on %s",
+                                 ring->name);
                I915_WRITE_CTL(ring, tmp);
                return HANGCHECK_KICK;
        }
@@ -2447,9 +2616,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
                default:
                        return HANGCHECK_HUNG;
                case 1:
-                       DRM_ERROR("Kicking stuck semaphore on %s\n",
-                                 ring->name);
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Kicking stuck semaphore on %s",
+                                         ring->name);
                        I915_WRITE_CTL(ring, tmp);
                        return HANGCHECK_KICK;
                case 0:
@@ -2479,9 +2648,8 @@ static void i915_hangcheck_elapsed(unsigned long data)
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
-#define FIRE 30
 
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        for_each_ring(ring, dev_priv, i) {
@@ -2563,7 +2731,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score > FIRE) {
+               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
                                 stuck[i] ? "stuck" : "no progress",
                                 ring->name);
@@ -2572,7 +2740,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        if (rings_hung)
-               return i915_handle_error(dev, true);
+               return i915_handle_error(dev, true, "Ring hung");
 
        if (busy_count)
                /* Reset timer case chip hangs without another request
@@ -2583,7 +2751,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 void i915_queue_hangcheck(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        mod_timer(&dev_priv->gpu_error.hangcheck_timer,
@@ -2632,8 +2800,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(HWSTAM, 0xeffe);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -2650,8 +2816,6 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        /* VLV magic */
        I915_WRITE(VLV_IMR, 0);
        I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
@@ -2681,8 +2845,6 @@ static void gen8_irq_preinstall(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
        POSTING_READ(GEN8_MASTER_IRQ);
 
@@ -2874,44 +3036,113 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv)
+{
+       u32 pipestat_mask;
+       u32 iir_mask;
+
+       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+                       PIPE_FIFO_UNDERRUN_STATUS;
+
+       I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+       I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+       POSTING_READ(PIPESTAT(PIPE_A));
+
+       pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+                       PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+       i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+                                              PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+       dev_priv->irq_mask &= ~iir_mask;
+
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+       POSTING_READ(VLV_IER);
+}
+
+static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv)
+{
+       u32 pipestat_mask;
+       u32 iir_mask;
+
+       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+
+       dev_priv->irq_mask |= iir_mask;
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       POSTING_READ(VLV_IIR);
+
+       pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+                       PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+       i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+                                               PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+                       PIPE_FIFO_UNDERRUN_STATUS;
+       I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+       I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+       POSTING_READ(PIPESTAT(PIPE_A));
+}
+
+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
+{
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (dev_priv->display_irqs_enabled)
+               return;
+
+       dev_priv->display_irqs_enabled = true;
+
+       if (dev_priv->dev->irq_enabled)
+               valleyview_display_irqs_install(dev_priv);
+}
+
+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
+{
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (!dev_priv->display_irqs_enabled)
+               return;
+
+       dev_priv->display_irqs_enabled = false;
+
+       if (dev_priv->dev->irq_enabled)
+               valleyview_display_irqs_uninstall(dev_priv);
+}
+
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 enable_mask;
-       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV |
-               PIPE_CRC_DONE_ENABLE;
        unsigned long irqflags;
 
-       enable_mask = I915_DISPLAY_PORT_INTERRUPT;
-       enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
-               I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
-               I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
-       /*
-        *Leave vblank interrupts masked initially.  enable/disable will
-        * toggle them based on usage.
-        */
-       dev_priv->irq_mask = (~enable_mask) |
-               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
-               I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+       dev_priv->irq_mask = ~0;
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        POSTING_READ(PORT_HOTPLUG_EN);
 
        I915_WRITE(VLV_IMR, dev_priv->irq_mask);
-       I915_WRITE(VLV_IER, enable_mask);
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
        I915_WRITE(VLV_IIR, 0xffffffff);
-       I915_WRITE(PIPESTAT(0), 0xffff);
-       I915_WRITE(PIPESTAT(1), 0xffff);
        POSTING_READ(VLV_IER);
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable);
+       if (dev_priv->display_irqs_enabled)
+               valleyview_display_irqs_install(dev_priv);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3007,8 +3238,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
 
 #define GEN8_IRQ_FINI_NDX(type, which) do { \
@@ -3044,12 +3273,13 @@ static void gen8_irq_uninstall(struct drm_device *dev)
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
        int pipe;
 
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
@@ -3057,8 +3287,14 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        I915_WRITE(HWSTAM, 0xffffffff);
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-       for_each_pipe(pipe)
-               I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       if (dev_priv->display_irqs_enabled)
+               valleyview_display_irqs_uninstall(dev_priv);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask = 0;
+
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IMR, 0xffffffff);
        I915_WRITE(VLV_IER, 0x0);
@@ -3072,7 +3308,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(HWSTAM, 0xffffffff);
 
@@ -3101,8 +3337,6 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE16(IMR, 0xffff);
@@ -3137,8 +3371,8 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -3187,8 +3421,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ16(IIR);
        if (iir == 0)
                return IRQ_NONE;
@@ -3201,7 +3433,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3210,12 +3444,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -3238,6 +3468,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                iir = new_iir;
@@ -3266,8 +3500,6 @@ static void i915_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3324,8 +3556,8 @@ static int i915_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -3373,8 +3605,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
        int pipe, ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
        do {
                bool irq_received = (iir & ~flip_mask) != 0;
@@ -3387,7 +3617,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3395,9 +3627,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        /* Clear the PIPE*STAT regs before the IIR */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
                                irq_received = true;
                        }
@@ -3413,9 +3642,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
@@ -3442,6 +3668,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -3476,7 +3706,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
@@ -3500,8 +3730,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
@@ -3540,9 +3768,9 @@ static int i965_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        /*
@@ -3610,21 +3838,17 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
        unsigned long irqflags;
-       int irq_received;
        int ret = IRQ_NONE, pipe;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
 
        for (;;) {
+               bool irq_received = (iir & ~flip_mask) != 0;
                bool blc_event = false;
 
-               irq_received = (iir & ~flip_mask) != 0;
-
                /* Can't rely on pipestat interrupt bit in iir as it might
                 * have been cleared after the pipestat interrupt was received.
                 * It doesn't set the bit in iir again, but it still produces
@@ -3632,7 +3856,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3642,11 +3868,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                         * Clear the PIPE*STAT regs before the IIR
                         */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
-                               irq_received = 1;
+                               irq_received = true;
                        }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -3663,9 +3886,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                                                  HOTPLUG_INT_STATUS_G4X :
                                                                  HOTPLUG_INT_STATUS_I915);
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger,
                                              IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
 
@@ -3695,8 +3915,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
 
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+               }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
@@ -3735,7 +3958,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3752,7 +3975,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
-static void i915_reenable_hotplug_timer_func(unsigned long data)
+static void intel_hpd_irq_reenable(unsigned long data)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
        struct drm_device *dev = dev_priv->dev;
@@ -3799,7 +4022,7 @@ void intel_irq_init(struct drm_device *dev)
        setup_timer(&dev_priv->gpu_error.hangcheck_timer,
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
-       setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
+       setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
                    (unsigned long) dev_priv);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);